RESTful Interface – How Do Searches Fit In?

api-designdesignhttp-requestrest

When designing a RESTful interface, the semantics of the request types are deemed vital to the design.

  • GET – List collection or retrieve element
  • PUT – Replace collection or element
  • POST – Create collection or element
  • DELETE – Well, erm, delete collection or element

However, this doesn't seem to cover the concept of "search".

E.g. in designing a suite of web services that support a Job Search site you might have the following requirements:

  • Get individual Job Advert
    • GET to domain/Job/{id}/
  • Create Job Advert
    • POST to domain/Job/
  • Update Job Advert
    • PUT to domain/Job/
  • Delete Job Advert
    • DELETE to domain/Job/

"Get All Jobs" is also simple:

  • GET to domain/Jobs/

However, how does the job "search" fall into this structure?

You could claim it's a variation of "list collection" and implement as:

  • GET to domain/Jobs/

However, searches can be complex and it's entirely possible to produce a search that generates a long GET string. That is, referencing a SO question here, there are issues using GET strings longer than about 2000 characters.

An example might be in a faceted search – continuing the "job" example.

I may allow for searching on facets – "Technology", "Job Title", "Discipline" as well as free-text keywords, age of job, location and salary.

With a fluid user interface and a large number of technologies and job titles, it is feasible that a search could encompass a large number of facet choices.

Tweak this example to CVs, rather than jobs, bring in even more facets, and you can very easily imagine a search with a hundred facets selected, or even just 40 facets each of which are 50 characters long (e.g. Job Titles, University Names, Employer Names).

In that situation it might be desirable to move a PUT or POST in order to ensure that the search data will get correctly sent. E.g.:

  • POST to domain/Jobs/

But semantically that's an instruction to create a collection.

You could also say you'll express this as the creation of a search:

  • POST to domain/Jobs/Search/

or (as suggested by burninggramma below)

  • POST to domain/JobSearch/

Semantically it may seem to make sense, but you're not actually creating anything, you're making a request for data.

So, semantically it's a GET, but GET isn't guaranteed to support what you need.

So, the question is – Trying to keep as true to RESTful design as possible, whilst ensuring that I'm keeping within the limitations of HTTP, what is the most appropriate design for a search?

Best Answer

You should not forget that GET requests have some superior advantages over other solutions:

1) GET requests can be copied from the URL bar, they are digested by search engines, they are "friendly". Where "friendly" means that normally a GET request should not modify anything inside your application (idempotent). This is the standard case for a search.

2) All of these concepts are very important not just from user and search engine, but from an architectural, API design standpoint.

3) If you create a workaround with POST/PUT you will have problems which you are not thinking of right now. For example in case of a browser the navigate back button / refresh page / history. These can be solved of course, but that's going to be another workaround, then another and another ...

Considering all this my advice would be:

a) You should be able to fit inside your GET with using clever parameter structure. In extreme case you can even go for tactics like this google search where I set a lot of parameters still its a super short url.

b) Create another entity in your application like JobSearch. Assuming you got so much options, its probable that you will need to store these searches as well and manage them, so its just clearing up your application. You can work with the JobSearch objects as a whole entity, meaning you can test it / use it easier.


Personally I would try to fight with all my claws to get it done with a) and when all hope is lost, I would crawl back with tears in my eyes to option b).