Search code examples
pythonjsonodoowerkzeug

In odoo's controller file, how to change the json response format when the type is json?


The application/json in the request header and json string in the request body when I initiate an http request , the Odoo server receives the request, but the json returned to the client is not what I want to return.

Here are two additional key,jsonrpc,id,result.The dictionary corresponding to the key result is what I really want to return to the client.

And if I change the type variable in the http.route to http instead of json, I will can't receive json format data from the client.

What shoul I do?Thanks everyone!

My Odoo version is 10,python version is 2.7.12

Here is my code

controllers.py

from odoo.http import Controller,route
class API(Controller):
    @route('/v1/access_something',type='json',auth='none',csrf=False,methods=['GET'])
    def access_something(self,**kwargs):
        return {"a":1,"b":2}

Test interface with requests

import requests
re = requests.get('http://192.168.1.55:8069/v1/access_something',json={"c":1},headers={'Content-Type':'application/json'})
print(re.json())

The data in re.json()

{
    "jsonrpc": "2.0",
    "id": null,
    "result": {
        "a": 1,
        "b": 2
    }
}

But the following result is what I want.

{
    "a": 1,
    "b": 2
}


Solution

  • I've found a way to solve this problem.

    This problem arises because there is a method _json_responsein the source code JsonRequestthat we can overwrite dynamically.

    In order not to interfere with the use of the original framework by others, we can pass our own specific parameters in our own decorator@http.routeby using kwargs. We construct the json dictionary we need to return to the client by determining whether the decorator has our own parameters.

    Here is my codecontrollers.py

    from odoo.http import Controller,route,JsonRequest
    
    def _json_response(self, result=None, error=None):
        lover = self.endpoint.routing.get('lover')
        if lover == 'chun':
            response = {}
            if error is not None:
                response['error'] = error
            if result is not None:
                response = result
        else:
            response = {
                'jsonrpc': '2.0',
                'id': self.jsonrequest.get('id')
            }
            if error is not None:
                response['error'] = error
            if result is not None:
                response['result'] = result
    
        if self.jsonp:
            # If we use jsonp, that's mean we are called from another host
            # Some browser (IE and Safari) do no allow third party cookies
            # We need then to manage http sessions manually.
            response['session_id'] = self.session.sid
            mime = 'application/javascript'
            body = "%s(%s);" % (self.jsonp, json.dumps(response),)
        else:
            mime = 'application/json'
            body = json.dumps(response)
    
        return Response(
            body, headers=[('Content-Type', mime),
                           ('Content-Length', len(body))])
    
    setattr(JsonRequest,'_json_response',_json_response) #overwrite the method
    
    class API(Controller):
        @route('/v1/access_something',type='json',auth='none',csrf=False,methods=['GET'],lover='chun')
        def access_something(self,**kwargs):
            return {"a":1,"b":2}
    

    The specific parameter lover='chun' is basis of our judgment.In method _json_response,we can get this parameter through self.endpoint.routing.get('lover')