Ports
How to define data interfaces, write schemas, and use $ref to keep your spec organized.
What is a port?
A port is a named data interface your product exposes. It could be a database table, a Kafka topic, an S3 path, or an HTTP endpoint. Every port has a name, an optional description, one or more connection bindings, and a schema that describes the shape of the data.
Adding a port
Run the interactive form:
daco ports add
Or pass everything as flags:
daco ports add \
--name orders \
--description "Live order records" \
--connection warehouse \
--location public.orders
This creates two things:
- An entry in
spec/opendpi.yaml - A blank schema file at
spec/schemas/orders.schema.yaml
Writing a schema
Open the generated schema file and define your port's data shape using JSON Schema:
# spec/schemas/orders.schema.yaml
type: object
properties:
order_id:
type: string
customer_id:
type: string
placed_at:
type: string
format: date-time
total_cents:
type: integer
status:
type: string
enum: [pending, confirmed, shipped, cancelled]
required:
- order_id
- customer_id
- placed_at
- total_cents
- status
The schema file is referenced from the spec via $ref:
ports:
orders:
description: Live order records
connections:
- connection: "#/connections/warehouse"
location: public.orders
schema:
$ref: schemas/orders.schema.yaml
You can also write the schema inline directly in opendpi.yaml — useful for simple ports with only a few fields.
Supported JSON Schema keywords
Daco's translator understands the full range of JSON Schema Draft 2020-12:
Types: string, integer, number, boolean, null
Objects:
type: object
properties:
name: { type: string }
required: [name]
additionalProperties: false
Arrays:
type: array
items:
type: string
Composition:
allOf:
- $ref: "#/components/schemas/BaseEvent"
- type: object
properties:
payload: { type: string }
Constraints:
type: string
minLength: 1
maxLength: 255
pattern: "^[a-z0-9_]+$"
type: integer
minimum: 0
maximum: 1000000
Enums:
type: string
enum: [active, inactive, archived]
Using $ref and $defs
For schemas with repeated sub-structures, use $defs to define them once and $ref to reference them:
type: object
properties:
billing_address:
$ref: "#/$defs/Address"
shipping_address:
$ref: "#/$defs/Address"
$defs:
Address:
type: object
properties:
street: { type: string }
city: { type: string }
country: { type: string }
required: [street, city, country]
You can also reference schemas from components.schemas in opendpi.yaml:
schema:
$ref: "#/components/schemas/Order"
Location syntax
The location inside a connection binding points to the specific resource within that infrastructure endpoint:
connections:
- connection: "#/connections/warehouse"
location: public.orders # schema.table for SQL databases
connections:
- connection: "#/connections/kafka_prod"
location: order-events # topic name for Kafka
connections:
- connection: "#/connections/s3_data"
location: analytics/orders/ # bucket prefix for S3
connections:
- connection: "#/connections/orders_api"
location: /api/v2/orders # path for HTTP
Viewing and managing ports
daco ports list
daco ports describe orders
Displays the port's connections, location bindings, and a preview of the schema.
Removing a port
daco ports remove orders
Use --force to skip the confirmation prompt. The schema file at spec/schemas/orders.schema.yaml is not deleted automatically — remove it manually if you no longer need it.
Nested objects and arrays
Schemas can be arbitrarily nested. The translator handles all depth levels:
type: object
properties:
id: { type: string }
line_items:
type: array
items:
type: object
properties:
sku: { type: string }
quantity: { type: integer }
unit_price_cents: { type: integer }
required: [sku, quantity, unit_price_cents]
required: [id, line_items]
This translates cleanly to nested PySpark StructType, Pydantic models, Go structs, Protobuf messages, and all other supported formats.