You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Drupal Subrequests module allows multiple, dependent or independent requests to be defined in a "blueprint". The blueprint is sent to the server in a single POST (or query string encoded GET request) to /subrequests, where the server performs each request and returns a single multipart/related response containing the result of each individual sub-request.
This enables more complex API operations to be completed in a single step. For example, creating a new asset and immediately creating a movement log to locate the asset. Subrequests would also help API users with creating Logs that have multiple quantities. This works by allowing response values in later requests via JSON Paths.
Implementation Details
Adding support for Subrequests to the client is nearly as easy as creating a new client.subrequests namesapce with a send(blueprint) method. Users can be responsible for building a valid Subrequests blueprint.
Each request in the blueprint only requires an action and url property. But in general, most subrequests to a farmOS server will require an Authorization header to be set as well (an additional permission is required for users to use the /subrequests endpoint). For DX, the farmOS client libraries could auto-fill the Authorization header of each individual request, unless one is already provided. Similarly, the base URL shouldn't need to be provided. The farmOS client could auto-fill this as value as well.
The body property that is need for sub-requests sending data, such as create or update actions, needs to be a serialized JSON string. This is something the client could handle as well.
By default Subrequests returns an HTML multipart/related response which is fairly complicated to parse (see https://www.drupal.org/project/subrequests/issues/3194286). BUT subrequests can also return a JSON response with the result of each sub-request keyed by requestId. To do this, the JSON format must be requested by adding the ?_format=json query parameter. I don't see a reason that users would want the HTML response, but we could support this by adding a format parameter that defaults to json, eg; client.subrequests.send(blueprint, format='html').
A nice addition would be for the farmOS clients to provide some "helper" methods for building a Subrequests blueprint. I think the main pain points for developers will be:
Learning the syntax for building blueprints
getting the correct API URL endpoint (this is largely why we have client.log.get() anyways)
building correct body payloads that include correct JSON Path embeddings
Proposed resolution
Create a client.subrequests namespace with a client.subrequests.send(blueprint, format="json") method to submit blueprints to the server. Unless format="html" is specified, append the ?_format=json query parameter.
Auto-fill the Authorization header on each sub-request within the blueprint, unless the header is already set (allow NULL so that un-authenticated requests can be made). This is not necessary! Each sub-request is run in same session as the "master request".
Set the Accept and Content-Type headers to be application/vnd.api+json, unless the header is already set.
Introduce an api_endpoint or endpoint property for individual subrequests. If no url is provided, the endpoint will be appended to the base URL already configured on the client.
Check if the sub-request body is a string or an object. If an object is provided, serialize it as a JSON string.
Re: painpoints:
1: Create Pydantic models that represent the Subrequest blueprint schema. These can be used in an objec-oriented way to both create, convert, validate, type-check and serialize the Subrequests blueprint.
2: Extra: consider creating client.resource.endpoint(type, bundle, id=None, params=None) and client.log.endpoint(bundle, id=None, params=None) methods for building correct API endpoints that include IDs and query parameters.
3: Extra: create helper methods for common tasks eg: client.subrequests.createLog(references = []) (tbd...)
The text was updated successfully, but these errors were encountered:
One clarification: Authorization headers are not needed for each individual sub-request. They are run in the same session as the initial request that is sent to /subrequests
2: Extra: consider creating client.resource.endpoint(type, bundle, id=None, params=None) and client.log.endpoint(bundle, id=None, params=None) methods for building correct API endpoints that include IDs and query parameters.
3: Extra: create helper methods for common tasks eg: client.subrequests.createLog(references = []) (tbd...)
I think these would be nice features but lets wait to add these until later on as use cases further develop.
Why
The Drupal Subrequests module allows multiple, dependent or independent requests to be defined in a "blueprint". The blueprint is sent to the server in a single POST (or query string encoded GET request) to
/subrequests
, where the server performs each request and returns a singlemultipart/related
response containing the result of each individual sub-request.This enables more complex API operations to be completed in a single step. For example, creating a new asset and immediately creating a movement log to locate the asset. Subrequests would also help API users with creating Logs that have multiple quantities. This works by allowing response values in later requests via JSON Paths.
Implementation Details
Adding support for Subrequests to the client is nearly as easy as creating a new
client.subrequests
namesapce with asend(blueprint)
method. Users can be responsible for building a valid Subrequests blueprint.Each request in the blueprint only requires an
action
andurl
property.But in general, most subrequests to a farmOS server will require an(an additional permission is required for users to use theAuthorization
header to be set as well/subrequests
endpoint).For DX, the farmOS client libraries could auto-fill theSimilarly, the base URL shouldn't need to be provided. The farmOS client could auto-fill this as value as well.Authorization
header of each individual request, unless one is already provided.The
body
property that is need for sub-requests sending data, such ascreate
orupdate
actions, needs to be a serialized JSON string. This is something the client could handle as well.By default Subrequests returns an HTML
multipart/related
response which is fairly complicated to parse (see https://www.drupal.org/project/subrequests/issues/3194286). BUT subrequests can also return a JSON response with the result of each sub-request keyed byrequestId
. To do this, the JSON format must be requested by adding the?_format=json
query parameter. I don't see a reason that users would want the HTML response, but we could support this by adding aformat
parameter that defaults tojson
, eg;client.subrequests.send(blueprint, format='html')
.A nice addition would be for the farmOS clients to provide some "helper" methods for building a Subrequests blueprint. I think the main pain points for developers will be:
client.log.get()
anyways)Proposed resolution
client.subrequests
namespace with aclient.subrequests.send(blueprint, format="json")
method to submit blueprints to the server. Unlessformat="html"
is specified, append the?_format=json
query parameter.Auto-fill theThis is not necessary! Each sub-request is run in same session as the "master request".Authorization
header on each sub-request within the blueprint, unless the header is already set (allow NULL so that un-authenticated requests can be made).Accept
andContent-Type
headers to beapplication/vnd.api+json
, unless the header is already set.api_endpoint
orendpoint
property for individual subrequests. If nourl
is provided, theendpoint
will be appended to the base URL already configured on the client.body
is a string or an object. If an object is provided, serialize it as a JSON string.client.resource.endpoint(type, bundle, id=None, params=None)
andclient.log.endpoint(bundle, id=None, params=None)
methods for building correct API endpoints that include IDs and query parameters.client.subrequests.createLog(references = [])
(tbd...)The text was updated successfully, but these errors were encountered: