Skip to content

Request Bodies in OpenAPI best practices

Request Body Object in OpenAPI

The request body is used to describe the HTTP body of the request for operations. Not all operations require a request body, but when they do, the request body is defined in the requestBody field of the operation object.

paths:
/drinks:
post:
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: The name of the drink.
ingredients:
type: array
items:
type: string
description: The ingredients of the drink.
instructions:
type: string
description: Instructions to prepare the drink.

Request Body Object

Here’s how the requestBody object is structured:

Request Body Object Fields

Field
description
Type
String
Description
A description of the request body. This may contain CommonMark syntax to provide a rich description.
Required
content
Description
A map of Media Type Objects that defines the possible media types that can be used for the request body.
Required
required
Type
Boolean
Description
Whether the request body is required. Defaults to false.
Required
x-*
Description
Any number of extension fields can be added to the Request Body Object that can be used by tooling and vendors.
Required

Required vs optional

Request bodies are optional by default in OpenAPI, so adding the requestBody property does not mean it expects the HTTP request to actually be present. It means it can be present.

This can be changed by setting the required property to true, but it is often forgotten and lots of tooling will remind you to add a required property, even if its set to required: false, just to make sure there is nothing spooky or unexpected happening.

paths:
/drinks:
post:
requestBody:
description: The drink to create.
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: The name of the drink.
ingredients:
type: array
items:
type: string
description: The ingredients of the drink.
instructions:
type: string
description: Instructions to prepare the drink.

Getting this right is not just important for API documentation, but for generated SDKs that should know whether or not to throw errors, and data validations libraries/middlewares which should know whether or not to reject an invalid request.

When should a request body be optional?

Not all that often, but it can be useful for things like PATCH requests where no changes are happening but you want to “touch” the resource to update the updatedAt timestamp.

PATCH /drinks/1 HTTP/1.1
Host: api.example.org

To support this use case, the requestBody can be set to be optional.

paths:
/drinks/{id}:
patch:
requestBody:
description: The drink to update.
required: false
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: The name of the drink.
ingredients:
type: array
items:
type: string
description: The ingredients of the drink.
instructions:
type: string
description: Instructions to prepare the drink.

Sometimes an API will set a request body for a DELETE request, but this is less common and recommended against in both RFC9110: HTTP Semantics and the OpenAPI specification.

Still, OpenAPI begrudgingly allows DELETE to describe a requestBody knowing that some legacy APIs will have done this, and some tooling will even support it.

paths:
/drinks/{id}:
delete:
requestBody:
description: The drink to delete.
required: false
content:
application/json:
schema:
type: object
properties:
reason:
type: string
description: The reason for deleting the drink.

It’s important to describe the API correctly, regardless of which best practices it has gone against, but whenever possible channel the feedback to the developers and see if those mistakes can be avoided in the future.

Encoding Object

Only applicable to requestBody where the media type is multipart or application/x-www-form-urlencoded. An encoding object describes the encoding of a single property in the request schema.

Encoding Object Fields

Field
contentType
Type
String
Description
The content type of the field. If the field is an object, the default is application/json. If the field is an array, the default is based on the inner type. Otherwise, the default is application/octet-stream. Valid values are either a media type (for example, application/json), a wildcard media type (for example, image/*), or a comma-separated list of media types and wildcard media types (for example, image/png, application/*).
Required
headers
Type
Description
Only applies to multipart requests. Allows additional headers related to the field. For example, if the client needs to add a Content-Disposition for an uploaded file. A Content-Type header in this map will be ignored, in favor of the contentType field of the encoding object.
Required
style
Type
String
Description
Can take one of the following values: form, spaceDelimited, pipeDelimited, or deepObject. Specifies the style of the field's serialization only in requests with media type multipart/form-data or application/x-www-form-urlencoded. See the description of style under Query Parameters.
Required
explode
Type
Boolean
Description
Only applies to requests with media type multipart/form-data or application/x-www-form-urlencoded and fields with array or object types. If style is form, the default is true, otherwise the default is false.
Required
allowReserved
Type
Boolean
Description
Only applies to requests with media type application/x-www-form-urlencoded. Determines whether reserved characters (those allowed in literals but with reserved meanings) are allowed in the parameter's content. The default is false. When true, it allows reserved characters as defined by RFC 3986 to be included without percent-encoding. This can be useful for parameters with content such as URLs.
Required
paths:
/drinks:
post:
requestBody:
description: The drink to create.
required: true
content:
multipart/form-data:
schema:
properties:
# ... other properties ...
photo:
description: A photo of the drink.
type: string
format: binary
encoding:
photo:
contentType: image/jpeg, image/png
headers:
Content-Disposition:
description: Specifies the disposition of the file (attachment and file name).
schema:
type: string
default: 'form-data; name="photo"; filename="default.jpg"'
allowReserved: false
# style: form - not applicable to strings
# explode: false - not applicable to strings

anyOf and oneOf

Sometimes a request body could contain multiple different data structures:

requestBody:
description: A JSON object containing pet information
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/DebitCard"
- $ref: "#/components/schemas/CreditCard"
- $ref: "#/components/schemas/BankTransfer"
- $ref: "#/components/schemas/IDEAL"

Learn more about this concept in the schema composition guide.