Go to Settings > Technical > WebService Backend (requires the
Administration / Settings group) and create a new backend:
- Name / Technical Name: a label and a unique technical key
you’ll use to look the backend up from code (e.g. env.ref is not
used here; search by tech_name instead).
- Protocol: only HTTP Request is available in this module.
- URL: the base URL every call is relative to, e.g.
https://api.example.com. It may contain {placeholder} tokens
(see Usage), e.g. https://api.example.com/{endpoint}.
- Content-Type: optional default Content-Type header for every
call.
- Timeout: optional timeout in seconds for the whole request
(connect + read). Left empty, a call waits indefinitely.
Under the Headers and Querystring Params tabs you can configure
static defaults, merged into every call (see Usage).
Then configure authentication via Auth Type:
- Public: no credentials needed.
- Username & password: sent as HTTP Basic Auth. Requires
Username and Password.
- API Key: sent as a custom header. Requires API Key and API
Key header (the header name to send it under, e.g. X-Api-Key).
Required fields depend on the selected auth type; the form only shows
and requires the ones that apply, and saving enforces it.
Each webservice.endpoint (see Description) has its own
Content-Type, Timeout, Headers and Querystring Params, overriding the
backend’s own for that specific endpoint - set only what needs to
differ.
Look up the backend (e.g. by its technical name) and call it:
backend = env["webservice.backend"].search([("tech_name", "=", "my_api")])
result = backend.call("get") # -> the full requests.Response object
call(method, *args, **kwargs) accepts any of the standard HTTP verbs
(get, post, put, delete) and forwards everything else to
requests, so any of its keyword
arguments work too (data, json, params, files, …):
backend.call("post", data=b"<xml>...</xml>")
backend.call("post", json={"foo": "bar"})
URL: by default the backend’s own url is used. Pass url to
hit a different path - relative paths are appended to the backend’s URL,
a full http(s):// URL is used as-is:
backend.call("get", url="orders") # -> <backend url>/orders
backend.call("get", url="https://other.example.com/orders")
If the backend’s URL (or the url passed above) contains
{placeholder} tokens, fill them with url_params:
# backend.url == "https://api.example.com/{endpoint}"
backend.call("get", url_params={"endpoint": "orders"})
Headers: pass headers to add/override headers for that call;
they are merged on top of the backend’s own static headers (configured
in the “Headers” tab), Content-Type and auth-derived headers (e.g.
the API key header) - the headers kwarg wins on matching keys:
backend.call("get", headers={"X-Request-Id": "42"})
Querystring params: sent via requests’ params=, not to be
confused with url_params above, which fills {placeholder} tokens
in the URL path itself. Configure static defaults in the “Querystring
Params” tab - a value there may itself contain a {placeholder},
resolved against the same url_params used for the URL. An explicit
params kwarg passed to call() wins over the static configuration
on matching keys:
backend.call("get", params={"verbose": "1"})
Auth override: pass auth to bypass the backend’s configured auth
type for a single call (same format requests itself accepts, e.g. a
(user, password) tuple):
backend.call("get", auth=("other_user", "other_password"))
Timeout: pass timeout to override the backend’s own configured
timeout (in seconds) for a single call:
backend.call("get", timeout=5)
Response: call() always returns the full requests.Response
object (status code, headers, content, …):
response = backend.call("get")
response.status_code
response.content