Using POST instead of GET for retrieving a resource

Hi there,

I’m working on an API and now I’m adding an endpoint that acts as a proxy.

The idea is to have an integration set (which can be to any of the 3rd parties we support), with the client only having to pass a code string as the single endpoint argument.

Currently, the endpoint looks like this:

GET /v1/foobar/{id}/scan=code=<vendor code>

The code format gets validated (according to the integration set) and the appropriate 3rd party service is hit, returning an existing standardised resource (i.e. HTTP 200).

This mostly works, but there are two things I would like to avoid:

  • depending on the 3rd party, clients might have to URL encode certain strings to be URL safe;
  • we sometimes deal with long values (think a vCard + URL encoding);

Using POST instead of GET would prevent the client from having to worry about encoding values and data size, since data would be sent in the body, rather than as a URL parameter.

However, we’re not actually creating a resource, just retrieving an existing one.

Regarding resource retrieval, the spec says:

Data, including resources and relationships, can be fetched by sending a GET request to an endpoint.

Since it doesn’t say MUST, would using POST be valid according to the spec?

As for the payload, how would it look like, since we’re not actually creating a resource?

Would this be a case for meta?

{
  "meta": {
    "code": "P)HcHXk3IQd?$%?bz/JpbfQ9#i:CEN"
  }
}

How would we go about this, in order to keep it JSON:API compliant?

Thanks,
Q

As I understand it, you need the body to carry a complex query to find a resource (or resource collection) that cannot fit in the URL.

I think just responding directly to the POST with the GET response could be misleading, but …

A simple and easy to understand approach is to create a resource which is a soft link to the underlying resource - where the POST says “create me a resource which is a simple link to the result of this query”.

  • This soft link could be time-limited or permanent according to use case.
  • The POST could return the result as well as the temporary URL location, because it is telling you what you will get if you GET at that URL.
  • Do you even need the soft-link to be created if the query sets are rarely if ever repeated? I’d say nominally yes if you want to follow the REST principles, but since there is no need for the soft-link to remain any amount of time, I guess you don’t have to, it could be a URL structure (e.g. https://example.org/alwaysgone/{id}) that always just replies “410 GONE” . But think carefully about how exotic your interface is becoming.

Another approach would be to redirect with a 303 to the URL if it is a single resource - either temporarily created for purpose, or a permanent URL. I think this is accetpable but more complex. Also, a word of caution, take care with 303. While I think in this case you would be fine. In the asynch processing case (see jsonapi.org example), we couldn’t use it because we needed the redirect URL to provide a large download (application/octet-stream) streamed to disk which required different handling in the client than the 200 request status response (application/vnd.api+json) it got while polling.

Finally I would take care over any access control complexity you may be creating

Hi @PeaDubYa,

Thanks for your reply and suggestions. I ended up keeping the original GET endpoint, though.

Initially, I was thinking about a POST request, mainly to avoid URL encoding and to accommodate (potential) large strings, but the data we work with is within the limits of clients and HTTP servers, so that’s fine.

Clients just have to make sure the code sent in the query string is URL safe.

Cheers,
Q

1 Like