Open jellis18 opened 11 months ago
I like this very much. I also come from FastAPI so maybe I'm biased
Digging in a bit more into how django does middleware and while this would work, and I still think it is worthwhile, its not the same "middleware" that Django uses. The Django middleware stack gets applied inside of WSGIHander
or ASGIHandler
and ninja has no access to that as ninja gets requests after the middleware has already run and the view has already been resolved (i.e. it has args and kwargs injected into the view depending on the path).
Maybe this just boils down to a semantic problem and maybe we can call it something other than middleware but really it is middlware just not "django middleware"
@jellis18 @jkgenser
where do you think execution of these middlewares should happen ?
I think 1st is basically covered with standard django middleware
as for 2nd case - basically it's a decorator - so yeah.. maybe router.use(decorator)
can automatically added to all functions
maybe even with some mode
router.use(decorator, mode="before") # will run before input validation
router.use(decorator) # default will run after data is validated
I guess we need first to define some use cases and then come with some solution...
@jellis18 @jkgenser
where do you think execution of these middlewares should happen ?
- before input validation (basically accessing only to request/response objects)
- after input validation (having access to request and all the validated kwargs)
I think 1st is basically covered with standard django middleware
as for 2nd case - basically it's a decorator - so yeah.. maybe
router.use(decorator)
can automatically added to all functionsmaybe even with some mode
router.use(decorator, mode="before") # will run before input validation router.use(decorator) # default will run after data is validated
I guess we need first to define some use cases and then come with some solution...
Overall though I think they can act like decorators on the outside of the @api.method
decorator so the signature is at least somewhat constant (i.e. Callable[Concatenate[HttpRequest, _P], HttpResponse]
)
Some of the main use cases that led me to thinking about this were permissions which would more easily be applied per router instead of API wide or as decorators on every different. Another thing that would be useful is setting context from the request in order to create contextual loggers. But there are lots of use cases where router based or per-route middleware/decorators would be useful.
If there is middleware, I can easily set request.user #990
@jellis18 @jkgenser
where do you think execution of these middlewares should happen ?
- before input validation (basically accessing only to request/response objects)
- after input validation (having access to request and all the validated kwargs)
I think 1st is basically covered with standard django middleware
as for 2nd case - basically it's a decorator - so yeah.. maybe
router.use(decorator)
can automatically added to all functionsmaybe even with some mode
router.use(decorator, mode="before") # will run before input validation router.use(decorator) # default will run after data is validated
I guess we need first to define some use cases and then come with some solution...
I just want to add that option 1 isn't fully covered by django middleware as that will also apply to requests for accessing the docs. Ofcourse it's possible to work around it.
Hello, I'd like to ask for your opinion.
I need to do a header check (if the version is correct), but it needs to be before the input schema starts validating.
This would be fairly easy using Django-middleware however, I only need to do this on certain endpoints.
The problem I'm having is that as soon as I use the decorator, a validation error (422) is thrown before my custom check, which I don't want.
Example decorator:
router = Router()
...
@router.get(...)
@my_header_checker
def some_endpoint_handler(request: HttpRequest, data: SomeSchema)
...
I want to ask if there is any way to run some checks before input validation.
Thank you for your time and reply.
Is your feature request related to a problem? Please describe.
I know that
django-ninja
is based off of django, obviously, but I'm really not a fan of the way django handles middleware where it applies globally and is somewhat hard to configure since you have to pass in the path to a callable as a string instead of being able to define it in code.To me it is always a pain (not just ninja, but django in general) when I want certain middleware per route or even per specific endpoint. I know we can do it with decorators or by subclassing router and using
view_decorator
now but all of those seem a bit tedious.It seems that django-ninja is missing a key middleware feature like in FastAPI
add_middleware
and express withuse
or something like go Chiuse
as well. In all of those systems you can add middleware directly from the router without needing to use a decorator or equivalent.Describe the solution you'd like I've already started prototyping this and its somewhat based on how go Chi does it. Basically what I am proposing is that middleware be defined like
This would add global middleware. To add router based middleware would look like
In this case the middleware from
api
would be inherited and the router would then have its own that comes after theapi
middlewareWe could go further and even have endpoint level middleware that could look like
In this case the middleware stack would include any from the global api, the router, and then this specific endpoint based middleware.
In all cases the middleware would have a signature that obeys
Which all standard django decorators would already obey.
Again, I know there are ways to accomplish the same goal already but this could be really useful and would allow users to more easily add their own middlware without having to subclass router or add decorators everywhere.
What are your thoughts on this?. I'd be happy to work on this as I've already started but just want to see what the community thinks.