Custom Decorators
Cut boilerplate by composing your own decorators: a FieldID wrapper, createMethodMiddlewareDecorator, and class level middleware decorators for resolvers
Custom decorators allow you to improve your developer experience and reduce code boilerplate.
Here is an extremely simple FieldID decorator:
export function FieldID(options: FieldOptions = {}) {
return Field(() => ID, {
description: 'Resource identifier in the UUID V4 format',
...options,
})
}
@ObjectType()
export class User {
@FieldID()
id: string
@FieldID()
organizationId: string
}Method decorators
We've seen that middlewares allow us to reuse some code between resolvers. To further reduce the boilerplate and improve the API we can create our own custom method decorators.
export function LogExecutionTiming() {
return createMethodMiddlewareDecorator(async (_, next) => {
const start = Date.now()
const result = await next()
const diff = Date.now() - start
this.logger.info(`took ${diff}ms`)
return result
})
}
@Resolver()
class RecipeResolver {
@LogExecutionTiming()
@Query()
createRecipe() {}
}Class decorators
Similar to method decorators, we can create our own custom resolver class decorators
export function ValidateRequestIp(ips: string[]) {
return createResolverClassMiddlewareDecorator(async ({ context }, next) => {
if (!ips.includes(context.request.ip())) {
throw new UnauthorizedIpException()
}
return next()
})
}
@ValidateRequestIp('127.0.0.1')
@Resolver()
class InternalResolver {
@Query()
localhostOnly() {}
}Decorators
A reference table of the @foadonis/graphql decorators, from @ObjectType, @Field and @Resolver to @Arg, @Ctx, @Root, @Directive and @UseMiddleware
Validation
Validate GraphQL inputs and args with class-validator decorators and the validate config option, and note that VineJS is not supported out of the box yet