mirror of
https://github.com/bringout/oca-technical.git
synced 2026-04-18 09:52:02 +02:00
Initial commit: OCA Technical packages (595 packages)
This commit is contained in:
commit
2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions
422
odoo-bringout-oca-rest-framework-base_rest/base_rest/README.rst
Normal file
422
odoo-bringout-oca-rest-framework-base_rest/base_rest/README.rst
Normal file
|
|
@ -0,0 +1,422 @@
|
|||
=========
|
||||
Base Rest
|
||||
=========
|
||||
|
||||
..
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:517d5b1d74542047b404d2130e5d9239fe591f43b1a89ca02339766c8c8a6584
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
||||
:target: https://odoo-community.org/page/development-status
|
||||
:alt: Beta
|
||||
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
|
||||
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
|
||||
:alt: License: LGPL-3
|
||||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Frest--framework-lightgray.png?logo=github
|
||||
:target: https://github.com/OCA/rest-framework/tree/16.0/base_rest
|
||||
:alt: OCA/rest-framework
|
||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
||||
:target: https://translation.odoo-community.org/projects/rest-framework-16-0/rest-framework-16-0-base_rest
|
||||
:alt: Translate me on Weblate
|
||||
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
|
||||
:target: https://runboat.odoo-community.org/builds?repo=OCA/rest-framework&target_branch=16.0
|
||||
:alt: Try me on Runboat
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
This addon is deprecated and not fully supported anymore on Odoo 16.
|
||||
Please migrate to the FastAPI migration module.
|
||||
See https://github.com/OCA/rest-framework/pull/291.
|
||||
|
||||
This addon provides the basis to develop high level REST APIs for Odoo.
|
||||
|
||||
As Odoo becomes one of the central pieces of enterprise IT systems, it often
|
||||
becomes necessary to set up specialized service interfaces, so existing
|
||||
systems can interact with Odoo.
|
||||
|
||||
While the XML-RPC interface of Odoo comes handy in such situations, it
|
||||
requires a deep understanding of Odoo’s internal data model. When used
|
||||
extensively, it creates a strong coupling between Odoo internals and client
|
||||
systems, therefore increasing maintenance costs.
|
||||
|
||||
Once developed, an `OpenApi <https://spec.openapis.org/oas/v3.0.3>`_ documentation
|
||||
is generated from the source code and available via a
|
||||
`Swagger UI <https://swagger.io/tools/swagger-ui/>`_ served by your odoo server
|
||||
at `https://my_odoo_server/api-docs`.
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
If an error occurs when calling a method of a service (ie missing parameter,
|
||||
..) the system returns only a general description of the problem without
|
||||
details. This is done on purpose to ensure maximum opacity on implementation
|
||||
details and therefore lower security issue.
|
||||
|
||||
This restriction can be problematic when the services are accessed by an
|
||||
external system in development. To know the details of an error it is indeed
|
||||
necessary to have access to the log of the server. It is not always possible
|
||||
to provide this kind of access. That's why you can configure the server to run
|
||||
these services in development mode.
|
||||
|
||||
To run the REST API in development mode you must add a new section
|
||||
'**[base_rest]**' with the option '**dev_mode=True**' in the server config
|
||||
file.
|
||||
|
||||
.. code-block:: cfg
|
||||
|
||||
[base_rest]
|
||||
dev_mode=True
|
||||
|
||||
When the REST API runs in development mode, the original description and a
|
||||
stack trace is returned in case of error. **Be careful to not use this mode
|
||||
in production**.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
To add your own REST service you must provides at least 2 classes.
|
||||
|
||||
* A Component providing the business logic of your service,
|
||||
* A Controller to register your service.
|
||||
|
||||
The business logic of your service must be implemented into a component
|
||||
(``odoo.addons.component.core.Component``) that inherit from
|
||||
'base.rest.service'
|
||||
|
||||
Initially, base_rest expose by default all public methods defined in a service.
|
||||
The conventions for accessing methods via HTTP were as follows:
|
||||
|
||||
* The method ``def get(self, _id)`` if defined, is accessible via HTTP GET routes ``<string:_service_name>/<int:_id>`` and ``<string:_service_name>/<int:_id>/get``.
|
||||
* The method ``def search(self, **params)`` if defined, is accessible via the HTTP GET routes ``<string:_service_name>/`` and ``<string:_service_name>/search``.
|
||||
* The method ``def delete(self, _id)`` if defined, is accessible via the HTTP DELETE route ``<string:_service_name>/<int:_id>``.
|
||||
* The ``def update(self, _id, **params)`` method, if defined, is accessible via the HTTP PUT route ``<string:_service_name>/<int:_id>``.
|
||||
* Other methods are only accessible via HTTP POST routes ``<string:_service_name>`` or ``<string:_service_name>/<string:method_name>`` or ``<string:_service_name>/<int:_id>`` or ``<string:_service_name>/<int:_id>/<string:method_name>``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from odoo.addons.component.core import Component
|
||||
|
||||
|
||||
class PingService(Component):
|
||||
_inherit = 'base.rest.service'
|
||||
_name = 'ping.service'
|
||||
_usage = 'ping'
|
||||
_collection = 'my_module.services'
|
||||
|
||||
|
||||
# The following method are 'public' and can be called from the controller.
|
||||
def get(self, _id, message):
|
||||
return {
|
||||
'response': 'Get called with message ' + message}
|
||||
|
||||
def search(self, message):
|
||||
return {
|
||||
'response': 'Search called search with message ' + message}
|
||||
|
||||
def update(self, _id, message):
|
||||
return {'response': 'PUT called with message ' + message}
|
||||
|
||||
# pylint:disable=method-required-super
|
||||
def create(self, **params):
|
||||
return {'response': 'POST called with message ' + params['message']}
|
||||
|
||||
def delete(self, _id):
|
||||
return {'response': 'DELETE called with id %s ' % _id}
|
||||
|
||||
# Validator
|
||||
def _validator_search(self):
|
||||
return {'message': {'type': 'string'}}
|
||||
|
||||
# Validator
|
||||
def _validator_get(self):
|
||||
# no parameters by default
|
||||
return {}
|
||||
|
||||
def _validator_update(self):
|
||||
return {'message': {'type': 'string'}}
|
||||
|
||||
def _validator_create(self):
|
||||
return {'message': {'type': 'string'}}
|
||||
|
||||
Once you have implemented your services (ping, ...), you must tell to Odoo
|
||||
how to access to these services. This process is done by implementing a
|
||||
controller that inherits from ``odoo.addons.base_rest.controllers.main.RestController``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from odoo.addons.base_rest.controllers import main
|
||||
|
||||
class MyRestController(main.RestController):
|
||||
_root_path = '/my_services_api/'
|
||||
_collection_name = my_module.services
|
||||
|
||||
In your controller, _'root_path' is used to specify the root of the path to
|
||||
access to your services and '_collection_name' is the name of the collection
|
||||
providing the business logic for the requested service/
|
||||
|
||||
|
||||
By inheriting from ``RestController`` the following routes will be registered
|
||||
to access to your services
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@route([
|
||||
ROOT_PATH + '<string:_service_name>',
|
||||
ROOT_PATH + '<string:_service_name>/search',
|
||||
ROOT_PATH + '<string:_service_name>/<int:_id>',
|
||||
ROOT_PATH + '<string:_service_name>/<int:_id>/get'
|
||||
], methods=['GET'], auth="user", csrf=False)
|
||||
def get(self, _service_name, _id=None, **params):
|
||||
method_name = 'get' if _id else 'search'
|
||||
return self._process_method(_service_name, method_name, _id, params)
|
||||
|
||||
@route([
|
||||
ROOT_PATH + '<string:_service_name>',
|
||||
ROOT_PATH + '<string:_service_name>/<string:method_name>',
|
||||
ROOT_PATH + '<string:_service_name>/<int:_id>',
|
||||
ROOT_PATH + '<string:_service_name>/<int:_id>/<string:method_name>'
|
||||
], methods=['POST'], auth="user", csrf=False)
|
||||
def modify(self, _service_name, _id=None, method_name=None, **params):
|
||||
if not method_name:
|
||||
method_name = 'update' if _id else 'create'
|
||||
if method_name == 'get':
|
||||
_logger.error("HTTP POST with method name 'get' is not allowed. "
|
||||
"(service name: %s)", _service_name)
|
||||
raise BadRequest()
|
||||
return self._process_method(_service_name, method_name, _id, params)
|
||||
|
||||
@route([
|
||||
ROOT_PATH + '<string:_service_name>/<int:_id>',
|
||||
], methods=['PUT'], auth="user", csrf=False)
|
||||
def update(self, _service_name, _id, **params):
|
||||
return self._process_method(_service_name, 'update', _id, params)
|
||||
|
||||
@route([
|
||||
ROOT_PATH + '<string:_service_name>/<int:_id>',
|
||||
], methods=['DELETE'], auth="user", csrf=False)
|
||||
def delete(self, _service_name, _id):
|
||||
return self._process_method(_service_name, 'delete', _id)
|
||||
|
||||
|
||||
As result an HTTP GET call to 'http://my_odoo/my_services_api/ping' will be
|
||||
dispatched to the method ``PingService.search``
|
||||
|
||||
In addition to easily exposing your methods, the module allows you to define
|
||||
data schemas to which the exchanged data must conform. These schemas are defined
|
||||
on the basis of `Cerberus schemas <https://docs.python-cerberus.org/en/stable/>`_
|
||||
and associated to the methods using the
|
||||
following naming convention. For a method `my_method`:
|
||||
|
||||
* ``def _validator_my_method(self):`` will be called to get the schema required to
|
||||
validate the input parameters.
|
||||
* ``def _validator_return_my_method(self):`` if defined, will be called to get
|
||||
the schema used to validate the response.
|
||||
|
||||
In order to offer even more flexibility, a new API has been developed.
|
||||
|
||||
This new API replaces the implicit approach used to expose a service by the use
|
||||
of a python decorator to explicitly mark a method as being available via the
|
||||
REST API: ``odoo.addons.base_rest.restapi.method``.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class PartnerNewApiService(Component):
|
||||
_inherit = "base.rest.service"
|
||||
_name = "partner.new_api.service"
|
||||
_usage = "partner"
|
||||
_collection = "base.rest.demo.new_api.services"
|
||||
_description = """
|
||||
Partner New API Services
|
||||
Services developed with the new api provided by base_rest
|
||||
"""
|
||||
|
||||
@restapi.method(
|
||||
[(["/<int:id>/get", "/<int:id>"], "GET")],
|
||||
output_param=restapi.CerberusValidator("_get_partner_schema"),
|
||||
auth="public",
|
||||
)
|
||||
def get(self, _id):
|
||||
return {"name": self.env["res.partner"].browse(_id).name}
|
||||
|
||||
def _get_partner_schema(self):
|
||||
return {
|
||||
"name": {"type": "string", "required": True}
|
||||
}
|
||||
|
||||
@restapi.method(
|
||||
[(["/list", "/"], "GET")],
|
||||
output_param=restapi.CerberusListValidator("_get_partner_schema"),
|
||||
auth="public",
|
||||
)
|
||||
def list(self):
|
||||
partners = self.env["res.partner"].search([])
|
||||
return [{"name": p.name} for p in partners]
|
||||
|
||||
Thanks to this new api, you are now free to specify your own routes but also
|
||||
to use other object types as parameter or response to your methods.
|
||||
For example, `base_rest_datamodel` allows you to use Datamodel object instance
|
||||
into your services.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from marshmallow import fields
|
||||
|
||||
from odoo.addons.base_rest import restapi
|
||||
from odoo.addons.component.core import Component
|
||||
from odoo.addons.datamodel.core import Datamodel
|
||||
|
||||
|
||||
class PartnerSearchParam(Datamodel):
|
||||
_name = "partner.search.param"
|
||||
|
||||
id = fields.Integer(required=False, allow_none=False)
|
||||
name = fields.String(required=False, allow_none=False)
|
||||
|
||||
|
||||
class PartnerShortInfo(Datamodel):
|
||||
_name = "partner.short.info"
|
||||
|
||||
id = fields.Integer(required=True, allow_none=False)
|
||||
name = fields.String(required=True, allow_none=False)
|
||||
|
||||
|
||||
class PartnerNewApiService(Component):
|
||||
_inherit = "base.rest.service"
|
||||
_name = "partner.new_api.service"
|
||||
_usage = "partner"
|
||||
_collection = "base.rest.demo.new_api.services"
|
||||
_description = """
|
||||
Partner New API Services
|
||||
Services developed with the new api provided by base_rest
|
||||
"""
|
||||
|
||||
@restapi.method(
|
||||
[(["/", "/search"], "GET")],
|
||||
input_param=restapi.Datamodel("partner.search.param"),
|
||||
output_param=restapi.Datamodel("partner.short.info", is_list=True),
|
||||
auth="public",
|
||||
)
|
||||
def search(self, partner_search_param):
|
||||
"""
|
||||
Search for partners
|
||||
:param partner_search_param: An instance of partner.search.param
|
||||
:return: List of partner.short.info
|
||||
"""
|
||||
domain = []
|
||||
if partner_search_param.name:
|
||||
domain.append(("name", "like", partner_search_param.name))
|
||||
if partner_search_param.id:
|
||||
domain.append(("id", "=", partner_search_param.id))
|
||||
res = []
|
||||
PartnerShortInfo = self.env.datamodels["partner.short.info"]
|
||||
for p in self.env["res.partner"].search(domain):
|
||||
res.append(PartnerShortInfo(id=p.id, name=p.name))
|
||||
return res
|
||||
|
||||
The BaseRestServiceContextProvider provides context for your services,
|
||||
including authenticated_partner_id.
|
||||
You are free to redefine the method _get_authenticated_partner_id() to pass the
|
||||
authenticated_partner_id based on the authentication mechanism of your choice.
|
||||
See base_rest_auth_jwt for an example.
|
||||
|
||||
In addition, authenticated_partner_id is available in record rule evaluation context.
|
||||
|
||||
Known issues / Roadmap
|
||||
======================
|
||||
|
||||
The `roadmap <https://github.com/OCA/rest-framework/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement+label%3Abase_rest>`_
|
||||
and `known issues <https://github.com/OCA/rest-framework/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Abase_rest>`_ can
|
||||
be found on GitHub.
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
16.0.1.0.2 (2023-10-07)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
**Features**
|
||||
|
||||
- Add support for oauth2 security scheme in the Swagger UI. If your openapi
|
||||
specification contains a security scheme of type oauth2, the Swagger UI will
|
||||
display a login button in the top right corner. In order to finalize the
|
||||
login process, a redirect URL must be provided when initializing the Swagger
|
||||
UI. The Swagger UI is now initialized with a `oauth2RedirectUrl` option that
|
||||
references a oauth2-redirect.html file provided by the swagger-ui lib and served
|
||||
by the current addon. (`#379 <https://github.com/OCA/rest-framework/issues/379>`_)
|
||||
|
||||
|
||||
12.0.2.0.1
|
||||
~~~~~~~~~~
|
||||
|
||||
* _validator_...() methods can now return a cerberus ``Validator`` object
|
||||
instead of a schema dictionnary, for additional flexibility (e.g. allowing
|
||||
validator options such as ``allow_unknown``).
|
||||
|
||||
12.0.2.0.0
|
||||
~~~~~~~~~~
|
||||
|
||||
* Licence changed from AGPL-3 to LGPL-3
|
||||
|
||||
12.0.1.0.1
|
||||
~~~~~~~~~~
|
||||
|
||||
* Fix issue when rendering the jsonapi documentation if no documentation is
|
||||
provided on a method part of the REST api.
|
||||
|
||||
12.0.1.0.0
|
||||
~~~~~~~~~~
|
||||
|
||||
First official version. The addon has been incubated into the
|
||||
`Shopinvader repository <https://github.com/akretion/odoo-shopinvader>`_ from
|
||||
Akretion. For more information you need to look at the git log.
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/rest-framework/issues>`_.
|
||||
In case of trouble, please check there if your issue has already been reported.
|
||||
If you spotted it first, help us to smash it by providing a detailed and welcomed
|
||||
`feedback <https://github.com/OCA/rest-framework/issues/new?body=module:%20base_rest%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
||||
|
||||
Do not contact contributors directly about support or help with technical issues.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Authors
|
||||
~~~~~~~
|
||||
|
||||
* ACSONE SA/NV
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
* Laurent Mignon <laurent.mignon@acsone.eu>
|
||||
* Sébastien Beau <sebastien.beau@akretion.com>
|
||||
|
||||
Maintainers
|
||||
~~~~~~~~~~~
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.
|
||||
|
||||
This module is part of the `OCA/rest-framework <https://github.com/OCA/rest-framework/tree/16.0/base_rest>`_ project on GitHub.
|
||||
|
||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
||||
Loading…
Add table
Add a link
Reference in a new issue