Inheritance and Polymorphism in REST API Modeling

11,513

Solution 1

I would go with option #1. Reason is: What if your list - Antelope, Bird, ..., Zebra is increased in future? You will end-up creating separate endpoints for every animal.

Assumption is that there are not much differences between payloads of /animals/antelopes and /animals/birds. If differences are more, then you will need to create separate endpoints for each payload.

If there are minor differences between payloads, I would suggest to add extra map containing key value pairs and these pairs are the values which are specific to that particular animal type.

As you have mentioned, extra map can be of type -

{
 'shared_animal_attribute_1': 'foo', 
 'shared_animal_attribute_n': 'bar', 
 'extra_attributes': 
     { 
         'antelopiness': 10
     }
}

You will need to extra processing logic of these attributes on the server side. This will reduce the pain of maintaining separate endpoints. If you have schema to validate, it's a hassle-free implementation.

Solution 2

OpenAPI 3.0 (former Swagger) comes with true support for polymorphism in JSON.

It's been possible to combine schemas using keywords such as oneOf, allOf, anyOf and get a message payload validated since JSON schema v1.0.

https://spacetelescope.github.io/understanding-json-schema/reference/combining.html

However, schemas composition in Swagger has been enhanced by the keywords discriminator (v2.0+) and oneOf (v3.0+) to support inheritance and polymorphism.

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaComposition

I have provided an example of a polymorphic POST method here.

Share:
11,513
emft
Author by

emft

Updated on June 05, 2022

Comments

  • emft
    emft almost 2 years

    I have an object hierarchy that I want to expose through a REST API, and I want to discuss best practices. I have seen this question asked before (e.g. here at the end, here, here, and especially here), but never really any conclusions arrived at.

    Suppose I have one base class, say Animal, and many different classes that inherit, say Antelope, Bird, ..., Zebra. Each kind of animal has unique attributes.

    Which is better?

    1. One endpoint path, /animals. You send and receive slightly different bodies depending on kind. There is a type field to help parse.
    2. A separate endpoint path for each kind of animal, /animals/antelopes, /animals/birds, ..., /animals/zebras. Each endpoint would always accept and return a consistent body (but these bodies would be different from each other).