Odoo v16 changes in odoo.http
Hello there,
I'm an Odoo employee and I've been working for the past months on a comprehensive refactor of the http framework. I fear that it is going to break your customizations a lot. I'm sorry I only hear about your modules now but we still have a couple of (but not many) weeks before my branch gets merged.
httpocalypse PR https://github.com/odoo/odoo/pull/78857
To give a few insights, once httpocalypse is merged we plan to introduce a new type="jsondata" to differentiate raw json data from JSON-RPC and to rely more on the route-type instead of the content-type to dispatch the request. Actually we plan to almost entirely drop checking the content-type, maybe we'll stiff have some guard, e.g. emitting a warning when the content-type is x-www-form-urlencoded and the route-type is json/jsondata.
If you absolutely need I restore some monkey-patchable hooks and fear that the upcoming type="jsondata" will not be enough, I urge you to suggest changes on the httpocalypse PR.
Regards,
@Julien00859 Thank you for the ping. I'll check your change to see if we can still easily plug a custom way of processing http requests. base_rest not only allows to process raw json data requests but also any other kind of requests (MultiPart form data, binary data, ...)
@Julien00859 Thank to take a look on the OCA modules ! That's not so common in odoo teams :-). Your message is in a good opensource spirit. Regards.
We have been suggested to add @route(type="custom") where the body will not be parsed by the framework in order to let the controller deal with the request the way it wants. Discussions about it over there: https://github.com/odoo/odoo/issues/82103
Hello there, our branch has been merged. Thanks to the contribution of @lmignon we made the necessary changes to ensure you guys still have a way to enrich @route(type=...), here is how you can do it.
There is a new Dispatcher abstract class in odoo/http.py that you can inherit from to define your own "dispatchers" (=class responsible for route-type specific code). There are a few mandatory attributes/methods you must implement (routing_type, is_compatible_with, dispatch and handle_error).
routing_type: str
A mandatory class attribute, this is the name of your dispatcher, the name to use as the type argument of @route.
is_compatible_with(cls, request) -> bool
You implement this method to ensure the current request object is compatible with the matched route. e.g. here is the code that ensure a request is compatible with a @route(type='json') endpoint:
return request.httprequest.mimetype in ('application/json', 'application/json-rpc')
If you want to accept all requests in your controller endpoint, just return True.
pre_dispatch(self, rule, args) -> None
You override this method when you need to prepare the system to handle the incoming request. Often used to save special query-string arguments into the context or the session. Also used to (in case of @route(type='http', method=['POST'])) verify the csrf_token. rule contains the werkzeug's match rule, itself contains the endpoint, itself contains the @route information (routing). args contains the values for the placeholders of the URL.
dispatch(self, endpoint) -> werkzeug.wrappers.Response
You implement this method to parse the request's body and to populate request.params before calling the endpoint. Because we are noobs and weren't able to come with a better design, you should either call the endpoint via ir.http in case there is a database either call the endpoint immediately:
if self.request.db:
return self.request.registry['ir.http']._dispatch(endpoint)
else:
return endpoint(**self.request.params)
The endpoint is free to return anything, it is only dispatch that must return a response.
post_dispatch(self, response) -> None
You override this method when you need to manipulate the response. This is where we save the session back on the file-system and where we inject some Content-Security-Policy headers.
handle_error(self, exc) -> werkzeug.wrappers.Response
You implement this method to convert the exception into a response object. This is where we convert odoo.exception.UserError to werkzeug.exception.BadRequest.
Keep in my that this new architecture is still subject to change. We are not entirely satisfied by the way request.params works, like some argue that it is set too late. I'll keep you update to date if there are important changes.
If you have any question you can reach me here or via my work email. I may be faster to reply here on github.
@Julien00859 A big thank you for the followup and the provided details! The new approach improve a lot this part of the code into odoo and provide now a better way to plug additional ways to process HTTP queries.
There hasn't been any activity on this issue in the past 6 months, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 30 days. If you want this issue to never become stale, please ask a PSC member to apply the "no stale" label.