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 Free
Top 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

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
$usehook, 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
createNestedMiddlewarewhich 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
createNestedMiddlewaredoes is call the middleware it’s been passed for every nested relation. It does this by using thedmmfobject 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
nextfunctions to have been passed params, updates the top level params object with those objects and awaits the top levelnextfunction, in this case thenextwhere model is ‘Country’.Once the top level
nextfunction resolves with a result thenextfunctions 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:
includethen that middleware’snextfunction will resolve withundefined.scopeobject to params of nested middleware which is the parent params.createactionsparams.argsdoes not include adatafield, that must be handled manually. You can use the existence ofparams.scopeto 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.