We have recently encountered several use cases that
- need to POST some data to a service, and
- would like to store the response of this request at a compact GET-accessible location for future use.
Examples include:
- Graphs: POST from the extension or VisualEditor, GET from the rendered page
- Math: POST from the extension or VisualEditor, GET form the reference in the rendered page
We might be able to implement this generically:
- store the request as a JSON blob in a key-value bucket, using the sha-1 of the JSON
- store the response from the backend service in a different bucket, using the same hash
- return hash location (in Content-Location header?) and original response
- alternatively, redirect to GET location
To facilitate a clean separation between content types, it probably makes sense to use separate request / response buckets per service. By storing the request, we can re-render all requests when necessary.
For expiry, we could consider a lazy LRU scheme. In any case, the direct correspondence between request and response key should help with systematic cleanup of both components.
Other considerations:
- We might want to limit the sources of POST requests (only authenticated users, by IP) and public read access to the original requests.
Strawman config stanza
This is an example of how this could be implemented as an extension of the simple_service module we already have:
/{module:postservice}: x-modules: - name: simple_service type: file options: paths: /posttest/{hash}/png: get: # First, check storage for png. # If found, simply return & be done. storage: # result storage for pngs bucket_request: uri: /{domain}/sys/key_value/postservice.png item_request: uri: /{domain}/sys/key_value/postservice.png/{hash} # If png not found, load original post request # Return 404 if missing post_request_storage: item_request: uri: /{domain}/sys/key_value/postservice.post/{hash} # Then, send templated backend request. POST request data # object is available in `post_request`. # On success, store back via put to `storage.item_request` # and return to client. backend_request: method: post uri: http://some.post.service/png body: '{$.post_request.body}' /posttest/: post: # Store or verify presence of POST data. post_request_storage: bucket_request: uri: /{domain}/sys/key_value/postservice.post item_request: uri: /{domain}/sys/key_value/postservice.post/{$.post_request.hash} # What to do on success: response: status: 200 headers: content-location: '{$.post_request.hash}'
Main changes are:
- added post_request_storage stanza, with implicit storage / hashing behavior
- hash & possibly update if method is POST
- load into post_request variable if method is GET, before making backend request on storage miss
- added optional response template (possibly useful for general request templating)
- added ability to reference post_request.body in backend_request (see T86737)