15

I'm building an EmberJS app using ember-data.

Some of the functionality in my app requires quite complex queries.

As an example, let's say I have three entities - students, teachers and classes. If I wanted to get a list of all the students born before 1993 that are taking classes taught by teacher X, how can I do that with a RESTful api? In plain SQL it's easy enough, but I'm unsure of the best practice for implementing this into my API.

Do I need to build a custom endpoint alongside my basic REST api?

So I'd still have:

GET /students (which returns all the students)
GET /students/{id} (which returns a specific student)
etc

But then implement the following for my 'custom' query:

GET /students/custom/born_before/{date}/taught_by/{teacher_id}

Or is there a more standardized way of doing this?

Anonymous
  • 6,181
  • 7
  • 45
  • 72

2 Answers2

34

You can transform your

GET /students/custom/born_before/{date}/taught_by/{teacher_id}

into

GET /students/?born_before={date}&taught_by={teacher_id}

which is just a "query by example" option: you can populate a model instance with the provided fields and make a query using them. The less fields, the broader is the search and more results to show.

This is the way JIRA's API works, for example.

Pablo Lozano
  • 10,122
  • 2
  • 38
  • 59
  • 1
    This is a far more standard & more practically useful solution – James Billingham May 07 '14 at 08:35
  • 3
    And the result can be cached (contrary to the solution with `POST`). – Aurélien Bénel May 07 '14 at 09:19
  • @Aurélien It can be unfortunate as well, esp if you don't want caching. My only issue with this is, for complex queries and filters this is REALLY ugly to do. – Rahly Sep 23 '18 at 17:47
  • @Rahly First, you are not obliged to implement caching. Second, caching doesn't mean getting outdated data (`ETag` for example is a nice way to handle this). If implemented rightly, it just means that you don't have to compute again what you already computed. – Aurélien Bénel Sep 24 '18 at 06:55
  • @Aurélien no, thats the problem, someone else can implement caching, outside of you and your users control. I've seen in actual proxy environments where the proxy server ignores all caching headers and does their own "rules". POST is the usual non caching method – Rahly Sep 24 '18 at 18:47
  • How do you do huge IN clauses with this approach? – 212 Jun 19 '19 at 16:14
  • @212 See https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers – Pablo Lozano Sep 29 '22 at 15:50
10

One option is to have a search endpoint on your students that you can post to.

So you might have:

POST /students/filter

The filter object that you'd POST would look something like:

{ BornBefore:1993, TaughtBy:123 }

I've also seen an option where instead of posting that, the API had a filter, and then used a query string.

I prefer the first one myself. Especially if it can be a long running process, because your POST could return an ID and/or a rel link to the API call the client should use to get status updates and get the results.

So then you'd POST /Students/filter and it would respond back with rel of /Students/Filter/123 and your client would do periodic GET's on /Students/Filter/123 until it got the result object. Of course, for simple, short queries, you could just instantly return the result. But if it was going to take more than a second or two you could go this route.

This book by O'Reilly has some good information on structuring ReSTful APIs.

taylonr
  • 10,732
  • 5
  • 37
  • 66
  • 23
    I don't like using POST to "get" information, in my opinion that is not RESTful. – Pablo Lozano May 28 '13 at 15:45
  • 2
    I updated my answer, to show why you'd do a post in some cases. In essence you are POSTing a search object that the server runs, and then GETting the results later. Much like you would POST an image to the server and retrieve it later. – taylonr May 28 '13 at 15:47
  • That'd be more like `/students/filters` then - as there are many. Regardless, this is not an optimal solution for average use cases. Having to make two requests to do a simple search & storing it on the backend makes little sense. – James Billingham May 07 '14 at 08:34
  • My biggest problem with using GET is that proxy's will cache them using their OWN rules, despite any headers you may send. POST/PUT's are never cached. Although this is rare, its still a concern when dealing with users, esp in a business setting. – Rahly Sep 23 '18 at 17:25