The second argument of the use method will execute the rest of the stack allowing you to run actions after the execution of your operations. For example you could log the execution time.
Middleware also has the ability to intercept the result of a resolver's execution. It's not only able to e.g. create a log but also replace the result with a new value:
app/graphql/middlewares/competitor_middleware.ts
import { ResolverData, NextFn } from '@foadonis/graphql'import { inject } from '@adonisjs/core'export default class CompetitorMiddleware { async use({ info }: ResolverData, next: NextFn) { const result = await next() if (result === 'ts.ed') { return 'adonis' } return result }}
Guards are simply middlewares that does not call the next function so it never reaches the resolver. This is useful when you want to block access on specific conditions.
app/graphql/middlewares/competitor_middleware.ts
import { ResolverData, NextFn } from '@foadonis/graphql'import { inject } from '@adonisjs/core'export default class CompetitorMiddleware { use({ args }, next) { if (args.frameworkName === 'ts.ed') { throw new Error('Adonis is better') } if (args.frameworkName === 'adonis') { return 'AdonisJS' } return next() }}
To attach middleware to a resolver method, use the @UseMiddleware decorator above the method declaration. It accepts an array of middleware that will be called in the provided order. You can also pass them without an array as it supports rest parameters:
app/graphql/resolvers/recipe_resolver.ts
import { Resolver, UseMiddleware, Query } from '@foadonis/graphql'import PerformanceLoggerMiddleware from '#graphql/middlewares/performance_logger_middleware'import AccessLoggerMiddleware from '#graphql/middlewares/access_logger_middleware'@Resolver()export default class RecipeResolver { @UseMiddleware(PerformanceLoggerMiddleware, AccessLoggerMiddleware) @Query() recipe() {}}