Understanding additionalProperties

In a standard JSON schema, additionalProperties (opens in a new tab) controls whether objects can include properties beyond those explicitly defined. By default, if not specified, additionalProperties is considered to be true, allowing objects to carry arbitrary additional data.

Speakeasy's Approach

At Speakeasy, we diverge from this default by setting additionalProperties to false unless explicitly defined otherwise. This approach encourages the definition of fully-typed objects, promoting clear and comprehensive documentation of the object structure. We believe this method aligns with the common developer expectation for creating APIs with precise and predictable data models.

Using additionalProperties: true

Enabling additionalProperties to true can be advantageous for schemas requiring flexibility to incorporate unknown fields dynamically. This setting is ideal for scenarios where the data model might extend beyond the initially defined properties, accommodating future growth without necessitating schema revisions.

Imagine a scenario where an API endpoint accepts user-generated content with a set of core properties but also needs to be open to future extensions. By setting additionalProperties to true, the API can accept and store these extensions without needing schema updates for each new property.

openapi.yaml

components:
schemas:
FlexibleObject:
type: object
properties:
title:
type: string
description:
type: string
additionalProperties: true

This schema allows for the inclusion of any additional user-provided properties alongside the defined title and description.

Typescript

export type FlexibleObject = {
title: string;
description: string;
additionalProperties: Record<string, any>;
}

Using Typed additionalProperties

For use cases that demand arbitrary additional data but within a constrained type, Speakeasy allows additionalProperties to be defined with a specific type or schema. This feature enables the creation of flexible yet type-safe objects.

openapi.yaml

components:
schemas:
StringOnlyObject:
type: object
properties:
title:
type: string
description:
type: string
additionalProperties:
type: string

In this schema, alongside the explicitly defined name, any additional properties must be strings, ensuring a consistent data type across all properties.

Typescript

export type StringOnlyObject = {
title: string;
description: string;
additionalProperties: Record<string, string>;
};