Middleware does not work for nested creates
See original GitHub issueBug description
I am trying to write middleware e.g. to lowercase all my eMail and to hash password whereever a user gets created, but unfortunately it only works for direct creations and not for nested creations.
How to reproduce
Steps to reproduce the behavior:
- Go to any prisma example: e.g. https://github.com/prisma/prisma-examples/tree/latest/typescript/graphql-apollo-server
- Change the context.ts to something like this:
prisma.$use(async (params, next) => {
if (params.model == 'User' && params.action == 'create') {
params.args.data.email = params.args.data.email.toLowerCase()
}
return next(params)
})
create some nested create like this:
prisma.post.create({
data: {
author: {
create: {
email: "SoMe@EmaiL.com"
}
}
}
})
- Run the instructions in the repo && prisma studio
- See error –> SoMe@EmaiL.com in the user table
Expected behavior
some@email.com
Prisma information
Environment & setup
- OS: MacOS
- Database: PostgreSQL
- Node.js version: 14.1
- Prisma version:
@prisma/cli : 2.10.1
@prisma/client : 2.10.2
Current platform : darwin
Query Engine : query-engine 7d0087eadc7265e12d4b8d8c3516b02c4c965111 (at node_modules/@prisma/engines/query-engine-darwin)
Migration Engine : migration-engine-cli 7d0087eadc7265e12d4b8d8c3516b02c4c965111 (at node_modules/@prisma/engines/migration-engine-darwin)
Introspection Engine : introspection-core 7d0087eadc7265e12d4b8d8c3516b02c4c965111 (at node_modules/@prisma/engines/introspection-engine-darwin)
Format Binary : prisma-fmt 7d0087eadc7265e12d4b8d8c3516b02c4c965111 (at node_modules/@prisma/engines/prisma-fmt-darwin)
Studio : 0.304.0
Preview Features : connectOrCreate, transactionApi
Issue Analytics
- State:
- Created 3 years ago
- Reactions:27
- Comments:14 (1 by maintainers)
Top Results From Across the Web
Express middleware with nested callback - node.js
In my server controller code i have a method that retrieves an income and an expense object based on a provided id. The...
Read more >Mongoose v6.8.1: SubDocuments
Nested schemas can have middleware, custom validation logic, virtuals, and any other feature top-level schemas can use. The major difference is that ...
Read more >Express.js Middleware Can Be Arbitrarily Nested Within A ...
Ben Nadel demonstrates that middleware can be arbitrarily nested within an Express.js route definition in Node.js. This is because Express ...
Read more >Nested Middleware - make the inside Middleware an exception
But, will it work in such case of Middleware with parameters (I will test it now but ... so it implicitly creates "permission...
Read more >Advanced Features: Middleware - Next.js
Middleware allows you to run code before a request is completed, then based on the incoming request, you can modify the response by...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
CASE
Hi prisma people, we are trying to use prisma middleware feature to implement subscriptions (publishing to the topic on the entity being changed). With some simplification, our code looks this way:
This works perfectly for our case, but what we hit into are nested mutations, e.g.:
In the case of nested mutations, middleware is not being called and we cannot react.
SOLUTION
That would be very helpful if we could specify an argument on the
$use
hook, to only track the operations on the root level, or on the nested entities as well.If you could advise on if we can achieve this at the moment in a different way, or let us know if this is something we can expect from Prisma in the future, we would be grateful, thank you!
Hi there, this was a problem for our team also as our existing code uses Loopback operation hooks (on save, on delete etc). In order to move over to Prisma we needed something that would make the transition easier.
In the end I implemented something in userland that is a version of @Charioteer’s nested middleware suggestion.
The way it works is that you pass a middleware function to
createNestedMiddleware
which returns modified middleware that can be passed toclient.$use
:This calls the middleware passed for the top-level case as well as for nested writes.
Edit: I’ve published the below code as a standalone npm package: prisma-nested-middleware.
Code
Usage / Explanation
What
createNestedMiddleware
does is call the middleware it’s been passed for every nested relation. It does this by using thedmmf
object which contains information about the relations defined inschema.prisma
.So for the following update:
It calls middleware function with params in the following order:
{ model: 'Recipe', action: 'update', args: { where: { id: 'stardust-pie' }, data: {...} } }
{ model: 'Food', action: 'connectOrCreate', args: { create: {...}, connect: {...} } }
{ model: 'Country', action: 'update', args: { where: { id: 'imagination-land', data: {...} } }
Then it waits for all the nested
next
functions to have been passed params, updates the top level params object with those objects and awaits the top levelnext
function, in this case thenext
where model is ‘Country’.Once the top level
next
function resolves with a result thenext
functions of the nested middleware are resolved with the slice of the result relevent to them. So the middleware called for the ‘Recipe’ model receives the recipe object, the middleware for the ‘Food’ receives the food object.Then the return values from the nested middleware are used to modify the top level result that is finally returned from the top level middleware.
There are a couple wrinkles:
include
then that middleware’snext
function will resolve withundefined
.scope
object to params of nested middleware which is the parent params.create
actionsparams.args
does not include adata
field, that must be handled manually. You can use the existence ofparams.scope
to know when to handle a nestedcreate
.I haven’t raised a PR since there is probably a better way to do this internally, however I haven’t checked… if this seems like a good solution to the Prisma team I’ll happily do so 👍
Disclamer: we’ve written tests for our middleware but that doesn’t mean this will work for you! Make sure you write your own tests before shipping anything that uses this.