25

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).

2 Answers 2

10

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.

Sign up to request clarification or add additional context in comments.

11 Comments

Hm, @asg, I'm not sure how it seems like payloads and responses are the same for each animal. In fact they are different--"You send and receive slightly different bodies depending on kind" and "Each kind of animal has unique attributes". I agree, if every kind of animal had the same payload and response (1) would be the obvious choice. The tricky thing here is that they are different.
hey @emft this is what you have mentioned in your question - #2 - 'The payloads and responses are the same for each endpoint'. If it is same, then why do you need a separate endpoint.. thats the point.
Ah, I see what you mean. What I mean is, if there were an endpoint for each animal, then each endpoint would receive and return consistent bodies within the endpoint. That is, /animals/antelopes would always have Body A, and /animals/birds would always have Body B, but Body A =/= Body B. I will edit to reflect this.
Okay.. got it. Question is - How much is the difference between Body A and Body B? How many attributes will be different? If those are not high, you can have an extra map containing key value pairs and these pairs are the values which are specific to that particular animal type. Again it depends on whether these extra attributes are manageable. If not , you may need to create a separate endpoint. But should be a last resort.
Interesting. Can you explain a little more what you mean by "an extra map"? Something like {'shared_animal_attribute_1': 'foo', ..., 'shared_animal_attribute_n': 'bar', 'extra_attributes': {'antelopiness': 10}} maybe?
|
7

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.

5 Comments

It's true that OAS allows this. However, there is no support for the feature to be displayed in Swagger UI (link), and I think a feature is of limited use if you can't show it to anyone.
@emft, not true. As of writing this answer, Swagger UI already supports that.
also the server code cannot handle oneOf schema. it becomes 'Object'.
OAS supports this but looks like code generators don't github.com/OpenAPITools/openapi-generator/issues/15
For Java, it has seemingly fixed by the OpenAPITools PR #5120 github.com/OpenAPITools/openapi-generator/pull/5120

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.