Skip to content

Instantly share code, notes, and snippets.

@KidkArolis
Created June 26, 2020 18:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save KidkArolis/98c5305dfe3c0f259d34cc1061eeb522 to your computer and use it in GitHub Desktop.
Save KidkArolis/98c5305dfe3c0f259d34cc1061eeb522 to your computer and use it in GitHub Desktop.
/*
Install this hook in app.hooks.js
module.exports = app => {
app.hooks({
before: {
all: [
addParamsForward()
]
}
})
}
Then use whenever you want to forward params, e.g. in a hook:
const { app, params } = context
app.service('another-service').find({ query: { id: 'x' }, ...params.forward() })
app.service('another-service').get(id, params.forward())
app.service('another-service').patch(id, {smth: 'x' }, params.forward())
*/
const { has } = require('lodash')
const paramsSeen = new WeakSet()
module.exports = function addParamsForward() {
return context => {
if (paramsSeen.has(context.params)) {
throw new Error(
`Params should never be shared across services, always use params.forward(). Fix calls to ${context.path}#${context.method}`,
)
}
paramsSeen.add(context.params)
context.params.forward = ({ only, omit = [] } = {}) => {
const { params } = context
const forwardedParams = {
caller: {
path: context.path,
method: context.method,
type: context.type,
},
requestId: context.params.requestId,
forwarded: true,
}
;(
only || [
'authenticated',
'user',
'transaction',
'skipEvents',
'permissions',
]
).forEach(param => {
if (has(params, param) && !omit.includes(param)) {
forwardedParams[param] = params[param]
}
})
if (forwardedParams.authenticated) {
forwardedParams.authentication = params.authentication
}
return forwardedParams
}
}
}
@bwgjoseph
Copy link

@KidkArolis,

ah! it works, but still can't figure out why using spread ...params.forward() will trigger the non-callable @@iterator error. Other than that, it looks good now.

If you know what's causing the error, do let me know.

Thanks!

@KidkArolis
Copy link
Author

Because you can only spread properties in an object:

let a = { x: 'y' }
let b = { ...a }

Or you can spread arrays as arguments:

let a = ['x', 'y', 'z']
example(...a)

You can't spread an object as arguments:

// not valid!!
// throws non-callable @@iterator / is not iterable
let a = { x: 'y' }
example(...a)

In Feathers, params is an object, params.forward() is also an object, so:

// invalid
service.get(1, ...params)
service.get(1, ...params.forward())

// valid
service.get(1, params)
service.get(1, params.forward())
service.get(1, { ...params })
service.get(1, { ...params.forward() })

// invalid
service.find(...params)
service.find(...params.forward())

// valid
service.find({ query: { email: 'x', }, ...params })
service.find({ query: { email: 'x', }, ...params.forward() })

@bwgjoseph
Copy link

That's it.

Thank you so much.

@bwgjoseph
Copy link

Hello @KidkArolis,

I noticed that in the forwardedParams.caller.type is always before, is that intended? I would imagine that it should be whoever called the forward()?

// I have a hook x at the after-remove hook of service y
// now I call to remove
app.service('y').remove(id)

// within hook x, it calls service z (note hook x is in after-remove hook of service y)
app.service('z').remove(anotherId, params.forward());

So when I logs out the forwardedParams before the return in addParamsForward(), the caller.type is before.

@KidkArolis
Copy link
Author

@bwgjoseph you're right, it could be fixed by readding addParamsForward() hook in after all, so that it uses updated the closed over context when computing forwardedParams.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment