Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to model a RESTful API with inheritance?

I have an object hierarchy I need to expose through a RESTful API and I'm not sure how my URLs should be structured and what they should return. I could not find any best practices.

Let's say I have Dogs and Cats inheriting from Animals. I need CRUD operations on dogs and cats; I also want to be able to do operations on animals in general.

My first idea was to do something like this:

GET /animals        # get all animals POST /animals       # create a dog or cat GET /animals/123    # get animal 123 

The thing is that the /animals collection is now "inconsistent", as it can return and take objects that do not have exactly the same structure (dogs and cats). Is it considered "RESTful" to have a collection returning objects that have differing attributes?

Another solution would be to create an URL for each concrete type, like this:

GET /dogs       # get all dogs POST /dogs      # create a dog GET /dogs/123   # get dog 123  GET /cats       # get all cats POST /cats      # create a cat GET /cats/123   # get cat 123 

But now the relationship between dogs and cats is lost. If one wishes to retrieve all animals, both the dog and cat resources must be queried. The number of URLs will also increase with each new animal subtype.

Another suggestion was to augment the second solution by adding this:

GET /animals    # get common attributes of all animals 

In this case, the animals returned would only contain attributes common to all animals, dropping dog-specific and cat-specific attributes. This allows to retrieve all animals, although with fewer details. Each returned object could contain a link to the detailed, concrete version.

Any comments or suggestions?

like image 293
Alpha Hydrae Avatar asked Jun 04 '12 11:06

Alpha Hydrae


People also ask

What is a polymorphic API?

Polymorphism in APIs allows resources to take on varying "types" to avoid duplicating shared functionality.


1 Answers

I would suggest:

  • Using only one URI per resource
  • Differentiating between animals solely at the attribute level

Setting up multiple URIs to the same resource is never a good idea because it can cause confusion and unexpected side effects. Given that, your single URI should be based on a generic scheme like /animals.

The next challenge of dealing with the entire collection of dogs and cats at the "base" level is already solved by virtue of the /animals URI approach.

The final challenge of dealing with specialized types like dogs and cats can be easily solved using a combination of query parameters and identification attributes within your media type. For example:

GET /animals (Accept : application/vnd.vet-services.animals+json)

{    "animals":[       {          "link":"/animals/3424",          "type":"dog",          "name":"Rex"       },       {          "link":"/animals/7829",          "type":"cat",          "name":"Mittens"       }    ] } 
  • GET /animals - gets all dogs and cats, would return both Rex and Mittens
  • GET /animals?type=dog - gets all dogs, would only return Rex
  • GET /animals?type=cat - gets all cats, would only Mittens

Then when creating or modifying animals, it would be incumbent on the caller to specify the type of animal involved:

Media Type: application/vnd.vet-services.animal+json

{    "type":"dog",    "name":"Fido" } 

The above payload could be sent with a POST or PUT request.

The above scheme gets you the basic similar characteristics as OO inheritance through REST, and with the ability to add further specializations (i.e. more animal types) without major surgery or any changes to your URI scheme.

like image 192
Brian Kelly Avatar answered Nov 09 '22 22:11

Brian Kelly