3

Is it better REST API design to use conditionally required fields or to create different resources based on the controlling field's value? Here's an example:

POST route/automobile

{
"type": "car", //This field controls validation rules
"bedLength": 6, //required if type == "truck"
"trunkVolume": 10 //required if type == "car"
}

or

POST route/automobile/truck

{
"bedLength": 6 //required 
}

POST route/automobile/car

{
"trunkVolume": 10 //required 
}

I personally lean toward the second design where fields are independently validated. I think the api is cleaner. But I'm getting some argument from coworkers. I'd like to hear some thoughts from others. Also, I'd like to restrict this to the discussion to the design of the service endpoints, independent of how the data is represented in the domain and data layers.

  • This question is unclear to me, and I don't know what those examples are. Are those the payload to a POST when updating a resource? Or something related to data retrieval? In what way are A and B "different" resources? Or are they really the same resource but a different representation? As written it's difficult to understand your question. – John Wu Jun 5 '18 at 15:42
  • I added the http method to clarify. Regarding whether they are different resources, this is the question. Should they be different resources? – Yuli Bonner Jun 5 '18 at 15:44
  • 1
    I think you need to explain a little more about what you mean by 'controlling value'. It seems the primary question here is whether route/a and route/b should be two different resources. Whether you need conditional fields should follow from that. The example is so abstract it's hard to understand your goal. Can you come up with something a little more concrete? – JimmyJames Jun 5 '18 at 15:52
  • This will be a much more meaningful question if you provide an example rather than using the generic format you currently have. An actual real-world use case. – Paul Jun 5 '18 at 15:59
  • 1
    If you modify this with the cars/trucks and bed size example, it would be much easier to understand. – JimmyJames Jun 5 '18 at 17:23
2

You're speaking of resources. I assume your endpoints are creating some kind of records in a database, let's call it car. If we're — in both cases — are talking about the same resource with different attributes, then go with one endpoint and properly document the behaviour.

If it's in contrast two different things (in your domain), e.g. a car and a banana two endpoints make sense.

  • Yeah, it would be easy if it were car v. banana, but it's automobile vs. car and truck. The question is should "bed size" be conditionally required on an auto endpoint or should there be separate car and truck endpoints. – Yuli Bonner Jun 5 '18 at 17:14
  • What's the representation inside your data store? Is it one table? – Philipp Frank Jun 5 '18 at 17:15
  • 1
    How it's stored in data source isn't relevant. There're two layers of abstraction before we get there. – Yuli Bonner Jun 5 '18 at 17:16
  • Well, it sure is. You're asking for opinions. If the data is physically separated (for example across several tables or apis) it would justify your decision to give it separate endpoints. If you - on the other hand - have something like a generic table "vehicle" with a type column, that would justify the one-endpoint solution. – Philipp Frank Jun 5 '18 at 17:20
  • 2
    We'll have to agree to disagree on this one. I'm not asking about full stack design, which should be appropriately decoupled. Designing your service endpoints around the structure of your persisted data is tight coupling. – Yuli Bonner Jun 5 '18 at 17:26
2

I don't think either approach is inherently better than the other. To get to a reasonable decision, I would personally start looking at it from the user perspective. Specifically: are trucks different from cars from the perspective of the user of the API? I assume that we are talking about passenger vehicles in both cases.

There are a lot of things that are similar about trucks and cars. Where do SUVs fit in? Some are built on car frames, some on truck frames. Not all cars have trunks. Some have a 'frunk' in addition to a trunk. On the other hand, there are many differences about trucks and cars. For example, in the US, trucks are subject to different fuel efficiency standards.

One benefit of separating them is that you can easily clarify the differences. The downside is that if the user is going to be treating them as roughly similar, you've greatly complicated things for them. So if I am using this API to search for vehicles I might buy as a consumer, I'm probably in the market for either a car or a truck, not both. But if I am using this as a dealer who just needs to restock my lot, you may be complicating my job by separating them.

0

I think your first option is the cleaner and more intuitive for this example: Car and Truck both derive from Vehicle (or Automobile) and have a lot of commonality, eg wheels, color, number of seats, etc.

I've just come across a similar scenario where a POST call adds a Constituent (you can think of it as a Legal Entity if you want) which can be either an Individual or an Organization.

The back end database expects an Individual to have at least a Last Name but an Organization to have at least a Name. (Name for an Individual is a computed field from First Name and Last Name but don't worry about that). The (required) Type field determines which one I am POSTing.

So if I POST a new Individual Constituent I must specify the Type as Individual and I would expect an error if I don't also provide a Last Name. Similarly, if I POST a new Organization Constituent I must specify the Type as Organization and I would expect an error if I don't also provide a Name.

The API I'm currently dealing with doesn't throw errors if Last Name or Type is empty or omitted; the data fields are simply left blank in the database, which I find strange and non-conformant to the rest of the design rules.

Why the error can’t be simply thrown in the response eludes me.

Yes, I understand that one could simply provide two endpoints – POST Individual and POST Organization – but the database has very many common fields and their commonality overall is far greater than there difference, so, like a tightly derived class, it does make sense to me to use the same endpoint.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.