Post with additional (not supported) attribute


#1

Hey,

so if I have a POST endpoint and I expect the attributes name and age, but the provided data in the POST request is name, age and gender, what is the correct response?

Should I just ignore gender and create the record, returning the created record (without gender). Or do I need to respond with a 403 or something?


#2

Postel’s Law says yes.
You may wish to add something in the meta section to provide feedback to the client that you ignored part of their data.


#3

Hmm, definitely an interesting approach. I just wonder if this is also the “official” json api approach.


#4

We went back-and-forth on this for our still-in-development API. Our take was to be super strict in validation, on the basis that dangling attributes / what-have-you may be symptoms of some other underlying issue in the client. I appreciate Postel’s law as much as the next guy, and I considered it when designing this API, but some small part of me was thinking “he said that because SMTP was poorly specced and there were already a million clients and he didn’t want to make things worse – we’re a clean slate, we don’t have to be nice.”


#5

Of course I can’t give you the “official” answer, but I am currently also implementing the POST in our API and had basically the same question. Since there is no mention of this in the spec, we decided to just ignore the attributes, which is basically in line with the rule that you don’t have to specify all the attributes when creating or updating a resource.


#6

@aah @dnperfors I can see the benefits in both approaches. Currently I am thinking that the user probably gets the bigger benefit in an explicit error, so he knows that something is wrong.

This could save you from issues like submitting a patch request with e.g. naem (a typo of name) where you do not notice that the name field is not updated do to the system ignoring the wrong field.

Thanks for both the answers though.


#7

That’s definitely useful, and why I suggested perhaps providing feedback using the meta section. But if you actually enforce a hard error here then you potentially limit the evolvability of your API - in future if you decided that you no longer needed or wanted the name attribute you couldn’t remove it from your API without breaking existing clients.


#8

Can you expand on this? I’m having trouble seeing how the issue is related to enforcing hard errors or not.


#9

Also, don’t you think it is risky to remove attributes and make it seem to not be a breaking change?

Of course, you should NOT do it, but if you needed to change sex to gender and it would not be a required field, ignoring sex might actually do more harm in not breaking the API, as the user expects the sex attribute to be added, but instead it is just ignored.

I would think it is better to bump the version number of your api if you really need to do those things.

Adding fields should not be a problem, even with the hard restrictions.


#10

Suppose name is a mandatory attribute for a POST, and suppose that the API generates errors when POSTs contain data the API does not support. If the API is changed so that name is no longer used by the API you have two options:

  1. Make name an optional attribute. Old clients will continue to work. New clients might send name or they might not, either way will work.
  2. Remove name from the API. New clients will not send name (because they will see an error if they try to do this). Old clients will all start to receive errors for calls that were previously valid :cry:

In my point of view, removing a previously required attribute should not be a breaking change, so generating errors is the wrong thing to do. I want the API to be evolvable, and I don’t want to break existing clients unless I have to. So I would treat removing any attribute (optional or mandatory) as a non-breaking change (because it is easy for the API to ignore unwanted data supplied in the old format from existing clients).

An attribute rename is effectively removing an attribute (sex) and adding an attribute (gender), they just happen to contain the same data type. Adding the attribute add is a non-breaking change (because the attribute is optional). Whether removing an optional attribute is different from removing a mandatory attribute is an interesting question; but I would prefer to handle the change in the same way (as described above).


#11

Your arguments seem valid to me and I can totally understand where you are coming from.

But the only benefit would be to be able to remove a field without producing errors.

  • Adding mandatory fields will produce an error in either case.
  • Adding optional fields will not result in an error in either case.

However the downside still exists, that while clients do not break, the intended behaviour might “break”. As in, user will now not be able to change their gender as you renamed the field. Finding where the error lies will be much more complicated, since the API does not throw an error.

I think that non-additive changes should always result in a version increase.


#12

Yes. In this particular case I would be tempted to make this a breaking change (and return an error if sex was sent in a request). But where the only change is the removal of an attribute I would prefer this not to be breaking; and therefore I would prefer (generally) to ignore unexpected data. I think this gives a looser coupling and makes it easier to evolve the API.

Agreed. That’s why I suggested the possibility of feeding back via meta even if no error is generated. This feedback could help track down the reason for the unexpected / broken behaviour.


#13

The discussion is interesting and I agree that the spec doesn’t mention it explicitly.

I would argue that how you deal with incomplete resource POST/PUT depends on the level of processing you’re doing with the resource:

  1. If you are storing the resource for retrieval and performing no processing; then an incomplete resource is OK.
  2. If you are expecting business logic to process the resource, then an incomplete resource is bad.

I tend to prefer APIs with clear cut rules and “fail fast”. If I am coding against an API then I want to ensure that I am doing it write and it’s a lot easier if you have a clear definition of what you need to send for a given operation. When serving APIs to others, I need the versioning to be explicit so that the consumers of it can plan and upgrade as required.

Breaking API changes are a pain but sorting out incomplete data in the database months after its collected is often impossible.