Search code examples
python-3.xodooresponsehttpresponsejson-rpc

How to set response status code in route with type json in odoo 14


I have created a route with type Json in odoo 14.

@http.route('/test', auth='public', methods=['POST'], type="json", csrf=False)
def recieve_data(self, **kw):
       headers = request.httprequest.headers
       args = request.httprequest.args
       data = request.jsonrequest

So when I receive request using this route everything is fine, but suppose I want to return a different status code like 401, I could not do that with the route which type is json. I have also tried the bellow method but the problem with this method is that it stops all odoo future requests.

from odoo.http import request, Response
@http.route('/test', auth='public', methods=['POST'], type="json", csrf=False)
def recieve_data(self, **kw):
      headers = request.httprequest.headers
      args = request.httprequest.args 
      data = request.jsonrequest
      Response.status = "401 unauthorized"
      return {'error' : 'You are not allowed to access the resource'}

So in the above example If I set the response status code to 401 all other requests even if they are to different routes will be stopped and its status code changes 401 . I have checked this problem in both odoo14 and odoo13.


Solution

  • You cannot specify the code of the response, as you can see the status code is hardcoded in http.py:

    def _json_response(self, result=None, error=None):
    
       # ......
       # ......
    
        return Response(
            body, status=error and error.pop('http_status', 200) or 200,
            headers=[('Content-Type', mime), ('Content-Length', len(body))]
        )
    

    If the result is not an error the status code is always 200. but you can change the code of the method directly or use a monkey patch witch if it's not really important to specify the code of status in the result don't do ti ^^.

    A simple monkey patch put this in __init__.py of the module that you want this behavior in it.

    from odoo.http import JsonRequest
    
    class JsonRequestPatch(JsonRequest):
    
        def _json_response(self, result=None, error=None):
            response = {
                'jsonrpc': '2.0',
                'id': self.jsonrequest.get('id')
                }
            default_code = 200
            if error is not None:
                response['error'] = error
            if result is not None:
                response['result'] = result
                # you don't want to remove some key of another result by mistake
                if isinstance(response, dict)
                    defautl_code = response.pop('very_very_rare_key_here', default_code)
    
            mime = 'application/json'
            body = json.dumps(response, default=date_utils.json_default)
    
            return Response(
                body, status=error and error.pop('http_status', defautl_code ) or defautl_code,
                headers=[('Content-Type', mime), ('Content-Length', len(body))]
            )
            
            
    JsonRequest._json_response = JsonRequestPatch._json_response
    

    and in the result of JSON api you can change the code of status like this

     def some_controler(self, **kwargs):
            result = ......
            result['very_very_rare_key_here'] = 401
            return result
    

    The risk in monkey patching is you override the method compeletly and if some change is done in Odoo in new version you have to do you it in your method too. The above code is from odoo 13.0 I did a lot of this when I build a restfull module to work with a website uses axios witch don't allow sending body in GET request. and odoo expect the argument to be inside the body in json request.