Concepts
Schemas
Schemas define the shape of your data using JSON Schema. Every port must have a schema that describes what data consumers can expect.
JSON Schema
OpenDPI uses JSON Schema Draft 2020-12 for schema definitions. JSON Schema is a widely-adopted standard with extensive tooling support.
Basic Types
Primitive Types
# String
type: string
# Number (includes decimals)
type: number
# Integer (whole numbers only)
type: integer
# Boolean
type: boolean
# Null
type: nullObjects
type: object
properties:
name:
type: string
age:
type: integer
required:
- nameArrays
type: array
items:
type: string
# Array of objects
type: array
items:
type: object
properties:
id: { type: integer }
name: { type: string }Common Patterns
Required Fields
Mark fields as required using the required keyword:
type: object
required:
- id
- email
properties:
id:
type: integer
email:
type: string
name:
type: string # OptionalFormats
Use format for semantic validation:
properties:
email:
type: string
format: email
created_at:
type: string
format: date-time
website:
type: string
format: uri
uuid:
type: string
format: uuid
date:
type: string
format: dateCommon formats:
date-time- RFC 3339 timestampdate- Full date (YYYY-MM-DD)time- Time (HH:MM:SS)email- Email addressuri- URIuuid- UUID
Enums
Restrict values to a specific set:
status:
type: string
enum:
- pending
- active
- completed
- cancelledNullable Fields
Allow null values:
# Option 1: Type array
deleted_at:
type:
- string
- "null"
format: date-time
# Option 2: Using oneOf
deleted_at:
oneOf:
- type: string
format: date-time
- type: "null"Additional Properties
Control extra properties on objects:
# Only allow defined properties
type: object
properties:
id: { type: integer }
additionalProperties: false
# Allow any extra properties
type: object
properties:
id: { type: integer }
additionalProperties: true
# Extra properties must be strings
type: object
properties:
id: { type: integer }
additionalProperties:
type: stringInline vs Referenced Schemas
Inline Schema
Define the schema directly in the port:
ports:
users:
connections:
- connection: "#/connections/db"
location: users
schema:
type: object
properties:
id: { type: integer }
email: { type: string, format: email }Use when:
- Schema is simple
- Schema is unique to this port
- Document is small
Referenced Schema
Define in components/schemas and reference with $ref:
ports:
users:
connections:
- connection: "#/connections/db"
location: users
schema:
$ref: "#/components/schemas/User"
components:
schemas:
User:
type: object
properties:
id: { type: integer }
email: { type: string, format: email }Use when:
- Schema is complex
- Schema is shared across ports
- You want better organization
- Schema has nested objects that could be reused
Reusable Components
Shared Schemas
Define once, use everywhere:
ports:
user_created:
schema:
$ref: "#/components/schemas/UserEvent"
user_updated:
schema:
$ref: "#/components/schemas/UserEvent"
user_deleted:
schema:
$ref: "#/components/schemas/UserEvent"
components:
schemas:
UserEvent:
type: object
properties:
user_id: { type: string }
timestamp: { type: string, format: date-time }
event_type: { type: string }Composing Schemas
Reference schemas within other schemas:
components:
schemas:
Address:
type: object
properties:
street: { type: string }
city: { type: string }
country: { type: string }
postal_code: { type: string }
User:
type: object
properties:
id: { type: integer }
name: { type: string }
billing_address:
$ref: "#/components/schemas/Address"
shipping_address:
$ref: "#/components/schemas/Address"allOf for Extension
Combine schemas using allOf:
components:
schemas:
BaseEvent:
type: object
properties:
event_id: { type: string, format: uuid }
timestamp: { type: string, format: date-time }
source: { type: string }
UserEvent:
allOf:
- $ref: "#/components/schemas/BaseEvent"
- type: object
properties:
user_id: { type: string }
action: { type: string }Best Practices
Be Specific
# Good - specific types and constraints
properties:
age:
type: integer
minimum: 0
maximum: 150
email:
type: string
format: email
status:
type: string
enum: [active, inactive]
# Avoid - too generic
properties:
age: {}
email: { type: string }
status: { type: string }Document with Descriptions
properties:
retention_days:
type: integer
description: Number of days to retain data before archival
minimum: 1
maximum: 365Use Consistent Naming
# Consistent: snake_case
properties:
user_id: { type: string }
created_at: { type: string, format: date-time }
order_total: { type: number }
# Avoid mixing styles
properties:
userId: { type: string }
created_at: { type: string }
OrderTotal: { type: number }Complete Example
components:
schemas:
Order:
type: object
description: A customer order with line items
required:
- order_id
- customer_id
- items
- created_at
properties:
order_id:
type: string
format: uuid
description: Unique order identifier
customer_id:
type: string
description: Reference to customer
status:
type: string
enum:
- pending
- confirmed
- shipped
- delivered
- cancelled
default: pending
items:
type: array
minItems: 1
items:
$ref: "#/components/schemas/OrderItem"
total_amount:
type: number
minimum: 0
description: Total order amount in cents
currency:
type: string
pattern: "^[A-Z]{3}$"
default: USD
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
OrderItem:
type: object
required:
- product_id
- quantity
- unit_price
properties:
product_id:
type: string
quantity:
type: integer
minimum: 1
unit_price:
type: number
minimum: 0