Aemal Shirzai
Aemal Shirzai

Reputation: 65

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.

Upvotes: 4

Views: 4218

Answers (2)

Mi Cha
Mi Cha

Reputation: 23

just for the sake of completion, here is a minor fix based on the comment of Charif DZ.

You have to pop your custom http-Status from result and not from response.

But many thanks for pointing in the right direction.

Is working in Odoo 14 and should also work with Odoo 13 as the original _json_response method is the same.

from odoo.http import JsonRequest, Response
from odoo.tools import date_utils

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(result, dict):
                default_code = result.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', default_code) or default_code,
            headers=[('Content-Type', mime), ('Content-Length', len(body))]
        )
        
        
JsonRequest._json_response = JsonRequestPatch._json_response

the controller logic remains the same as above

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

Upvotes: 0

Charif DZ
Charif DZ

Reputation: 14751

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.

Upvotes: 9

Related Questions