Skip to main content

OpenAPI support

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]
note

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<string, number>;
export type MapUntypedValues = Record<string, unknown>;
Python
MapTypedValues = Dict[str, int]
MapUntypedValues = Dict[str, object]
Go
type Data struct {
MapTypedValues map[string]int64
MapUntypedValues map[string]interface{}
}

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 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'`
}