Search code examples
pythonjsoncontrollerodooodoo-11

How to send json in response at Get Endpoint Odoo v11


Currently trying to call a odoo controller which return json data as per my exception.

@http.route('/web/update_order_webhook', type='http', csrf=False, auth="public")
def update_order_webhook(self, **kwargs):
    return Response(json.dumps({"yes":"i am json"}),content_type='application/json;charset=utf-8',status=200)

When I tried to call this end point

import requests

url = "http://159.89.197.219:8069/web/update_order_webhook"

headers = {
    'content-type': "application/json"
    }

response = requests.request("GET", url, headers=headers)

print(response.text)

I get Request Body

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>400 Bad Request</title>
<h1>Bad Request</h1>
<p>Invalid JSON data: ''</p>

And Request Header at my calling end point

content-length →137
content-type →text/html
date →Thu, 11 Jan 2018 20:32:53 GMT
server →Werkzeug/0.13 Python/3.5.2

that clearly mean that I am not getting json response data from my odoo endpoint. As per last answer I had update my code

@http.route('/web/update_order_webhook', type='json', auth="public", website=True)
    def update_order_webhook(self, **kwargs):
         return json.dumps({"yes":"i am json"})

But now I got new error while I called my endpoint

Bad Request
<function Binary.update_order_webhook at 0x7efd82ac8510>, /web/update_order_webhook: Function declared as capable of handling request of type 'json' but called with a request of type 'http'

Solution

  • As an update to your question, I invite you to check the link bellow, it treat the same issue as yours : https://www.odoo.com/fr_FR/forum/aide-1/question/web-webclient-version-info-function-declared-as-capable-of-handling-request-of-type-json-but-called-with-a-request-of-type-http-100834

    So the solution was to set the python method as you already have done with the type 'json', also use a 'POST method when requesting the server, in the client side you have to make a GET request and get the result from the json field.

    The python method will be :

    @http.route('/web/update_order_webhook',methods=['POST'], type='json', csrf=False, auth="public")
        def update_order_webhook(self, **kwargs):
            return Response(json.dumps({"yes":"i am json"}),content_type='application/json;charset=utf-8',status=200)
    

    The client side will be :

    import requests
    url = "http://159.89.197.219:8069/web/update_order_webhook"
    payload = {'key1':'val1','key2':'val2'}
    response = requests.post(url, data=payload)
    print(response.text)
    print(response.json())
    

    Check this url to see more details about the new way to make requests in pyhton : http://docs.python-requests.org/en/master/user/quickstart/#more-complicated-post-requests

    End of update

    To replace the header type of your request :text/html if you want to return an HTMl response, otherwise the response type of the method must be 'json'

    @http.route('/web/update_order_webhook', type='json', csrf=False, auth="public")
    def update_order_webhook(self, **kwargs):
        return Response(json.dumps({"yes":"i am json"}),content_type='application/json;charset=utf-8',status=200)
    

    Also take a look at this example from the odoo github repo : https://github.com/odoo/odoo/blob/11.0/addons/calendar/controllers/main.py

    the accept method of the calendar main controller :

    @http.route('/calendar/meeting/accept', type='http', auth="calendar")
        def accept(self, db, token, action, id, **kwargs):
            registry = registry_get(db)
            with registry.cursor() as cr:
                env = Environment(cr, SUPERUSER_ID, {})
                attendee = env['calendar.attendee'].search([('access_token', '=', token), ('state', '!=', 'accepted')])
                if attendee:
                    attendee.do_accept()
            return self.view(db, token, action, id, view='form')
    

    If you look at the return of this method you will notice that it's a view (a form view ) so the response type is http

    In the same file you will find the method notify_ack that returns a json response so the type is set to 'json'

    @http.route('/calendar/notify_ack', type='json', auth="user")
        def notify_ack(self, type=''):
            return request.env['res.partner']._set_calendar_last_notif_ack()