I am learning OpenAPI recently, and would like to know the best practices.
Let's say I have a resource called Person, and it is defined in components/schemas as follows:
Person:
type: object
required:
- id
- name
- age
properties:
id:
readOnly: true
type: integer
name:
type: string
age:
type: integer
I've made id readOnly because when I do post or patch, the ID will be passed as part of the URL. See https://swagger.io/docs/specification/data-models/data-types/
name and age must present when the client tries to create a new person using post method, or get a person, therefore they are defined as required.
My question is about patch: what if I only want to update a person's age or name independently? Ideally I would like to do something like
PATCH /person/1
{"age": 40}
However, since I've defined name as required, I can't do it. I can think of several solutions, but they all have flaws:
- Remove the
requiredrestriction. But if I do that, I lose the validation onpostandget. - Use a separate schema for
patch, e.g.PersonUpdate, withrequiredremoved. Apparently that leads to redundancy. - When I do
patch, I do pass all the fields, but for the ones I don't want to update, I pass an invalid value, e.g.
PATCH /Person/1
{"age": 40, "name": null}
And make all the fields nullable, and let the server ignore these values. But what if I do want to set name to null in DB?
- I use
PUTfor update, and always pass all the required fields. But what if my data is outdated? E.g. when I do
PUT /Person/1
{"age": 40, "name": "Old Name"}
Some other client has already changed name to "New Name", and I am overriding it.
- Like method 3, but I pass additional fields when doing
patchto indicate the fields the server should care, whether using query parameters like?fields=age, or add it to the JSON body. So I can change therequestBodyto something like
requestBody:
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Person'
- type: object
properties:
_fields:
type: array
items:
type: string
Then I can do this
PATCH /Person/1
{"age": 40, "name": null, _fields: ["age"]}
In this way, I can update name to null as well
PATCH /Person/1
{"age": 40, "name": null, _fields: ["age", "name"]}
This method seems can work, but is there a better or widely accepted practice?