# Middlewares
Middlewares are very common in backend development, they allow you to avoid repetition, to clarify your code and to better organize it.
The system used by this module is based on koa
middleware.
# Building and using function-based middleware
A middleware is a function that is executed before the main function of a request. For example, it can be used to verify that a user is authenticated.
Here we will create a middleware that checks the value of an argument.
# 1. Declaration
Let's declare the function
import { Context, Next } from "graphql-compose";
async function verifiyArgs(args, context: Context, next: Next) {
}
# 2. Validation
If the condition is met, we will have to tell our middleware that it can go to the next middleware, this is done with the parameter next
which is an asynchronous function to call.
If next
is not called, the next middleware is simply not executed.
If you don't put
await
beforenext()
, the current middleware will not wait until the next middleware has finished executing to execute the rest of its code.
import { Context, Next } from "graphql-compose";
async function verifiyArgs(args, context: Context, next: Next) {
if (args.count > 0) {
await next();
}
throw new Error ("Count must be greater than 0");
}
# 3. Use
Your middleware can be applied with the @Middlewares
decorator at:
- A resolver
- An ObjectType
- An InterfaceType
- A query
- A mutation
- A subscription
# With @Query
or @Mutation
or @Subscription
@Resolver()
class Resolver {
@Query()
@Middlewares(verifyArgs)
query(@Arg("count") count: number) {
// ...
}
@Mutation()
@Middlewares(verifyArgs)
mutation(@Arg("count") count: number) {
// ..
}
@Subscribe({ subscribe: () => pubsub.asyncIterator("NOTIFICATION") })
@Middlewares(verifyArgs)
subscription(@Arg("count") count: number) {
// ..
}
}
# With @Resolver
(or ObjectType
/ InterfaceType
)
This will apply the middleware to all methods of the resolver.
The middlewares applied to @Resolver
will be executed before the middlewares on the methods of the class.
@Resolver()
@Middlewares(verifyArgs)
class Resolver {
@Query()
query(@Arg("count") count: number) {
// ...
}
@Mutation()
mutation(@Arg("count") count: number) {
// ..
}
@Subscribe({ subscribe: () => pubsub.asyncIterator("NOTIFICATION") })
subscription(@Arg("count") count: number) {
// ..
}
}
# Building and using class based middleware
It may be "cleaner" to use a class to declare middleware rather than a function directly. For this you can use the Middleware
class provided by graphql-composer-decorators
.
# 1. Declaration
Let's declare the class
import { Context, Next } from "graphql-compose";
import { Middleware } from "graphql-composer-decorators";
class ArgsVerificator extends Middleware {
async resolve(args, context: Context, next: Next) {
}
}
# 2. Validation
If the condition is met, we will have to tell our middleware that it can go to the next middleware, this is done with the parameter next
which is an asynchronous function to call.
If next
is not called, the next middleware is simply not executed.
If you don't put
await
beforenext()
, the current middleware will not wait until the next middleware has finished executing to execute the rest of its code.
import { Context, Next } from "graphql-compose";
import { Middleware } from "graphql-composer-decorators";
class ArgsVerificator extends Middleware {
async resolve(args, context: Context, next: Next) {
if (args.count > 0) {
await next();
}
throw new Error ("Count must be greater than 0");
}
}
# 3. Use
They can be used in the same way as a middleware based on a function
Your middleware can be applied with the @Middlewares
decorator at:
- A resolver
- An ObjectType
- An InterfaceType
- A query
- A mutation
- A subscription
# With @Query
or @Mutation
or @Subscription
@Resolver()
class Resolver {
@Query()
@Middlewares(ArgsVerificator)
query(@Arg("count") count: number) {
// ...
}
@Mutation()
@Middlewares(ArgsVerificator)
mutation(@Arg("count") count: number) {
// ..
}
@Subscribe({ subscribe: () => pubsub.asyncIterator("NOTIFICATION") })
@Middlewares(ArgsVerificator)
subscription(@Arg("count") count: number) {
// ..
}
}
# With @Resolver
(or ObjectType
/ InterfaceType
)
This will apply the middleware to all methods of the resolver.
The middlewares applied to @Resolver
will be executed before the middlewares on the methods of the class.
@Resolver()
@Middlewares(ArgsVerificator)
class Resolver {
@Query()
query(@Arg("count") count: number) {
// ...
}
@Mutation()
mutation(@Arg("count") count: number) {
// ..
}
@Subscribe({ subscribe: () => pubsub.asyncIterator("NOTIFICATION") })
subscription(@Arg("count") count: number) {
// ..
}
}
← Resolver Description →