Middleware
Doesn't work like express middleware
- instead, inspired by koa.js
A middleware function takes 2 args:
- resolver data (ie.
root
,args
,context
,info
) - the
next
function, which is used to control execution of the next middleware in the stack, as well as the resolver to which the middleware is attached.- the way this differs from Express middleware is that this
next
function returns a Promise that resolves to the value returned by the subsequent middleware and resolver in the stack.
- the way this differs from Express middleware is that this
Because of how next
works, it is simple to perform actions before and/or after resolver execution:
export const ResolveTime: MiddlewareFn = async ({ info }, next) => {
// before
const start = Date.now();
await next();
// after
const resolveTime = Date.now() - start;
console.log(`${info.parentType.name}.${info.fieldName} [${resolveTime} ms]`);
};
If we only want to do something before an action, like log the access to the resolver, we can just place the return next() statement at the end of our middleware:
const LogAccess: MiddlewareFn<TContext> = ({ context, info }, next) => {
const username: string = context.username || "guest";
console.log(`Logging access: ${username} -> ${info.parentType.name}.${info.fieldName}`);
return next();
};
Guards
Guarding is a technique to programmatically break the middleware stack (which is done by purposefully not calling next()
)
- in doing this, the result returned from the middleware will be used instead of calling the resolver and returning its result.
- We can also throw an error in the middleware if the execution must be terminated and an error returned to the user, e.g. when resolver arguments are incorrect.
It's called a guard because it prevents execution of the resolver and prevents any data return.