I struggled with this exact same question. Thanks for your research into it and for articulating it well. I think the issue here is that there is data that has to be determined/created by the server/backend that REST hasn't really addressed a best practice for. For example:
- GUID's
- Unique/Sequential Ids
- Timestamps
In every trivial REST example you see it appears to be pretty symmetrical between what you GET vs what you POST/PUT. For example, REST would lead you to believe that if you do a GET on a collection (or resource) and then POST (or PUT) that response body back that there should be no change, but that's just not realistic considering the aforementioned examples. So in essence your GET response becomes a superset of the actual POST/PUT body.
The terminology I've used for this as a head nod to the relational asymmetry between the two has been to say that my GET returns a Readonly representation of the collection/resource, versus that the POST/PUT body accepts. That lends itself nicely to code where you can inherit a Readonly
representation from the object to augment it with the properties that your server/backend is responsible for creating/managing. For example, here's two TypeScript interfaces showing what data a user could PUT (IPet
) versus what data the server would respond with for a GET (IReadonlyPet
)
interface IPet {
name: string, // The user can change the pet's name
}
interface IReadonlyPet extends IPet {
id: number, // The user should not be able to change the pet's id
}
I don't know if I'd force a user to strip off things like id
when making a POST/PUT subsequent to a GET request as that's a lot of data transformation work to ask of your API consumers. I can see two valid and opposing arguments:
- It's borderline bad practice to allow them to create/update with data where you're only accepting some of the properties but silently ignoring others (i.e. they can PUT with a different
id
than they received and you're just silently ignoring it could potentially give them a false sense of the actual state of the collection/resource)
- The adage "be liberal about what you accept and strict about what you generate" would dictate that properties that are superfluous to the schema that your API defines can safely be ignored without generating any errors for the client. So someone could do a GET, then modify the
id
, then do a POST/PUT and you would simply ignore the id
property.
If I had to choose one, I'd probably go with the second option because I think it makes for a simpler, more symmetrical experience for your API consumers in that they can do a full circle GET, POST/PUT the GET response, and GET again to receive the same original response. Additionally, your API consumers can't really complain about implementation behavior for data that goes beyond the defined schema since you're already off the beaten path of standardization.