mirror of
https://github.com/bringout/oca-technical.git
synced 2026-04-18 17:31:59 +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
|
|
@ -0,0 +1,247 @@
|
|||
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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue