Utilities
callingParams
Build params for a service call.
Arguments
{Object} options
| Argument | Type | Default | Description |
|---|---|---|---|
options | Object | How to construct params for service call. |
options | Argument | Type | Default | Description |
|---|---|---|---|---|
query | Object | The params.query for the calling params. | ||
propNames | Array< String > | [] | The names of the props in context.params to include in the new params. | |
newProps | Object | {} | Additional props to add to the new params. | |
hooksToDisable | Array< String > | [] | The names of hooks to disable during the service call. populate, fastJoin, softDelete and stashBefore are supported. | |
ignoreDefaults | Boolean | Ignore the defaults propNames and newProps. |
Returns
{Function}Arguments
{Object} context
| Argument | Type | Default | Description |
|---|---|---|---|
context | Object | The context of the hook which will make the service call. |
Returns
{Object} newParams
| Name | Type | Description |
|---|---|---|
newParams | Object | The params for the service call. |
Example
jsconst { callingParams, callingParamsDefaults } = require('feathers-hooks-common'); // Authentication props to always copy. Suitable for feathers-authentication-management. callingParamsDefaults(['provider', 'authenticated', 'user', 'isVerified']); async function myCustomHook(context) { // ... const result = await service.find(callingParams({ query: { { id: { $in: [1, 2, 3] } } }, propNames: ['customProp'], newProps: { mongoose: ... }, hooksToDisable: 'populate' }))(context); // ... }Details
When calling another service within a hook, consideration must be given to what the
paramsshould be for the called service. For example, should the called service see that a client is making the call, or the server? What authentication and authorization information should be provided? You can use this convenience function to help create thatparams.The properties
provider,authenticatedanduserare the standard authentication properties used by Feathers. They are copied automatically.These defaults and others can be changed app-wide by calling the
callingParamsDefaultsutility.
callingParamsDefaults
Set defaults for building params for service calls with callingParams.
Arguments
{Array< String >} propNames{Object} newProps
| Argument | Type | Default | Description |
|---|---|---|---|
propNames | Array< String > | The names of the props in context.params to automatically include in the new params. | |
newProps | Object | Additional props to add to the new params. |
Example
jsconst { callingParams, callingParamsDefaults } = require('feathers-hooks-common'); // Authentication props to always copy. Suitable for feathers-authentication-management. // Only hooks will be calling `callingParams`. Set a flag so other hooks recognize such a call. callingParamsDefaults(['provider', 'authenticated', 'user', 'isVerified'], { _calledByHook: true }); async function myCustomHook(context) { // ... const result = await service.find(callingParams({ query: { { id: { $in: [1, 2, 3] } } }, propNames: ['customProp'], newProps: { mongoose: ... }, hooksToDisable: 'populate' }), context); // ... }Details
When calling another service within a hook, consideration must be given to what the
paramsshould be for the called service. For example, should the called service see that a client is making the call, or the server? What authentication and authorization information should be provided? You can use this convenience function to help create thatparams.The properties
provider,authenticatedanduserare the standard authentication properties used by Feathers. They are copied automatically.These defaults and others can be changed app-wide by calling the
callingParamsDefaultsutility.
checkContext
Restrict a hook to run for certain methods and method types.
- Arguments
{Object} context{String | Array< String >} [ type ]{String | Array< String >} [ methods ]{String} [ label ]
| Argument | Type | Default | Description | |
|---|---|---|---|---|
context | Object | The hook context. | ||
type | `String | Array< String >` | all types | The service type allowed - before, after, error. |
methods | `String | Array< String >` | all methods | The service methods allowed - find, get, update, patch, remove. |
label | String | 'anonymous' | Name of hook to use with throw. |
Example
jsconst { checkContext } = require('feathers-hooks-common'); function myHook(context) { checkContext(context, 'after', ['create', 'remove']); ... } module.exports = { before: { create: [ myHook ] // throws } }; // checkContext(hook, 'before', ['update', 'patch'], 'hookName'); // checkContext(hook, null, ['update', 'patch']); // checkContext(hook, 'before', null, 'hookName'); // checkContext(hook, 'before');Details
Its important to ensure the hook is being used as intended.
checkContextlet's you restrict the hook to a hook type and a set of service methods.
combine
Sequentially execute multiple sync or async hooks.
| before | after | methods | multi | details |
|---|---|---|---|---|
| yes | yes | all | n/a | source |
- Arguments
{Array< Function >} hookFuncs
| Argument | Type | Default | Description |
|---|---|---|---|
hookFuncs | Array<Function > | Hooks, used the same way as when you register them. |
Example
jsconst { combine, createdAt, updatedAt } = require('feathers-hooks-common'); async function myCustomHook(context) { const newContext = await combine(setNow('createdAt'), setNow('updatedAt')).call(this, context); return newContext; }Details
combinehas the signature of a hook, but is primarily intended to be used within your custom hooks, not when registering hooks.
The following is a better technique to use when registering hooks.
const workflow = [createdAt(), updatedAt(), ...];
module.exports = { before: {
update: [...workflow],
patch: [...workflow],
} };every
Return the and of a series of sync or async predicate functions.
| before | after | methods | multi | details |
|---|---|---|---|---|
| yes | yes | all | yes | source |
- Arguments
{Array< Function >} predicates
| Argument | Type | Default | Description |
|---|---|---|---|
predicates | Array< Function > | Functions which take the current hook as a param and return a boolean result. |
Returns
{Boolean} result
| Name | Type | Description |
|---|---|---|
| result | Boolean | The logical and of predicates |
Example
jsconst { iff, every } = require('feathers-hooks-common'); module.exports = { before: { create: iff(every(hook1, hook2, ...), hookA, hookB, ...) } };Details
everyis a predicate function for use in conditional hooks. The predicate functions are run in parallel, andtrueis returned if every predicate returns a truthy value.
getItems
Get the records in context.data or context.result
- Arguments
{Object} context
| Argument | Type | Default | Description |
|---|---|---|---|
context | Object | The hook context. |
Returns
{Array< Object > | Object | undefined} records
| Name | Type | Description | | ------- | --------------- | ----------- | --------- | ------------ | | records | Array< Object > | Object | undefined | The records. |
Example
jsconst { getItems, replaceItems } = require('feathers-hooks-common'); const insertCode = code => context => { const items = getItems(context); if (Array.isArray(items)) { items.forEach(item => { item.code = code; }); } else { items.code = code; } replaceItems(context, items); }; module.exports = { before: { create: insertCode('a') } };Details
getItemsgets the records from the hook context:context.data(before hook) orcontext.result[.data](after hook).
isNot
Negate a sync or async predicate function.
| before | after | methods | multi | details |
|---|---|---|---|---|
| yes | yes | all | yes | source |
Arguments
{Function | Boolean} predicate
| Argument | Type | Default | Description |
|---|---|---|---|
predicate | Function Boolean | A sync or async function which take the current hook as a param and returns a boolean result. |
Returns
{Boolean} result
| Name | Type | Description |
|---|---|---|
| result | Boolean | The not of predicate |
Example
jsconst { iff, isNot, isProvider, discard } = require('feathers-hooks-common'); const isRequestor = () => context => new Promise(resolve, reject) => ... ); module.exports = { after: { create: iff(isNot(isRequestor()), discard('password')) } };Details
isNotis a predicate function for use in conditional hooks.
isProvider
Check which transport provided the service call.
| before | after | methods | multi | details |
|---|---|---|---|---|
| yes | yes | all | yes | source |
- Arguments
{Array< String >} transports
| Name | Type | Default | Description |
|---|---|---|---|
transports | Array< String > | The transports you want to allow. |
transports | Value | Description |
|---|---|---|
socketio | Allow calls by Socket.IO transport. | |
rest | Allow calls by REST transport. | |
external | Allow calls other than from server. | |
server | Allow calls from server. |
Returns
{Boolean} result
| Name | Type | Description |
|---|---|---|
| result | Boolean | If the call was made by one of the transports. |
Example
jsconst { iff, isProvider, discard } = require('feathers-hooks-common'); module.exports = { after: { create: iff(isProvider('external'), discard('password')) } };Details
isProvideris a predicate function for use in conditional hooks. Its determines which transport provided the service call by checkingcontext.params.provider.
makeCallingParams
Build context.params for service calls.
Tip: You should prefer using the
callingParamsutility tomakeCallingParams.
Arguments
{Object} context{Object} [ query ]{Array< String > | String} [ include ]{Object} [ inject ]
| Argument | Type | Default | Description |
|---|---|---|---|
context | Object | The existing hook context. | |
query | Object | The context.params.query for the new context. | |
include | Array< String > | The names of the props in context to include in the new context. | |
inject | Object | Additional props to add to the new context. |
Returns
{Object} newContext
| Variable | Type | Default | Description |
|---|---|---|---|
newContext | Object | The new context created. |
Example
jsconst { makeCallingParams } = require('feathers-hooks-common'); async function myCustomHook(context) { // ... const result = await service.find(makeCallingParams( context, { id: { $in: [1, 2, 3] } }, 'user', { _populate: false, mongoose: ... } )); // ... }Details
When calling another service within a hook, consideration must be given to what the
context.paramsshould be for the called service. For example, should the called service see that a client is making the call, or the server? What authentication and authorization information should be provided? You can use this convenience function to help create thatcontext.params.The value
context.params._populate: 'skip'is automatically added to skip anyfastJoinorpopulatehooks registered on the called service. Set it tofalse, like in the example above, to make those hooks run.
paramsForServer
Pass an explicit context.params from client to server. Client-side.
- Arguments
{Object} params{Array< String >} [ whitelist ]
| Argument | Type | Default | Description |
|---|---|---|---|
params | Object | The context.params to use for the service call, including any query object. | |
whitelist | dot notation | all props in context.params | Names of the props in context.params to transfer to the server. This is a security feature. All props are transferred if no whitelist is provided. |
Example
js// client const { paramsForServer } = require('feathers-hooks-common'); service.update( id, data, paramsForServer({ query: { dept: 'a' }, populate: 'po-1', serialize: 'po-mgr' }) ); // server const { paramsFromClient } = require('feathers-hooks-common'); module.exports = { before: { all: [paramsFromClient('populate', 'serialize', 'otherProp'), myHook] } }; // myHook's `context.params` will now be // { query: { dept: 'a' }, populate: 'po-1', serialize: 'po-mgr' } }Details
By default, only the
context.params.queryobject is transferred from a Feathers client to the server, for security among other reasons. However you can explicitly transfer othercontext.paramsprops with the client utility functionparamsForServerin conjunction with theparamsFromClienthook on the server.This technique also works for service calls made on the server.
The data is transfered using `context.params.query.$client`. If that field already exists, it must be an Object.
replaceItems
Replace the records in context.data or context.result[.data].
Arguments
{Object} context{Array< Object > | Object} records
| Argument | Type | Default | Description |
|---|---|---|---|
context | Object | The hook context. | |
records | Array< Object > Object | The new records. |
Example
jsconst { getItems, replaceItems } = require('feathers-hooks-common'); const insertCode = code => context { const items = getItems(context); if (Array.isArray(items)) { items.forEach(item => { item.code = code; }); } else { items.code = code; } replaceItems(context, items); }; module.exports = { before: { create: insertCode('a') } };Details
replaceItemsreplaces the records in the hook context:context.data(before hook) orcontext.result[.data](after hook).
runHook
Let's you call a hook right after the service call.
- Arguments
{Object} [ hookContext ]{Function} hookFunc
| Argument | Type | Default | Description |
|---|---|---|---|
hookContext | Object | {} | The context for hookFunc. |
hookFunc | Function | The hook to run. |
Example
jsconst { keep, runHook } = require('feathers-hooks-common'); user.get(...) .then( runHook()(keep('name', 'address.state')) ) .then(data => ...); // [{ name: 'Marshall', address: { state: 'UT' }}] const data = await user.get(...); const result = await runHook()(data)(keep('name', 'address.state'));jsconst { fastJoin, runHook } = require('feathers-hooks-common'); const runHookFinds = runHook({ app: app, method: 'find' }); const paymentsRecords = [ { _id: 101, amount: 100, patientId: 1 }, { _id: 102, amount: 105, patientId: 1 }, { _id: 103, amount: 110, patientId: 1 }, { _id: 104, amount: 115, patientId: 2 }, { _id: 105, amount: 120, patientId: 3 }, { _id: 106, amount: 125, patientId: 3 } ]; await payments.create(paymentsRecords); const patientsRecords = [ { _id: 1, name: 'John' }, { _id: 2, name: 'Marshall' }, { _id: 3, name: 'David' } ]; await patients.create(patientsRecords); const paymentResolvers = { joins: { patient: () => async payment => { payment.patient = ( await patients.find({ query: { id: payment.patientId } }) )[0]; } } }; await payments .find() .then(runHookFinds(fastJoin(paymentResolvers))) .then(data => console.log(data)); // log [ { _id: 101, amount: 100, patientId: 1, patient: { _id: 1, name: 'John' } }, { _id: 102, amount: 105, patientId: 1, patient: { _id: 1, name: 'John' } }, { _id: 103, amount: 110, patientId: 1, patient: { _id: 1, name: 'John' } }, { _id: 104, amount: 115, patientId: 2, patient: { _id: 2, name: 'Marshall' } }, { _id: 105, amount: 120, patientId: 3, patient: { _id: 3, name: 'David' } }, { _id: 106, amount: 125, patientId: 3, patient: { _id: 3, name: 'David' } } ];Details
Hooks are normally registered for a service, e.g. in
project/src/services/posts/posts.hooks.js. This is nice and simple when, for example, all thefindhooks have to run for everyfindcall.The conditional hooks can be used when hooks have to be conditionally run based on the current environment. For example, we can discard the
passwordfield when the call is made by a client.However things are not always so straightforward. There can be that one call for which we want to join specific records. We could add a conditional hook that runs just for that one call, however we may soon find ourselves with a second and a third special case.
runHookis designed for such cases. Instead of having to register a conditioned hook, it allows us to run the hook in a.then()right after the service call.
some
Return the or of a series of sync or async predicate functions.
| before | after | methods | multi | details |
|---|---|---|---|---|
| yes | yes | all | yes | source |
Arguments
{Array< Function >} predicates
| Argument | Type | Default | Description |
|---|---|---|---|
predicates | Array< Function > | Functions which take the current hook as a param and return a boolean result. |
Returns
{Boolean} result
| Name | Type | Description |
|---|---|---|
| result | Boolean | The logical or of predicates |
Example
jsconst { iff, some } = require('feathers-hooks-common'); module.exports = { before: { create: iff(some(hook1, hook2, ...), hookA, hookB, ...) } };Details
someis a predicate function for use in conditional hooks. The predicate functions are run in parallel, andtrueis returned if any predicate returns a truthy value.
