typegraphql-prisma
typegraphql-prisma copied to clipboard
add support for overriding _all decorators on CRUD resolvers
Is your feature request related to a problem? Please describe.
When applying decorators on all the methods of a model CRUD resolver, there is no way to remove or override those decorators on specific resolvers e.g:
applyResolversEnhanceMap({
Story: {
_all: [Authorized(Role.ADMIN, Role.DEVELOPER)],
stories: [Authorized()],
story: [Authorized()]
},
})
the _all decorators are applied to all Story resolvers, if you want to solve this you have to remove the _all field and write all the CRUD resolvers that you want to apply decorators to.
Describe the solution you'd like
An option could be introduced to accept both an array of decorators and a function for all CRUD resolvers except for the _all field,
this function can be passed in with the decorators passed in the _all field, and it can return more decorators or none at all:
applyResolversEnhanceMap({
Story: {
_all: [Authorized(Role.ADMIN, Role.DEVELOPER)],
stories:(decorators) => [Authorized()],
story: (decorators) => [],
createStory: (decorators) => [...decorators, RateLimit({ window: "15min", max: 10 })]
},
})
there is also the option to just pass in an array of decorators like the current implementation and it will just add the decorators passed in the _all field e.g:
applyResolversEnhanceMap({
Story: {
_all: [Authorized(Role.ADMIN, Role.DEVELOPER)],
stories:(decorators) => [Authorized()],
createStory: [RateLimit({ window: "15min", max: 10 })],
},
})
This would be a very helpful feature - what needs to happen for it to be implemented?
Agreed, would be quite helpful since I close all on default but require finer checks for certain actions:
applyResolverEnhanceMap({
Story: {
_all: [Authorized()],
createStory: [Authorized(Role.ADMIN]
},
})
@Gr3yShad0w Even raw TypeGraphQL does not support a resolver-level decorators like @Authorized().
I think that it would be much simpler if you define a decorator on resolver and then on the field, so the middleware can read extensions and use default value or per action value.
That would solve the issue with overriding default decorator value as _all is just a shorthand, workaround that was not supposed to handle such cases.
I believe the issue here is to be able to define a default decorator for all query/mutation in a resolver class via _all as well as override the said default decorator (or add more) for specific queries/mutations.
This is so that we can prevent having to mention all the generated queries/mutations within the map, when we only want to override one (or a few) queries/mutations.
For example:
Projectmodel defines project entities that only anADMINorMANAGERshould be able to create or delete, and…- All users should be able to query projects as well as fetch and mutate relations for any project.
In this case, the applyResolverEnhanceMap call tends to become like this:
applyResolverEnhanceMap({
Project: {
// All authenticated users can perform these queries/mutation
aggregateProject: [Authorized()],
project: [Authorized()],
projects: [Authorized()],
findFirstProject: [Authorized()],
groupByProject: [Authorized()],
updateProject: [Authorized()],
// Mutations reserved for Admins or Managers
updateManyProject: [Authorized(Role.ADMIN, Role.MANAGER)],
createProject: [Authorized(Role.ADMIN, Role.MANAGER)],
createManyProject: [Authorized(Role.ADMIN, Role.MANAGER)],
deleteProject: [Authorized(Role.ADMIN, Role.MANAGER)],
deleteManyProject: [Authorized(Role.ADMIN, Role.MANAGER)],
upsertProject: [Authorized(Role.ADMIN, Role.MANAGER)],
},
})
The solution proposed by the OP above could reduce this to the following:
applyResolverEnhanceMap({
Project: {
// All authenticated users can perform these queries/mutation
_all: [Authorized()],
// These can be removed
// aggregateProject: [Authorized()],
// project: [Authorized()],
// projects: [Authorized()],
// findFirstProject: [Authorized()],
// groupByProject: [Authorized()],
// updateProject: [Authorized()],
// Mutations reserved for Admins or Managers
updateManyProject: [Authorized(Role.ADMIN, Role.MANAGER)],
createProject: [Authorized(Role.ADMIN, Role.MANAGER)],
createManyProject: [Authorized(Role.ADMIN, Role.MANAGER)],
deleteProject: [Authorized(Role.ADMIN, Role.MANAGER)],
deleteManyProject: [Authorized(Role.ADMIN, Role.MANAGER)],
upsertProject: [Authorized(Role.ADMIN, Role.MANAGER)],
},
})
As @MichalLytek said, the resolver class itself does not (nor should it, for simplicity's sake) support decorators like @Authorized(). We're only focused on overriding the _all decorator for individual queries/mutations within the resolver class.
If I might add a suggestion as well:
I am currently working on a project, using TypeGraphQL-Prisma, where I often encounter the case of 'any authenticated user can Read objects, but only admins can Create, Update, or Delete'.
as such my enhance maps look like this:
const resolversEnhanceMap: ResolversEnhanceMap = {
Event: {
event: [Authorized()],
events: [Authorized()],
findFirstEvent: [Authorized()],
aggregateEvent: [Authorized()],
createEvent: [Authorized<Role>(Role.ADMIN)],
createManyEvent: [Authorized<Role>(Role.ADMIN)],
upsertEvent: [Authorized<Role>(Role.ADMIN)],
updateEvent: [Authorized<Role>(Role.ADMIN)],
updateManyEvent: [Authorized<Role>(Role.ADMIN)],
deleteEvent: [Authorized<Role>(Role.ADMIN)],
deleteManyEvent: [Authorized<Role>(Role.ADMIN)],
},
};
Might it be benificial to implement, in addition to the _all shorthand, shorthands like _create, _update, _read, and _delete?
It seems like this could already greatly reduce the amount of code needed to specify separate config for queries and mutations that belong together.
something like
const resolversEnhanceMap: ResolversEnhanceMap = {
Event: {
_create: [Authorized<Role>(Role.ADMIN)]
_read: [Authorized()],
_update: [Authorized<Role>(Role.ADMIN)]
_delete: [Authorized<Role>(Role.ADMIN)]
},
};
or even
const resolversEnhanceMap: ResolversEnhanceMap = {
Event: {
_mutate: [Authorized<Role>(Role.ADMIN)]
_query: [Authorized()],
},
};
This could still work in conjunction with the proposed overrides, if needed.
@MitchJans nice idea, tracked by #300 💪
@MitchJans exactly! I copy over the map and reduce it to the enhancemap, as I'm to lazy to update it in the future.
@MichalLytek appreciate it, that you track it!
Resolved by fdb4bba, extended to support also relation resolvers, models, outputs and inputs. Published in https://github.com/MichalLytek/typegraphql-prisma/releases/tag/v0.24.0 🚀