type-graphql
type-graphql copied to clipboard
Scoping middlewares
Right now there are to ways to register a middleware:
-
@UseMiddleware
above the resolver method -
globalMiddlewares
inbuildSchema
In case of @UseMiddleware
decorator, it should be possible to place in on the whole class to avoid manually placing on every method.
In case of global middlewares, it should be possible to register a global middleware that will be run:
- only once (e.g. dataloaders initialization)
- only in resolvers (query/mutation/subscription)
- only on advanced field resolvers (resolver's class method)
- only on simple field resolvers (getters, inline methods and simple fields)
and any combination of this possible options.
I have to investigate if the
@Middleware
decorator for class-based and.scope
static property for function-based solution will be better than a detailed config object inbuildSchema
In case of subscriptions, It should be also possible to choose if the middleware should be run only on subscribing, only on resolving the payload, or both.
This should also affect the @Authorized
decorator which will be overwritten by a resolver's @Authorized
, not concatenated like middlewares.
So, if i want to the log middleware just run once in one query, what should i do?
@Yrobot Use @UseMiddleware
decorator to scope middleware to single query.
If by "one query" you mean one request, you need to use apollo server plugin or something similar.
@Yrobot Use
@UseMiddleware
decorator to scope middleware to single query. If by "one query" you mean one request, you need to use apollo server plugin or something similar.
thanks, i use apollo server plugin in the end.
Hi! Just asking if there is any updates on this feature, right now I am forced to implement @UseMiddleware on each query/mutation since I don't want to trigger middleware multiple times
I came upon something there that is probably worth mentioning. Either it's a bug or the documentation is misleading.
I cannot get a custom middleware to apply to an ObjectType Field when it has a Field Resolver in the ObjectType's Resolver. When attached to the Field Resolver, I get a callback for every returned instance of that resolved field rather than once for the fact that the field was requested. Since this is a OneToMany resolution, I can't just get rid of the field resolver (without a lot of work)
I do think there's utility in having middleware run for every instance of a field when attached to a field resolver, however I think it would be more convenient to have middleware attached to a field run once if the field appears in a request, regardless of the return type
It's worth noting I'm using typeorm and dataloaders with type-graphql and maybe they're breaking something in the decorator stack
Here's a barebones example of how I have it setup right now. Once again, attaching middleware to a Field doesn't appear to work
Entity + ObjectType + Relationship definition
@ObjectType({ description: 'example description' })
@Entity()
export class Example {
@Field(() => [Another], { deprecationReason: 'this is a deprecated field' })
@UseMiddleware(LogDeprecated)
@OneToMany(() => Another, ({example}) => example)
anothers!: Another[]
}
Resolver
@Resolver(Example)
export class ExampleResolver implements ResolverInterface<Example> {
// relations
@FieldResolver(() => [Another])
@UseMiddleware(LogDeprecated)
anothers(
@Root() { id }: Example,
@Ctx() context: Context
) {
// use data loader batch load function to resolve one to many relation
}
}
and a sample of my LogDeprecated middleware
export const LogDeprecated: MiddlewareFn<Context> = async function (
{ info, context },
next
) {
try {
// pull information out of context and info
// track who and when deprecated queries, mutations, fields were requested
catch (err) {
// handle errors
} finally {
return next()
}
}
this example query will result in x
number of logs for each instance of Another associated with Example
query {
example(id: 1 ) {
anothers {
...
}
}
}