10

A few days ago I did a similar question here: How to get JSON data in an Odoo controller?

But now, I need to create a controller which receives only JSON data. So, I am doing the request from a Python console, this way:

import requests
import json

url = 'http://localhost:8069/odoo/test'
headers = {'Content-Type': 'application/json'}
data = {
    'name': 'Jane',
    'email': 'jane.doe@gmail.com',
}
data_json = json.dumps(data)
r = requests.post(url=url, data=data_json, headers=headers)

I have created a controller which listens to http://localhost:8069/odoo/test, this way:

import openerp.http as http
from openerp.http import Response
import logging
_logger = logging.getLogger(__name__)


class WebFormController(http.Controller):

    @http.route('/odoo/test', type='json',
                auth='public', methods=['POST'], website=True)
    def index(self, **args):
        _logger.info('CONNECTION SUCCESSFUL')
        _logger.info(args)
        name = args.get('name', False)
        email = args.get('email', False)
        _logger.info(name)
        _logger.info(email)
        if not name:
            Response.status = '400 Bad Request'
        return '{"response": "OK"}'

The problem is that I am receiving an empty JSON in the controller. I can read CONNECTION SUCCESFUL in the log, with no error, but when I show args, I get {}, and obviously due to that, False when writing name and email.

If I pass the data as a Python dictionary or as a string, I get the following error:

Invalid JSON data: 'name=Jane&email=jane.doe%40gmail.com' or Invalid JSON data: "{'name': 'Jane', 'email': 'jane.doe@gmail.com'}" respectively.

If I modify type='json' and I write type='http' instead, I get the following error:

Function declared as capable of handling request of type 'http' but called with a request of type 'json'.

I have read that may be this could be solved if the request is sent using the parameter json instead of data, this way:

r = requests.post(url=url, json=data_json, headers=headers)

Unfortunately, the server which is going to make the request has an old operating system which cannot update the python-requests package, so I cannot use json parameter since it did not exist at the version installed in that server.

Please, can anyone help me? I need get JSON data in the controller, not a string neither Python dictionaries.

forvas
  • 9,801
  • 7
  • 62
  • 158
  • maybe your missing csrf_token? – mokiSRB May 09 '16 at 10:58
  • thank you for answering @mokiSRB, but `csrf_token` is a new feature of Odoo 9, and I am working with Odoo 8, so that should not be the problem. I am seeing other JSON controllers in Odoo and all of them are called from JavaScript with libraries like `openerp.jsonRpc`. How can I send data to the controller from a simple Python script (using `requests` for example) like the above one? – forvas May 09 '16 at 14:28
  • When I work with rest api and Odoo, I usually start with Postman queries, then copy the code, for some reasons request doesn't work with `curl` but it works in postman, this is due to the double quote symbol which need to be escaped, see also: https://stackoverflow.com/questions/32122586/curl-escape-single-quote/39802572 – Ibrahim.H Sep 25 '20 at 21:14

3 Answers3

10

You have just forgotten to put your data inside the params keywords:

Use this correct syntax :

data = {"params": dict(key="value")}

data = {
    "params": {
        "name":"prakashsharma",
        "email":"prakashsharmacs24@gmail.com",
        "phone":"+917859884833"
    }
}

Please don't forget to use json.dumps(data) and 'Content-Type': 'application/json' while requesting a resource in json format.

I am damn sure your issue will be solved after using this one my friend... cheers :)!!

forvas
  • 9,801
  • 7
  • 62
  • 158
Prakash Kumar
  • 2,554
  • 2
  • 18
  • 28
  • that was exactly the problem! You have helped me a lot! Thank you very much my friend!! – forvas May 09 '16 at 16:05
  • @forvas: Is it possible to access this from another platform? whenever I try to access this url from Postman it was returning 404. But possible to access from the browser in which the user logged in. – Muneer Muhammed Jan 18 '18 at 04:42
  • @MuneerMuhammed yes, it is, in fact, a website of a customer was sending these JSON data to my Odoo. – forvas Jan 18 '18 at 09:31
1

You can use below format for a POST request

{
"params" : {
    "name" : "Order/1/18",
    "session_id" : 1,
    "customer_count" : 2,
    "partner_id" : 9,
    "lines": [
        {
            "product_id": 37,
            "qty" : 2,
            "price_unit" : 2,
            "discount" : 10
        }
        ],
    "pos_reference" : 2,
    "note" : "This is a test note"
}
}

Content type must be application/json

How odoo route will handle request ?

Route will help creating a POS order in odoo [POST]

@http.route(['/api/v1/resources/<string:api_key>/pos_order'], 
            auth="public",
            website=False,
            type="json",
            csrf=False,
            methods = ['POST'])
def create_update_pos_order(self, api_key=None, **kwargs):
    print(kwargs.get('name')) -> Order/1/18
Community
  • 1
  • 1
0

God Bless Forvas:: But for more clearity: if you want to test through cURL:

curl -i -X POST -H "Content-Type: application/json" -d '{"params": {"name":"prakashsharma","email":"prakashsharmacs24@gmail.com","phone":"+917859884833"}}' 'http://localhost:8069/web/yourlistoner/'

if you want to test through python request:

import requests

headers = {
    'Content-Type': 'application/json',
}

data = '{"params": {"name":"prakashsharma","email":"prakashsharmacs24@gmail.com","phone":"+917859884833"}}'

requests.post('http://localhost:8069/web/yourlistoner/', headers=headers, data=data)

the function in odoo will be something like

from odoo import http
import json

class YourClass(http.Controller):
    @http.route('/web/yourlistoner/', type='json', auth="none", methods=['POST'],cors="*", csrf=False)
    def listoner(self, **kw):

        print http.request.params
        print "lllllllllllllllllllll"
        return json.dumps({"result":"Success"}) 
wahab ali
  • 41
  • 1