Skip to content

Commit d74377a

Browse files
[ADD] endpoint_json2
1 parent 477c13c commit d74377a

21 files changed

Lines changed: 2248 additions & 0 deletions

endpoint_json2/README.rst

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
.. image:: https://odoo-community.org/readme-banner-image
2+
:target: https://odoo-community.org/get-involved?utm_source=readme
3+
:alt: Odoo Community Association
4+
5+
==============
6+
Endpoint JSON2
7+
==============
8+
9+
..
10+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
11+
!! This file is generated by oca-gen-addon-readme !!
12+
!! changes will be overwritten. !!
13+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14+
!! source digest: sha256:c7e6ba5b070db8b93a1ae44bd87344a39b885ff2b4667a1a26e9e7b1cc677402
15+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
16+
17+
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
18+
:target: https://odoo-community.org/page/development-status
19+
:alt: Alpha
20+
.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png
21+
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
22+
:alt: License: LGPL-3
23+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb--api-lightgray.png?logo=github
24+
:target: https://github.com/OCA/web-api/tree/19.0/endpoint_json2
25+
:alt: OCA/web-api
26+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
27+
:target: https://translation.odoo-community.org/projects/web-api-19-0/web-api-19-0-endpoint_json2
28+
:alt: Translate me on Weblate
29+
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
30+
:target: https://runboat.odoo-community.org/builds?repo=OCA/web-api&target_branch=19.0
31+
:alt: Try me on Runboat
32+
33+
|badge1| |badge2| |badge3| |badge4| |badge5|
34+
35+
Adds ``exec_mode="json2"`` to the endpoint framework, enabling
36+
declarative JSON-2 API endpoint configuration. Select a model, method,
37+
and parameters — the module handles dispatch, parameter validation,
38+
access control, and result filtering. A code snippet can be used as an
39+
alternative to a model method for quick, ad-hoc logic.
40+
41+
Also provides auto-generated API documentation endpoints at
42+
``/json2/doc``.
43+
44+
.. IMPORTANT::
45+
This is an alpha version, the data model and design can change at any time without warning.
46+
Only for development or testing purpose, do not use in production.
47+
`More details on development status <https://odoo-community.org/page/development-status>`_
48+
49+
**Table of contents**
50+
51+
.. contents::
52+
:local:
53+
54+
Configuration
55+
=============
56+
57+
Go to *Settings > Technical > Endpoints* and create a new endpoint with
58+
**Exec Mode** set to **JSON-2 API**.
59+
60+
Basic Setup
61+
-----------
62+
63+
- **Route Group** and **Name**: Together these determine the endpoint
64+
URL, which is automatically computed as
65+
``/json2/{route_group}/{name}``. For example, a route group
66+
``contacts`` with name ``get_partners`` produces
67+
``/json2/contacts/get_partners``. The route group also organizes
68+
endpoints in the API documentation at ``/json2/doc/{route_group}``.
69+
70+
- **Model**: The Odoo model to operate on (e.g. ``res.partner``).
71+
72+
- **Method**: A public model method (e.g. ``search_read``).
73+
Alternatively, provide a **Code Snippet** for custom logic — these
74+
two fields are mutually exclusive.
75+
76+
- **Response Fields**: One field per line. Optionally follow with an
77+
alias to rename the key in the response. Use dotted notation (one
78+
level) for relational fields (Many2one, Many2many, One2many). Leave
79+
empty to return all fields. Example:
80+
81+
::
82+
83+
name
84+
email
85+
country_id.name country
86+
write_date last_modified
87+
88+
- **Default Domain**: A JSON-formatted domain filter applied to every
89+
request (e.g. ``[["active", "=", true]]``).
90+
91+
- **Parameters**: Define named parameters with types, defaults, and
92+
required flags. These are validated before the method is called.
93+
94+
Access Control
95+
--------------
96+
97+
All endpoint execution is wrapped in ``sudo()``, allowing API users to
98+
operate with minimal Odoo privileges. Access is controlled at two
99+
levels:
100+
101+
- **Auth Type**: Select the authentication method for the endpoint
102+
(e.g. **Bearer** for API key authentication).
103+
- **Allowed Groups**: Restrict endpoint access to specific user groups.
104+
Create integration-specific groups (e.g. "Hospital System", "WMS")
105+
and assign them to the corresponding API users. Each endpoint
106+
declares which groups may call it.
107+
108+
Code Snippets
109+
-------------
110+
111+
As an alternative to a model method, a code snippet can be used for
112+
quick, ad-hoc logic. Available variables:
113+
114+
- ``Model``: The target model (with ``sudo()``).
115+
- ``params``: Validated parameters from the request.
116+
- ``env``: The Odoo environment.
117+
- ``Command``: Odoo's ``Command`` helper for relational field writes.
118+
- ``json``: Safe JSON module for serialization.
119+
- ``exceptions``: Werkzeug exceptions (``BadRequest``, ``NotFound``,
120+
etc.).
121+
- ``log``: Log messages to the ``ir.logging`` table.
122+
123+
The snippet must set a ``result`` variable with the response data.
124+
125+
Usage
126+
=====
127+
128+
Calling an Endpoint
129+
-------------------
130+
131+
Send a POST request with a JSON body to the endpoint's route. The
132+
example below uses Bearer authentication with an API key:
133+
134+
.. code:: bash
135+
136+
curl -X POST https://your-odoo.com/json2/contacts/get_partners \
137+
-H "Content-Type: application/json" \
138+
-H "Authorization: Bearer YOUR_API_KEY" \
139+
-d '{"domain": [["is_company", "=", true]], "limit": 10}'
140+
141+
API Documentation
142+
-----------------
143+
144+
Auto-generated documentation for all JSON-2 endpoints is available at
145+
``/json2/doc``, grouped by route group. Each endpoint's visibility
146+
respects the **Allowed Groups** setting — users only see endpoints they
147+
have access to. Filter by route group with ``/json2/doc/{route_group}``.
148+
149+
Bug Tracker
150+
===========
151+
152+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/web-api/issues>`_.
153+
In case of trouble, please check there if your issue has already been reported.
154+
If you spotted it first, help us to smash it by providing a detailed and welcomed
155+
`feedback <https://github.com/OCA/web-api/issues/new?body=module:%20endpoint_json2%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
156+
157+
Do not contact contributors directly about support or help with technical issues.
158+
159+
Credits
160+
=======
161+
162+
Authors
163+
-------
164+
165+
* Quartile
166+
167+
Contributors
168+
------------
169+
170+
- Quartile <https://www.quartile.co>
171+
172+
- Yoshi Tashiro
173+
174+
Maintainers
175+
-----------
176+
177+
This module is maintained by the OCA.
178+
179+
.. image:: https://odoo-community.org/logo.png
180+
:alt: Odoo Community Association
181+
:target: https://odoo-community.org
182+
183+
OCA, or the Odoo Community Association, is a nonprofit organization whose
184+
mission is to support the collaborative development of Odoo features and
185+
promote its widespread use.
186+
187+
.. |maintainer-yostashiro| image:: https://github.com/yostashiro.png?size=40px
188+
:target: https://github.com/yostashiro
189+
:alt: yostashiro
190+
.. |maintainer-aungkokolin1997| image:: https://github.com/aungkokolin1997.png?size=40px
191+
:target: https://github.com/aungkokolin1997
192+
:alt: aungkokolin1997
193+
194+
Current `maintainers <https://odoo-community.org/page/maintainer-role>`__:
195+
196+
|maintainer-yostashiro| |maintainer-aungkokolin1997|
197+
198+
This module is part of the `OCA/web-api <https://github.com/OCA/web-api/tree/19.0/endpoint_json2>`_ project on GitHub.
199+
200+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

endpoint_json2/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from . import controllers
2+
from . import models

endpoint_json2/__manifest__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright 2026 Quartile (https://www.quartile.co)
2+
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
3+
{
4+
"name": "Endpoint JSON2",
5+
"summary": "Declarative JSON-2 API endpoints on the endpoint stack",
6+
"version": "19.0.1.0.0",
7+
"license": "LGPL-3",
8+
"development_status": "Alpha",
9+
"author": "Quartile, Odoo Community Association (OCA)",
10+
"website": "https://github.com/OCA/web-api",
11+
"category": "Technical",
12+
"depends": ["endpoint"],
13+
"data": [
14+
"security/ir.model.access.csv",
15+
"views/endpoint_views.xml",
16+
],
17+
"demo": ["demo/endpoint_json2_demo.xml"],
18+
"installable": True,
19+
"maintainers": ["yostashiro", "aungkokolin1997"],
20+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import main

endpoint_json2/controllers/main.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright 2026 Quartile (https://www.quartile.co)
2+
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
3+
4+
from werkzeug.exceptions import NotFound
5+
6+
from odoo import http
7+
from odoo.http import request
8+
9+
10+
class EndpointJson2DocController(http.Controller):
11+
def _get_accessible_endpoints(self, extra_domain=None):
12+
domain = [("exec_mode", "=", "json2")] + (extra_domain or [])
13+
all_endpoints = request.env["endpoint.endpoint"].sudo().search(domain)
14+
user = request.env.user
15+
return all_endpoints.filtered(
16+
lambda ep: ep.json2_group_ids & user.all_group_ids
17+
)
18+
19+
def _endpoint_to_doc(self, endpoint):
20+
return {
21+
"name": endpoint.name,
22+
"description": endpoint.json2_description or "",
23+
"method": endpoint.json2_method,
24+
"model": endpoint.json2_model_name,
25+
"url": endpoint.route,
26+
"parameters": [
27+
{
28+
"name": p.name,
29+
"type": p.param_type,
30+
"required": p.required,
31+
"description": p.description or "",
32+
"default": p.default_value,
33+
}
34+
for p in endpoint.json2_param_ids
35+
],
36+
}
37+
38+
@http.route(
39+
"/json2/doc",
40+
methods=["GET"],
41+
auth="user",
42+
type="http",
43+
readonly=True,
44+
save_session=False,
45+
)
46+
def doc_index(self):
47+
endpoints = self._get_accessible_endpoints()
48+
result = {}
49+
for ep in endpoints:
50+
result.setdefault(ep.route_group, []).append(self._endpoint_to_doc(ep))
51+
return request.make_json_response(result)
52+
53+
@http.route(
54+
"/json2/doc/<string:route_group>",
55+
methods=["GET"],
56+
auth="user",
57+
type="http",
58+
readonly=True,
59+
save_session=False,
60+
)
61+
def doc_domain(self, route_group):
62+
endpoints = self._get_accessible_endpoints([("route_group", "=", route_group)])
63+
if not endpoints:
64+
raise NotFound(f"No endpoints found for domain {route_group!r}")
65+
return request.make_json_response(
66+
[self._endpoint_to_doc(ep) for ep in endpoints]
67+
)

0 commit comments

Comments
 (0)