v 8.0 v 9.0 v 10.0 v 11.0 v 12.0 Third Party 241
Live Preview
Availability
Odoo Online
Odoo.sh
On Premise
Lines of code 1084
Technical Name rest_api
LicenseOPL-1
Websitehttps://app.swaggerhub.com/apis-docs/avs3/odoo_rest_api/1
Versions 17.0 13.0 8.0 9.0 10.0 11.0 12.0 14.0 15.0 16.0
You bought this module and need support? Click here!
Availability
Odoo Online
Odoo.sh
On Premise
Lines of code 1084
Technical Name rest_api
LicenseOPL-1
Websitehttps://app.swaggerhub.com/apis-docs/avs3/odoo_rest_api/1
Versions 17.0 13.0 8.0 9.0 10.0 11.0 12.0 14.0 15.0 16.0
Community Enterprise Odoo.sh On-Premise Self-Hosted

REST API engine for quick and productive developers



Overview

Enhanced RESTful API access to Odoo resources with simplified variant of OAuth2 authentication and OpenAPI specification.

The module may have a predefined (statically and dynamically customizable) tree-like schema of response Odoo fields for 'Read one', 'Read all' and 'Create one' methods. This allow not to fetch unnecessary fields (like a heavy image/binary fields or technical garbage fields) in each request or not to compose the list of desired fields in each request. Also that schemas can be used as a quick and clear model reference guide for your developers (backend, client side, etc.). See "Example #3" below.

The schema of the response fields can have a tree-like structure with any level of nesting. So you can read an object at once with absolutely all its inner data (including its lines with all inner data) in just one http request. Therefore you don't need to make a two (or much more) requests to get one object (if would so, the possible interruptions or lags between that requests can be fatal to the integrity of your data). See "Example #1" below.

The schema of the request fields can have a tree-like structure with one (and more in some cases) level of nesting. So you can easily update (or create) an object at once with all its lines (including all their data) in just one http request. See "Example #2" below.

This module has a high-load ready feature: it uses a mechanism which allow to cope with intensive and concurrent reading and writing the same Odoo records.

The previous features improves the integrity of your data, enhance the reliability of data processing and also reduce the size and complexity of code on your REST client side.

Also this module allow to fetch any PDF report, attachment or binary data from Odoo.

This module works with standard and custom Odoo models, also this API is CORS compatible.

All features and behaviour of this module are identical in all Odoo versions, so you will not have a problems when migrating.

We don't cheat with itself purchasing and don't use any SEO techniques.


By default, all Odoo models have a flat and non-predefined response schema.

There are two possible ways to set up predefined schemas for any Odoo model - in UI mode or by generating a special file. The special files also allow to create a custom API routes/endpoints, and in this case you can debug its code like an ordinary Python code using your favorite IDE.

Each Odoo model has the following API methods:
  • Read all (with optional filters, offset, limit, order, exclude_fields, include_fields)
  • Read one (with optional exclude_fields, include_fields)
  • Create one (with optional static default values)
  • Update one/multi
  • Delete one/multi
  • Call any method of Odoo model, including workflow manipulations (till the Odoo v10)
Also the 'Call any method' feature allow to execute any standard model's methods, like:
  • copy()
  • check_access_rights()
  • check_access_rule()
  • fields_get()
  • etc.


Simple REST Client example (Python):
import requests

# Authentication
r = requests.get('https://rest-api-demo.root.sx/api/auth/get_tokens?username=demo&password=demo')
access_token = r.json()['access_token']

# GET - Read record
r = requests.get(
    'https://rest-api-demo.root.sx/api/sale.order/21',
    headers = {'Access-Token': access_token})
print(r.json())

# PUT - Update record
r = requests.put(
    'https://rest-api-demo.root.sx/api/res.partner/26?name=Tom Lenz&city=New York',
    headers = {'Access-Token': access_token})
print(r)


Custom API route/endpoint example:
from .main import *

class ControllerREST(http.Controller):
    @http.route('/api/your.custom.endpoint', methods=['GET'], type='http', auth='none', cors=rest_cors_value)
    @check_permissions
    def a(self, **kw):
        # get Odoo env params
        cr, uid = request.cr, request.session.uid
        # get any model as ordinary Odoo object
        odoo_model_obj = request.env(cr, uid)['res.partner']
        # make models manipulations, actions, computations etc. And if you need, fill the results dictionary
        your_custom_dict_data = {'your_vals': '...'}
        # send HTTP response
        return successful_response(status=200, dict_data=your_custom_dict_data)


Installation and Setup


First install one Python dependency:

pip install simplejson

Then install this module as ordinary Odoo module - in developer mode, go to menu Apps > Update Apps List > find this app 'rest_api' and install it.

This module requires 'db_name' Odoo config parameter (or command line option) with only one database (without aliases)!:

    (config parameter)
db_name = your_db_name

    (or command line option)
--database=your_db_name

After the installation (or updating) of this module it need to restart Odoo server!


This module adds the following 'System Parameters' in Odoo:
  • rest_api.access_token_expires_in (600 seconds)
  • rest_api.refresh_token_expires_in (7200 seconds)
  • rest_api.cors_parameter_value_in_all_routes ('null')
  • rest_api.u_escape_characters_for_unicode_in_responses (False)
  • rest_api.use_redis_token_store (False)
  • rest_api.redis_host (localhost)
  • rest_api.redis_port (6379)
  • rest_api.redis_db (0)
  • rest_api.redis_password (None)

If you want to use the Redis token store (what is optional), you should set the Odoo system parameter rest_api.use_redis_token_store = True, and also you need to install, (optional) setup and run Redis server, something like this (in terminal):

    (choose your package manager)
sudo apt install redis-server python3-redis
sudo apt-get install redis-server python3-redis
sudo yum install redis python3-redis
sudo dnf install redis python3-redis
    (run)
redis-server

And then restart Odoo server.

Useful Redis links:

  • https://pypi.python.org/pypi/redis
  • https://redis.io/topics/quickstart


First possible way to set up predefined schemas for any Odoo model - in UI mode:

Activate the developer mode, go to the menu Settings > Technical > Database Structure > Models, open desired model and go to "REST API" tab:


Here is the syntax of the schema (also you can see the working schema in "Example #3").



Second possible way to set up predefined schemas for any Odoo model - by generating a special file:

1. In terminal, go to the controllers folder and run SCRIPT_add_model.sh script (previously ensure you have execution rights on script and write permissions inside the folder and its files):

cd <your odoo addons path>/rest_api/controllers/
./SCRIPT_add_model.sh

That script will ask you desired model name and will create a new model file - model__your_model_name.py

2. In that new file, fill the three schemas of response Odoo fields for "Read one", "Read all" and "Create one" methods in three variables - OUT__your_model_name__read_one__SCHEMA, OUT__your_model_name__read_all__SCHEMA and OUT__your_model_name__create_one__SCHEMA.

Here is the syntax of the schema (also you can see the working schema in "Example #3"):
(
    # simple fields (non relational):

    'simple_field_1',
    'simple_field_2',
    ...

    # many2one fields:

    'many2one_field_1',     # will return just 'id'
    OR
    ('many2one_field_1', (  # will return dictionary of inner fields
        'inner_field_1',
        'inner_field_2',
        ...
    )),
    ...

    # one2many fields:

    ('one2many_field_1', [(
        'inner_field_1',
        'inner_field_2',
        ...
    )]),
    ...

    # many2many fields:

    ('many2many_field_1', [(
        'inner_field_1',
        'inner_field_2',
        ...
    )]),
    ...

)

There can be any level of nesting of inner fields.

If you'll want to add or remove some Odoo field in REST API in the future, you'll need just add or remove/comment out a field in this schema.

3. If necessary (but not mandatory), change the values of some variables which are labeled by tag # editable in that file. There are such variables:

- default values in "Create one" method;
- successful response codes in all methods;
- etc.

4. Restart Odoo server.

The advantages of that method:

  • you can create your custom API route/endpoint with your custom arbitrary code (for example call some Server Action, etc.),
  • API controller in a separate file allow to debug its code like an ordinary Python code using your favorite IDE,
  • you can create multiple versions of the same API resource (eg for different REST clients).


Examples and Tests


See endpoints DOCUMENTATION, online TESTS & EXAMPLES and also simple REST Client Python example.


Simple 'cURL' tests:

(Bash syntax)

1. Login in Odoo and get access and refresh token:
curl -i -H "Content-Type: text/html"   -X GET   http://localhost:8069/api/auth/get_tokens   -d '{"username":"admin", "password":"admin"}'

2. Refresh access token:
curl -i -H "Content-Type: text/html"   -X POST   http://localhost:8069/api/auth/refresh_token   -d '{"refresh_token":"XXXXXXXXXXXXXXXXX"}'

3. Delete access token:
curl -i -H "Content-Type: text/html"   -X POST   http://localhost:8069/api/auth/delete_tokens   -d '{"refresh_token":"XXXXXXXXXXXXXXXXX"}'

4. res.partner - Read all (without filters):
curl -i -H "Content-Type: text/html"   -X GET   http://localhost:8069/api/res.partner   -H "Access-Token: XXXXXXXXXXXXXXXXX"

5. res.partner - Read all (with two filters):
curl -i -H "Content-Type: text/html"   -X GET   http://localhost:8069/api/res.partner   -H "Access-Token: XXXXXXXXXXXXXXXXX"   -d '{"filters": [["name", "like", "ompany"], ["id", "<=", 50]]}'

6. res.partner - Read one:
curl -i -H "Content-Type: text/html"   -X GET   http://localhost:8069/api/res.partner/3   -H "Access-Token: XXXXXXXXXXXXXXXXX"

7. res.partner - Create one:
curl -i -H "Content-Type: text/html"   -X POST   http://localhost:8069/api/res.partner   -H "Access-Token: XXXXXXXXXXXXXXXXX"   -d '{"name": "TEST Name", "street": "TEST Street", "city": "TEST City"}'

8. res.partner - Update one:
curl -i -H "Content-Type: text/html"   -X PUT   http://localhost:8069/api/res.partner/2361   -H "Access-Token: XXXXXXXXXXXXXXXXX"   -d '{"name": "TEST Name~~", "street": "TEST Street~~", "city": "TEST City~~"}'

9. res.partner - Delete multi:
curl -i -H "Content-Type: text/html"   -X DELETE   http://localhost:8069/api/res.partner/57,58,59   -H "Access-Token: XXXXXXXXXXXXXXXXX"

10. res.partner - Call method 'address_get' (without parameters):
curl -i -H "Content-Type: text/html"   -X PUT   http://localhost:8069/api/res.partner/2361/address_get   -H "Access-Token: XXXXXXXXXXXXXXXXX"

11. res.partner - Call method '_email_send' (with parameters and context):
curl -i -H "Content-Type: text/html"   -X PUT   http://localhost:8069/api/res.partner/2361/_email_send   -H "Access-Token: XXXXXXXXXXXXXXXXX"   -d '{"email_from": "test@test.com", "subject": "TEST Subject", "body": "TEST Body", "__context__": {"lang": "en_US"}}'

12. report - Call method 'get_pdf' (with parameters):
curl -i -H "Content-Type: text/html"   -X GET   http://localhost:8069/api/report/get_pdf   -H "Access-Token: XXXXXXXXXXXXXXXXX"   -d '{"report_name": "account.report_invoice", "ids": [3]}'

Python examples and tests:
  • /rest_api/tests/test__Auth_GetTokens.py
  • /rest_api/tests/test__Create__OrderInvoice.py
  • /rest_api/tests/test__Create__product.template.py
  • /rest_api/tests/test__Create__res.partner.py
  • /rest_api/tests/test__CreateWithAttributes__product.template.py
  • /rest_api/tests/test__CreateWithImage__res.partner.py
  • /rest_api/tests/test__CreateWithVendors__product.template.py
  • /rest_api/tests/test__get_pdf__report.py
  • /rest_api/tests/test__ReadAllWithFiltersInURL__res.partner.py
  • /rest_api/tests/test__ReadAllWithFiltersOffsetLimitOrder__res.partner.py
  • /rest_api/tests/test__ReadOneWithIncludeFieldsInURL__res.partner.py
  • /rest_api/tests/test__Update__res.partner.py
  • /rest_api/tests/test__Update__SO_TaxInLine.py
  • /rest_api/tests/test__UpdateWithVendors__product.template.py


Example #1: 'sale.order - Read one' - response json:

{
  • "date_order": "2016-06-02 18:41:42",
  • "name": "SO001",
  • "partner_id": {
    • "city": "City 1",
    • "id": 6,
    • "name": "Customer 1"
    },
  • "order_line": [
    1. {
      • "name": "Product 1",
      • "price_unit": 111,
      • "product_uom_qty": 11,
      • "price_subtotal": 1221,
      • "product_id": {
        • "barcode": "2400000032632",
        • "name": "Product 1",
        • "type": "consu",
        • "attribute_line_ids": [
          1. {
            • "display_name": "Attribute 1",
            • "id": 1
            },
          2. {
            • "display_name": "Attribute 2",
            • "id": 2
            }
          ],
        • "categ_id": {
          • "id": 1,
          • "name": "All"
          },
        • "id": 2
        },
      • "id": 1,
      • "tax_id": [
        1. {
          • "id": 6,
          • "name": "ITAX X"
          },
        2. {
          • "id": 7,
          • "name": "Tax 15.00%"
          }
        ]
      },
    2. {
      • "name": "Product 2",
      • "price_unit": 222,
      • "product_uom_qty": 22,
      • "price_subtotal": 4884,
      • "product_id": {
        • "barcode": null,
        • "name": "Product 2",
        • "type": "consu",
        • "attribute_line_ids": [],
        • "categ_id": {
          • "id": 1,
          • "name": "All"
          },
        • "id": 3
        },
      • "id": 2,
      • "tax_id": [
        1. {
          • "id": 7,
          • "name": "Tax 15.00%"
          }
        ]
      }
    ],
  • "amount_tax": 915.75,
  • "state": "manual",
  • "user_id": {
    • "id": 1,
    • "name": "Admin"
    },
  • "create_date": "2016-06-02 18:42:48",
  • "payment_term_id": {
    • "id": 2,
    • "name": "15 Days"
    },
  • "id": 1,
  • "amount_total": 7020.75
}


Example #2: 'res.partner - Update one' - request json:

{
  • # simple fields (non relational):
  • "name": "TEST Name~~",
  • "street": "TEST Street~~",
  • "street2": "TEST Street2~~",
  • "city": "TEST City~~",
  • "zip": "123~~",
  • "phone": "+123456789~~",
  • "email": "a@b.com~~",
  • # many2one fields (existing 'id', not dictionary of new record!):
  • "state_id": 6,
  • "country_id": 14,
  • # one2many fields (list of dictionaries of records):
  • "bank_ids": [
    1. {
      • # this record will be updated (because 'id' is specified)
      • "id": 56,
      • "acc_number": "acc_number 1~~",
      • "bank_bic": "bank_bic 1~~"
      },
    2. {
      • # this record will be removed (because 'id' is specified and record is empty)
      • "id": 57
      },
    3. {
      • # this record will be created (because 'id' is not specified but record is not empty)
      • "acc_number": "acc_number 4",
      • "bank_bic": "bank_bic 4"
      }
    ],
  • # many2many fields (list of dictionaries of existing 'ids'):
  • "category_id": [
    1. # field's values will be replaced by this 'ids'
    2. {
      • "id": 3
      },
    3. {
      • "id": 4
      }
    ]
}

For "x2many" fields in second and deeper levels of nesting, you can use the special Odoo format.


Example #3: 'sale.order - Read one' - response fields schema:

(
    # simple fields (non relational):
    'id',
    'name',
    'date_order',
    'create_date',
    'amount_tax',
    'amount_total',
    'state',
    # many2one fields:
    ('partner_id', (
        'id',
        'name',
        'city',
    )),
    ('user_id', (
        'id',
        'name',
    )),
    ('payment_term_id', (
        'id',
        'name',
    )),
    # one2many fields:
    ('order_line', [(
        'id',
        ('product_id', (  # many2one
            'id',
            'name',
            'type',
            'barcode',
            ('categ_id', (  # many2one
                'id',
                'name',
            )),
            ('attribute_line_ids', [(  # one2many
                'id',
                'display_name',
            )]),
        )),
        'name',
        'product_uom_qty',
        'price_unit',
        ('tax_id', [(  # many2many
            'id',
            'name',
        )]),
        'price_subtotal',
    )]),
)


Example #5: 'res.partner - Create one' - request json:

{
  • # simple fields (non relational):
  • "name": "TEST Name",
  • "street": "TEST Street",
  • "street2": "TEST Street2",
  • "city": "TEST City",
  • "zip": "123",
  • "phone": "+123456789",
  • "email": "a@b.com",
  • # many2one fields (existing 'id', not dictionary of new record!):
  • "state_id": 10,
  • "country_id": 235,
  • # one2many fields (list of dictionaries of new records):
  • "bank_ids": [
    1. {
      • "acc_number": "acc_number 1",
      • "bank_bic": "bank_bic 1"
      },
    2. {
      • "acc_number": "acc_number 2",
      • "bank_bic": "bank_bic 2"
      },
    3. {
      • "acc_number": "acc_number 3",
      • "bank_bic": "bank_bic 3"
      }
    ],
  • # many2many fields (list of dictionaries of existing 'ids'):
  • "category_id": [
    1. {
      • "id": 1
      },
    2. {
      • "id": 2
      }
    ]
}

For "x2many" fields in second and deeper levels of nesting, you can use the special Odoo format.



Support

The support consists of free lifetime bug-fixing and keeping the actuality of this module's code according with all stable and old (since v8) Odoo versions.

@odoo-rest_api:matrix.org
odoo-rest_api#2144
Odoo Proprietary License v1.0

This software and associated files (the "Software") may only be used (executed,
modified, executed after modifications) if you have purchased a valid license
from the authors, typically via Odoo Apps, or if you have received a written
agreement from the authors of the Software (see the COPYRIGHT file).

You may develop Odoo modules that use the Software as a library (typically
by depending on it, importing it and using its resources), but without copying
any source code or material from the Software. You may distribute those
modules under the license of your choice, provided that this license is
compatible with the terms of the Odoo Proprietary License (For example:
LGPL, MIT, or proprietary licenses similar to this one).

It is forbidden to publish, distribute, sublicense, or sell copies of the Software
or modified copies of the Software.

The above copyright notice and this permission notice must be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

Please log in to comment on this module

  • The author can leave a single reply to each comment.
  • This section is meant to ask simple questions or leave a rating. Every report of a problem experienced while using the module should be addressed to the author directly (refer to the following point).
  • If you want to start a discussion with the author or have a question related to your purchase, please use the support page.