Calum
Calum

Reputation: 1889

RESTful Querystring in Resource URL

I'm in the process of making an API more RESTful. At the moment I have an endpoint like this:

/booking?bookingid=123

I have updated the endpoint to be more RESTful like this:

/bookings/123

A booking looks a bit like this:

{
   "bookingId":123,
   "people":[
      {
         "personId":0,
         "name":{
            "forename":"Jon",
            "surname":"Smith"
         }
      },
      {
         "personId":1,
         "name":{
            "forename":"Sarah",
            "surname":"Jones"
         }
      }
   ]
}

I want to only return a booking if the booking contains a particular surname and to return Not Found if the surname doesn't exist on the booking.

The way I am looking to implement this is by adding a query string:

/bookings/123?surname="Jones"

This would return the booking above as Sarah's surname is "Jones" the booking would also be returned with a query string surname with value "Smith".

The first problem I have with this is that if a property of surname were added to the booking object it looks like the query is against that and the other problem I have is that it's querying against a single entity and not a list, is this a RESTful approach and if not then what is a better approach?

Upvotes: 2

Views: 175

Answers (3)

crdesilva
crdesilva

Reputation: 53

When you access the resource directly by id (i.e. /booking/123/) afterwards querying might not be the best option. As you are specifying the UID of the resource [which you know surely exists] and expecting a "Not Found" are at odds.

I'd recommend making the query a bit more uniform and keep provision to add more and more parameters in a single url parameter.

/bookings?query="param1=value1 AND param2=value2"

In the above of course encoding the URL param will be the best choice, so it'll be

/bookings/123?query="param1%3Dvalue1%20AND%20param2%3Dvalue2"

Here param1 can be your Booking ID with value 123 and param2 can be surname with the value you need.

Now the issue is param2 (i.e. surname) is not a direct property of the resource so you'd want to consider using below as a more improved version.

/bookings?query="bookingId=123 AND people.surname=myname" // in your case people.name.surname

Also make note that you need both param1 and param2 above as if you just pass the 2nd param booking.people.name.surname someone can expect it'll return all the bookings with person's surname with the value.

Upvotes: 1

Vasiliy Faronov
Vasiliy Faronov

Reputation: 12310

There is no definition of “RESTful” that the community agrees upon.

The closest thing to the definition of “RESTful” is Architectural Styles and the Design of Network-based Software Architectures by Roy T. Fielding, the dissertation that introduced the term “REST”. This dissertation has not a single word on how “RESTful” URLs should be structured. Instead, the idea is that the server chooses whichever URLs are convenient for it, then explicitly communicates them to the client in hypermedia links. In this kind of “RESTful” system, /booking?bookingid=123 is a perfectly good URL, as is /_content/AcmeWebApi.dll?ENDPOINT=booking&ID=123&tc=y.

However, after this dissertation (and the term “REST” with it) achieved widespread recognition, the community quickly drifted away from this idea of “REST” to a range of other, conflicting ideas of what is or is not “REST”, to the great dismay of Roy T. Fielding.

Therefore, your question cannot be usefully answered.

Consider if “RESTfulness” is really the property you’re trying to optimize for, or if you’re after some other properties, which could be, for example:

  • ease of understanding by a client implementer
  • interoperability with deployed components like HTTP caches
  • the server’s freedom to change URLs in the future
  • being like company X’s API

and each of which might call for a different URL design.

Upvotes: 3

Eric Stein
Eric Stein

Reputation: 13672

It's not typical to filter out a single resource using a query parameter, but it conforms to the spec. You might prefer your filter name to be ?person-surname= to leave yourself flexibility later. You might also consider whether it makes more sense to filter the collection (/bookings?person-surname=) and return all the matching bookings.

Upvotes: 1

Related Questions