--- title: OpenAPI support | Stainless --- ## Schemas and types ### Primitives Stainless supports these primitives from the OpenAPI specification: - `string` - `null` - `boolean` - `integer` - `number` TypeScript ``` export interface Data { strings: string; nulls: null; booleans: boolean; integers: number; numbers: number; } ``` Python ``` class Data(BaseModel): strings: str nulls: None booleans: bool integers: int numbers: float ``` Go ``` type Data struct { String string Nulls interface{} Booleans bool Integers int64 Numbers float64 } ``` ### `object` Stainless supports multiple variations of `object` types. ``` # MapTypedValues type: object properties: foo: type: string description: A foo property bar: type: boolean required: [foo] ``` TypeScript ``` interface FooObject { // A foo field foo: string: bar?: boolean; } ``` Python ``` class FooObject(BaseModel): # A foo field foo: str bar: Optional[bool] ``` Go ``` type FooObject struct { // A foo field Foo string `json:"foo,required"` Bar bool `json:"bar"` } ``` ### `oneOf` and `anyOf` Stainless treats both `oneOf` and `anyOf` as equivalent to a TypeScript union. ``` oneOf: - type: object properties: foo: type: string required: [foo] - type: object properties: bar: type: boolean required: [bar] ``` JSON Schema states that a `oneOf` schema must match *exactly* one of the given schemas. This means that a schema like ``` oneOf: - type: string - enum: ['CLOSED', 'OPEN'] ``` has the surprising behavior that `CLOSED` is not accepted by the schema since it matches both of the schemas in the `oneOf`, not one. Counterintuitively this schema accepts *all strings except* `CLOSED` and `OPEN`. TypeScript ``` export interface FooObj { foo: string; } export interface BarObj { bar: boolean; } export type Schema = FooObj | BarObj; ``` Python ``` class FooObj(BaseModel): foo: str class BarObj(BaseModel): bar: bool Schema = Union[FooObj, BarObj] ``` Go ``` type FooObj struct { Foo string `json:"foo"` } func (*FooObj) implementsSchema() {} type BarObj struct { Bar bool `json:"bar"` } func (*BarObj) implementsSchema() {} type Schema interface { implementsSchema() } ``` #### `discriminator` A `discriminator` property for a union schema allows mapping a JSON object to one of the variants by looking up a single property. This simplifies deserialization and makes mapping much faster. We recommend that all unions which have multiple object variants specify this in the schema. ``` oneOf: - type: object properties: kind: const: 'foo_object' foo: type: string required: [foo] - type: object properties: kind: const: 'bar_object' bar: type: boolean required: [bar] discriminator: propertyName: kind ``` ### `allOf` By default, Stainless handles `allOf` by flattening the entries into one schema and treating it like an `object`. However, if one of the entries is a model, then Stainless uses the model entry as a part of composition. ``` # ObjectIntersection allOf: - $ref: '#/components/schemas/FooObject' - type: object properties: baz: type: string - type: object properties: haz: type: boolean ``` TypeScript ``` export interface ObjectIntersection extends FooObject { baz?: string; haz?: boolean; } ``` Python ``` class ObjectIntersection(BaseModel, FooObject): # A foo baz: Optional[str] has: Optional[bool] ``` Go ``` type ObjectIntersection struct { FooObject Baz string `json:"baz"` Has bool `json:"has"` } ``` ### `date` and `date-time` Stainless supports generating rich, language specific types for date and datetime schemas. ``` # DateObj type: string format: date # DateTimeObj type: string format: date-time ``` TypeScript ``` // Not fully supported yet export type DateObj = string; export type DateTimeObj = string; ``` Python ``` import datetime DateObj = datetime.date DateTimeObj = datetime.datetime ``` Go ``` import "time" type Data struct { DateObj param.Field[time.Time] `format:"date"` DateTimeObj param.Field[time.Time] `format:"date-time"` } ``` ### `additionalProperties` Stainless supports OpenAPI’s `additionalProperties` specification which is equivalent to TypeScript’s `Record` type or Python’s `dict` type. ``` # MapTypedValues type: object additionalProperties: type: integer # MapUntypedValues type: object additionalProperties: true ``` TypeScript ``` export type MapTypedValues = Record; export type MapUntypedValues = Record; ``` Python ``` MapTypedValues = Dict[str, int] MapUntypedValues = Dict[str, object] ``` Go ``` type Data struct { MapTypedValues map[string]int64 MapUntypedValues map[string]interface{} } ``` Stainless does not support `additionalProperties: {}` as that’s often a mistake. You should instead use the more explicit `additionalProperties: true` syntax. #### `propertyNames` Stainless does not support `propertyNames`, which is used to define the schema of the map key. ``` type: object propertyNames: type: string enum: ["name", "email"] ``` ### `enum` and `const` Enums define a set of number and string literals that could be specified withing a field. ``` # FooModel type: string enum: [bar, baz, bam] ``` TypeScript ``` export type FooModel = 'bar' | 'baz' | 'bam' ``` Python ``` FooModel = Literal['bar' | 'baz' | 'bam'] ``` Go ``` type FooModel string const ( FooModelBar FooModel = 'bar' FooModelBaz = 'baz' FooModelBam = 'bam' ) ``` #### `x-enum-descriptions` Stainless optionally supports providing enum member descriptions, which either get rendered in the member variables or the main enum type, depending on the language. Descriptions can be provided with either the [x-enum-descriptions](https://redocly.com/docs/api-reference-docs/specification-extensions/x-enum-descriptions/) extension or with a `oneOf`: ``` # FooModel oneOf: - const: 'bar' description: 'A bar variant' - const: 'baz' description: 'A baz variant' - const: 'bam' description: 'A bam variant' ``` ### Unknown and Any Stainless supports specifying types that are `unknown` and `any`, and accepts any valid JSON value. The JSON Schema way of specifying this behavior is to specify an ‘empty’ schema, but this often happens by accident. Unless you add an `x-stainless-any`, Stainless adds a diagnostic note to your OpenAPI schema. ``` # EmptySchema (the OpenAPI default) type: 'object' properties: foo: x-stainless-any: true ``` TypeScript ``` export type EmptySchema = { foo: unknown; }; ``` Python ``` class EmptySchema(BaseModel): foo: object ``` Go ``` type EmptySchema struct { Foo interface{} `json:'foo'` } ``` ## Parameter behavior ### `default` Stainless does not include default values from the OpenAPI spec in generated SDK methods. Parameters with defaults are treated the same as optional parameters without defaults. Stainless treats the `default` property as the server-defined default. If your server applies this default when the parameter is omitted, there’s no need to send it from the client. Not sending defaults from the client gives you more control over the value and allows you to change it without requiring SDK users to upgrade. Supporting defaults at arbitrary locations across all SDK languages would also require significant implementation tradeoffs. For header parameters that need a default value sent with every request, configure them in your Stainless config using [`client_settings.default_headers`](/docs/reference/config#client-settings/index.md): ``` client_settings: default_headers: X-Feature-Flag: 'enabled' X-API-Version: '2025-01-01' ``` This will ensure these headers are sent automatically with every request made by the SDK. For query parameters or request body parameters, there is currently no equivalent configuration option in Stainless. These should be handled by your server applying the default when the parameter is omitted, or can be implemented via [custom code](/docs/guides/add-custom-code/index.md). Similarly, `default` values in response schemas are ignored by Stainless. Response defaults are expected to be applied server-side. ### `readOnly` Properties marked with `readOnly: true` in OpenAPI are handled differently depending on whether they appear in request parameters or response schemas: - **Request parameters**: Fields marked as `readOnly` are excluded from generated parameter types, as they should not be sent by the client - **Response schemas**: Fields marked as `readOnly` are included in response types, as they are expected to be returned by the server This behavior aligns with the OpenAPI specification, where `readOnly` properties should only appear in responses and not in request bodies. For Terraform providers, `readOnly` properties are automatically treated as `computed` attributes, meaning they are provided by the API rather than configured by the user. See our [Terraform guide](/docs/targets/terraform#custom-configurability/index.md) for more details on how `readOnly` affects Terraform resource configurability.