Updates
A spec package contains OpenAPI specifications. These generate types used in TypeScript on both client and server, json objects which are used by node/express to validate responses and requests, and an html file for exploring your APIs. This document goes over how to update these APIs and update these outputs.
DRY Schemas with Properties Reference
Best Practice: When defining request bodies for create/update endpoints, use a direct reference to the properties from your main schema to avoid repeating all properties. This keeps your spec DRY and easier to maintain.
Example:
post:
summary: Create a new contact
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
$ref: "../schemas/contact.yaml#/properties"
required:
- relationship_to_owner
This approach:
- Reuses all property definitions from the main schema
- Allows you to specify different required fields for requests vs responses
- Keeps the schema DRY by referencing properties directly
- Works for both POST (create) and PUT (update) operations
The backend can ignore fields it doesn't use, and the response schemas can still use the full schema reference which includes all required fields for responses.
Directory Structure
<your-spec-package>/
├── openapi.yaml # Root OpenAPI specification
├── routes/ # Route specifications
│ ├── auth.yaml
│ ├── todos.yaml
│ └── ...
└── schemas/ # Shared schema definitions
├── user.yaml
├── error.yaml
└── ...
Adding New Endpoints to Your API Specs
When adding new endpoints to your project's API specifications, follow these guidelines:
Create schema file in
schemas/
if neededyamltype: object properties: id: type: integer # ... other properties required: - id # ... other required fields
Create route file in
routes/
following this pattern:yamlget: summary: List all items operationId: listItems # IMPORTANT: Always include operationId for type generation tags: - Feature Name responses: "200": description: Success response content: application/json: schema: type: array items: $ref: "../schemas/your-schema.yaml" "401": description: Unauthorized content: application/json: schema: $ref: "../schemas/error.yaml" /{id}: get: operationId: getItem # IMPORTANT: Always include operationId # Single item endpoint put: operationId: updateItem # IMPORTANT: Always include operationId # Update endpoint
Add paths to
openapi.yaml
:yamlpaths: /your-feature: get: $ref: "./routes/your-feature.yaml#/get" post: $ref: "./routes/your-feature.yaml#/post" /your-feature/{id}: get: $ref: "./routes/your-feature.yaml#/{id}/get" put: $ref: "./routes/your-feature.yaml#/{id}/put"
Add schema reference to components in
openapi.yaml
:yamlcomponents: schemas: YourFeature: $ref: "./schemas/your-feature.yaml"
Generate types and validation:
bashcd specs/apis npm run generate
API Best Practices
General Guidelines
- Always include
operationId
: This is required for proper type generation in the TypeScript clients. - Do not include
security
sections: The security handling is currently managed separately and not used in the OpenAPI specs. - Use consistent naming: Use kebab-case for paths (
/user-profiles
) and camelCase for operationIds (getUserProfile
). - Group related endpoints: Add tags to group related endpoints for better organization.
Data Type Best Practices
Currency: Always use integers (cents) instead of floats to avoid floating-point precision issues.
yamlprice: type: integer description: Price in cents (e.g., 1000 = $10.00)
Dates and Times: Use ISO 8601 format strings for dates and times.
yamlcreatedAt: type: string format: date-time description: Creation timestamp in ISO 8601 format
IDs: Use integer types for database IDs (for SQLite compatibility).
yamlid: type: integer description: Unique identifier
Enums: Define enum values explicitly for better type safety.
yamlstatus: type: string enum: [pending, active, completed] description: Current status of the item
Response Structure
- Always include appropriate error responses (401, 403, 404, 500)
- Use consistent response structures across all endpoints
- Include pagination metadata for list endpoints
Request Validation
- Define request validation rules in the schema
- Include examples where helpful
- Document required vs. optional fields clearly
- Always set
additionalProperties: false
on object schemas to ensure strict validation and prevent unexpected properties
Common Patterns
- Follow existing examples in routes/ for consistent structure
- Include error responses with error schema
- Use descriptive summaries and descriptions
- Use strict schema validation with
additionalProperties: false
to prevent unexpected properties