1

Context

Hi, in my job we are trying to modify an API endpoint (/resources) to make special queries to it. A resource has a location (long/lat) and we want to make queries based on that location. We want to support mainly two different filters:

  • Filter by lat/long (already done): GET /resources?lat=0&long=0 returns a list of resource with that location.
  • Filter by a polygon (currently designing): a polygon is a very long sequence of points and we want to return those resources that are included in that polygon.

Both filters return an array of resources but with different representations.

Problems

The new filter has three main problems:

  1. Due to the length of the polygon (represented by and array or vertices) we cannot use a query parameter.
  2. This filter is quite time consuming in our backend, so we need to implement it in an asynchronous way.
  3. Both endpoints return different representations of each resource (both return an array of resource but in a different format).

Solution first problem

We are going to use the body of the request instead of a query parameter. So we call the endpoint like:

GET /resources

Body:
{
    "vertices": [ ... very long list of lat/long values ... ]
}

We think this solution is the only available.

Solution second problem

We are going to use jobs. By that I mean the following:

GET /resources -> returns a job_id -> once it's finished the frontend gets notified -> frontend calls a new endpoint GET /resources?job_id=<job_id>

We see some drawbacks in this design:

  1. To differentiate the type of filter, we need to check the parameters: if lat, long and zoom are included, then it's the first filter. If the body is not empty and contains a list of vertices (the polygon), then is the second one. We think this is a bad approach and it's not "very restful".

Solution thrid problem

As stated in the third problem, we are returning different representations but we do not specify that anywhere. To fix that, we have thought of using the Content Type header and create our own types, like application/json;<our_type>, but we are not sure about this solution either.

How do you think we should solve these problems? Can you give us some guidelines or resources to try to improve the solution?

2 Answers 2

1
GET /resources

Body:
{
    "vertices": [ ... very long list of lat/long values ... ]
}

Bad idea. See RFC-7231

A payload within a GET request message has no defined semantics

What this really means: if somebody is using standard, general-purpose components to interact with your API, and something expensive happens, it's your fault.

It is okay to use POST

POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.” -- Roy Fielding, 2009


POST /resources -> returns a job_id -> once it's finished the frontend gets notified -> frontend calls a new endpoint GET /resources?job_id=<job_id>

That's the right basic idea (notice that I changed the method of the first request). Think about how it would look with web pages; we would submit a form (POST), and get back a document that would tell us that our form submission was accepted, the job is in process, here's a link to use to check if the job is done, here's the link where the results will appear.

The main difference here is that, in REST, the server would usually provide the URI to use, rather than just giving you information to build your own URI.


To fix that, we have thought of using the Content Type header and create our own types, like application/json;<our_type>, but we are not sure about this solution either.

That's a GREAT answer. See RFC 6838.

My interpretation is that you probably want to use vendor/vanity tree subtypes, rather than parameters

application/vnd.company-name.v1+json
application/vnd.company-name.v2+json

You'll find lots of spelling examples in the IANA media-type registry.

1
0

I think @VoiceOfUnreason has provided great suggestions for your problems and solutions. But, let me tell you that you can use WebSocket for the search part which is more efficient, and I should tell you that it's not hard to use it.

Read More Here - Python Sample/Tutorial

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.