8

Let's assume I have this API on /api/v2/persons that enables me to create new entries by POSTing this JSON:

{
  "name": "me"
}

The API is implemented using Spring Boot and if someone sends this JSON ...

{
  "name": "me",
  "age": 47
}

... Spring refuses to handle it because it can't map the additional value of age to the defined POJO. Because of this I was asked to change the API to simply ignore unsupported values like age. While this could be done rather easily I don't like the idea. In order to compare my personal opinion I searched and checked the API design book I own but didn't find an authoritative source that gives me some guidance which approach (ignore or reject) is better.

9
  • 3
    I am not aware of an authoritative source, but the downside to refusing to handle a request with extraneous fields is that adding or removing a field is always a breaking change to your API. If you accept extraneous field, your clients may preemptively add the fields to their requests until your API is ready to handle them, and your clients do not require an update if you decide you no longer need to handle a field. Oct 1, 2021 at 16:39
  • @VincentSavard Good point. But on the other hand: how much weighs the risk of losing data ? age=47 will perhaps never be stored and nobody will tell you (the user of the API) because I can only return http status 200 and not 199,5 (to signal: almost OK ;-)). I'm not sure if one approach would be to return 202, because I think it has a different meaning.
    – Marged
    Oct 1, 2021 at 17:06
  • That's a risk/benefit question you have to decide for yourself depending on your use case (which is why the question seems to be opinion-based). Though, in my experience, it is much more common to add or remove fields to an API than having to deal with the issue you're describing. Oct 1, 2021 at 17:09
  • This is screaming for a way to return a warning. One that could be ignored. Oct 1, 2021 at 17:32
  • Is the API (specifically the v2 that you are mentioning) public? If so, what is the current behavior when posting the JSON with the extraneous fields? Based on the answers, you may have to think carefully about what Vincent Savard suggested - changing the behavior may result in something that changes the version of the API (although I'm not certain that permitting new values would be a breaking change that would require a major version, it could lead to some decisions down the road if you added the fields as required).
    – Thomas Owens
    Oct 1, 2021 at 20:25

6 Answers 6

11

Whether the API rejects or ignores unsupported fields is a concern for the documentation used by consumers. Pick one, and then document this behavior so clients know what to expect. Let them decide whether or not sending unsupported fields is what they want to do.

There are benefits and drawbacks to either strategy. There is no best practice or design pattern for this. You will need to judge for yourselves based on the sensitivity of data and the potential security impacts of rejecting the request versus simply ignoring it.

Just remember to document this, and inform your clients even if you decide to ignore unsupported fields. Clients might send requests with unsupported fields as a means of feature detection.

If service X supports the age field, do this, otherwise fall back to this other thing.

This change in the outward behavior of your API should be considered a breaking change, because it requires downstream changes to how clients handle this response. This justifies an increment to the major version number of the API if you use semantic versioning.

3
  • If age is optional, would you consider this a breaking change and compulsory to create a v+1 API ?
    – Marged
    Oct 2, 2021 at 5:45
  • If this changes the behavior of what clients expect, then yes. Increment the major version if using semantic versioning. Oct 2, 2021 at 13:25
  • @Marged: I updated my answer with that last bit of info. Oct 2, 2021 at 13:30
6

REST APIs publish contracts so that consumers may know how to use them.

A contract is a written agreement between the publisher and consumer.

Extraneous fields can be handled however you like, provided the publisher and consumer have an agreement.

That's all there is to it.

6

This comment is very relevant.

It is only an internal API. The argument of the consumers is that they will ask me to support the age field ans want to start changing their app and send that field before the API was updated. Although I understand the urgency I don't like that approach.

There is nothing wrong with having a planned API change and your endpoint being forwards compatible. It is especially useful when you already know the change is coming and the client is hard to change (e.g. a mobile app typically has a longer release cycle than web service).

Make sure that the semantics of the API are loosely defined and client doesn't make any assumptions. E.g. the semantics could "I want to register someone to an event, here is everything I know about them, do what you want with that data." and the service defines the details (whether to only the name or both the name and the age).

Imagine you already know the age in the client and are planning to use ages in the future on your service and make it mandatory, but don't have time to implement the backend feature right now. You would have to do multiple steps:

  1. Deploy the backend service with v2.0 (without age) of the API.
  2. Deploy the client with v2.0 of the API
  3. Deploy the backend service with v2.1 (with age), have a feature that allows you to make the presence of the age field mandatory
  4. Deploy all the clients using v2.1 of the API (many users don't update apps immediately or even within years).
  5. Turn on the feature to make age field mandatory.

Now look at the scenario where you do send ages from the beginning:

  1. Deploy the service with a forward compatible API v2.0 or use v2.1 already but ignore the "name" field.
  2. Deploy the app the users, using v2.1 of the API
  3. Deploy a new version of the service using the age field.

Software is there to be useful for the users. Software principles should serve your users and not serve themselves. Don't make then stand in the way of having a good user experience, without a strong reason.

4

In your example, the operation is successful if it sets name to “me” and age to 47. It can fail for any number of reasons, but in this case it must fail because there is no field “age” that can be set to 47.

I would report an error and make sure it doesn’t make any change. Well, that’s me.

Imagine your database has a field age, but by mistake someone called the field “ape” in the request. Same situation, so whatever strategy you use for access to a missing field must also work for a misspelled field. You wouldn’t want the “ape” to be silently ignored, so you can’t allow “age” to be silently ignored.

1
  • Yes, it's situations like the age/ape scrnario that make me think accepting anything is not a good idea
    – Marged
    Oct 2, 2021 at 5:35
4

The Robustness principle, also called "Postel's law" states:

be conservative in what you do, be liberal in what you accept from others

For your case it means to accept the unknown fields and just ignore them.

2
  • I would suggest this only applies to the consumer of the API, not the provider; the provider should reject any requests not matching a (strict) validation; lest a consumer calls your service with dry_ruun=true and expects not to drop an entire database.
    – Duroth
    Oct 6, 2021 at 10:35
  • 1
    Then this should be a required field and not implicitly assume false. The Robustness principle says that as the API provider, you should be forgiving, but as the consumer of the API you should be strict with regards to the parameters. For the response it is the other way around. Oct 6, 2021 at 13:00
1

As other answers note, there are prod and cons to both strictness and leniency here. Which approach is correct depends on the specifics of your use case and how you weight those costs and benefits. There's no cut-and-dried right answer here.

I will note though, that my experience with XML-schema defined interfaces tells me that strictness makes evolving an API much more difficult and I think it's a big reason for why things have moved away from XML (among a number of other problems.)

The problem is that (under strictness) when you want to add an element to your document, the old spec becomes invalid. That means that if client A needs age but client B doesn't, you can't add the field to the interface without either:

  • Client B updating their code
  • Versioning the interface

Both add to the cost of making changes. However, if the cost of potential errors is very high, you may want to implement strictness around unknown fields. The norm with JSON tends to be lenient with regard to unknown fields which leads to the kind of pushback on this that got you here.

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.