In the GraphQL world, there is a lot of debate about handling issues like authentication, or side-effects of operations. Should we handle things inside the business logic? Should we use a higher-order function to enhance queries and mutations with authorization logic? Or should we use schema directives? There is no single one-size-fits-all answer to these questions.
Nest helps address these issues with its cross-platform features like guards and interceptors. The philosophy is to reduce redundancy and provide tooling that helps create well-structured, readable, and consistent applications.
You can use standard guards, interceptors, filters and pipes in the same fashion with GraphQL as with any RESTful application. Additionally, you can easily create your own decorators by leveraging the custom decorators feature. Let's take a look at a sample GraphQL query handler.
As you can see, GraphQL works with both guards and pipes in the same way as HTTP REST handlers. Because of this, you can move your authentication logic to a guard; you can even reuse the same guard class across both a REST and GraphQL API interface. Similarly, interceptors work across both types of applications in the same way:
Since GraphQL receives a different type of data in the incoming request, the execution context received by both guards and interceptors is somewhat different with GraphQL vs. REST. GraphQL resolvers have a distinct set of arguments:
info. Thus guards and interceptors must transform the generic
ExecutionContext to a
GqlExecutionContext. This is straightforward:
The GraphQL context object returned by
GqlExecutionContext.create() exposes a get method for each GraphQL resolver argument (e.g.,
getContext(), etc). Once transformed, we can easily pick out any GraphQL argument for the current request.
Nest standard exception filters are compatible with GraphQL applications as well. As with
ExecutionContext, GraphQL apps should transform the
ArgumentsHost object to a
info Hint Both
GqlArgumentsHostare imported from the
Note that unlike the REST case, you don't use the native
response object to generate a response.
As mentioned, the custom decorators feature works as expected with GraphQL resolvers.
@User() custom decorator as follows:
info Hint In the above example, we have assumed that the
userobject is assigned to the context of your GraphQL application.
In the GraphQL context, Nest does not run enhancers (the generic name for interceptors, guards and filters) at the field level see this issue: they only run for the top level
@Mutation() method. You can tell Nest to execute interceptors, guards or filters for methods annotated with
@ResolveField() by setting the
fieldResolverEnhancers option in
GqlModuleOptions. Pass it a list of
'filters' as appropriate:
Warning Enabling enhancers for field resolvers can cause performance issues when you are returning lots of records and your field resolver is executed thousands of times. For this reason, when you enable
fieldResolverEnhancers, we advise you to skip execution of enhancers that are not strictly necessary for your field resolvers. You can do this using the following helper function: