- Overview
- Specification Versions
- Specification Hierarchy
- Key Features
- Core Concepts
- Document Structure
- Schema Conventions
- Path Conventions
- Response Patterns
- Output Modes
- Configuration Options
- Kalo-Morphe Extensions
- Best Practices
- Examples
- Contributing
- License
KA:OA1 (Kalo OpenAPI 1) is a specialized OpenAPI 3.1 specification standard for REST APIs generated from Morphe schemas. It defines conventions, patterns, and extensions that enable seamless integration between Morphe's declarative data modeling and OpenAPI's REST API specification.
This specification builds on OpenAPI 3.1.0 while establishing Kalo-specific conventions for:
- Resource naming and URL structure
- CRUD operation patterns
- Schema generation from Morphe models and entities
- Metadata annotations for traceability
- Modular composition for team collaboration
| Version | Status | Description | Docs |
|---|---|---|---|
| KA:OA1 | 🚧 In Progress | Core OpenAPI standard for Morphe-generated APIs | This document |
| KA:OA1:YAML1 | 🚧 In Progress | YAML format standard for KA:OA1 | format/YAML.md |
| KA:OA1:JSON1 | 🚧 In Progress | JSON format standard for KA:OA1 | format/JSON.md |
The Kalo OpenAPI specification system follows the Kalo specification hierarchy:
KA:- Kalo organization prefixOA1- OpenAPI specification version 1- Defines: Core conventions, patterns, and extensions for Morphe-generated OpenAPI documents
KA:OA1:YAML1- YAML format specification (base format)KA:OA1:JSON1- JSON format specification
YAML (KA:OA1:YAML1) serves as the base format for the Kalo OpenAPI specification, providing:
- Human Readability: Easy to read and edit API specifications
- OpenAPI Ecosystem: Standard format for OpenAPI tooling
- Morphe Alignment: Consistency with Morphe's YAML base format
- Version Control: Diff-friendly format for collaboration
-
📋 Convention-Based CRUD
- Automatic REST endpoint generation
- Consistent operation patterns (list, create, get, update, delete)
- Standard HTTP method mappings
- Predictable URL structures
-
🔄 Morphe Integration
- Direct mapping from Morphe models and entities
- Type-safe schema generation
- Enum and structure support
- Relationship handling
-
🏷️ Traceability Annotations
kalo-morphe-*metadata fields- Source tracking (model, entity, DTO)
- ID strategy identification
- Resource type classification
-
📦 Modular Architecture
- Segmented output for team collaboration
- Reference-based composition
- Clean bundled distribution
- Selective schema inclusion
-
🎯 Production Ready
- OpenAPI 3.1.0 compliant
- JSON Schema validation
- Standard error responses
- Pagination support
The Kalo OpenAPI specification follows REST principles with resources as first-class concepts:
Resource: A Morphe model or entity exposed via REST endpoints
- Collection: Multiple resource instances (e.g.,
/api/people) - Item: Single resource instance (e.g.,
/api/people/{id})
Resource Sources:
entities- Generate endpoints from Morphe entities (domain-oriented)models- Generate endpoints from Morphe models (data-oriented)both- Generate from both entities and models
Each resource supports five standard operations:
| Operation | HTTP Method | Path | Description |
|---|---|---|---|
| List | GET |
/api/{resources} |
Retrieve paginated collection |
| Create | POST |
/api/{resources} |
Create new resource |
| Get | GET |
/api/{resources}/{id} |
Retrieve single resource |
| Update | PATCH |
/api/{resources}/{id} |
Partially update resource |
| Delete | DELETE |
/api/{resources}/{id} |
Delete resource |
Each resource generates four schema types:
- {Resource} - Complete resource representation (read operations)
- {Resource}Create - Create request payload (POST)
- {Resource}Update - Update request payload (PATCH)
- {Resource}List - Paginated list response (GET collection)
Metadata annotations provide traceability from OpenAPI back to Morphe sources:
kalo-morphe-name: Person
kalo-morphe-origin: model
kalo-morphe-resource-type: model
kalo-morphe-id-strategy: autoincrementSee Kalo-Morphe Extensions for complete annotation reference.
Every Kalo OpenAPI document includes:
openapi: 3.1.0
info:
title: Generated API
description: API generated from Morphe schema
version: 1.0.0
servers:
- url: http://localhost:8080
description: Development serverPaths follow resource-oriented conventions:
paths:
/api/{resources}:
get: # List operation
post: # Create operation
/api/{resources}/{id}:
get: # Get operation
patch: # Update operation
delete: # Delete operationComponents organize reusable API elements:
components:
schemas: # Resource, DTO, and enum schemas
responses: # Shared response definitions (Error)
parameters: # Shared parameters (pagination)Tags group operations by resource:
tags:
- name: Person
description: Operations on Person
- name: Company
description: Operations on CompanyResource schemas represent the complete data model:
Person:
type: object
properties:
id:
type: integer
readOnly: true
firstName:
type: string
lastName:
type: string
nationality:
$ref: '#/components/schemas/Nationality'
required:
- firstName
- lastName
- nationality
description: Person modelConventions:
- ID fields marked
readOnly: true - Auto-generated fields excluded from create DTOs
- Foreign keys include descriptive comments
- Required fields explicitly listed
DTOs (Data Transfer Objects) define request payloads:
Create DTO - Excludes auto-generated fields:
PersonCreate:
type: object
properties:
firstName:
type: string
lastName:
type: string
nationality:
$ref: '#/components/schemas/Nationality'
required:
- firstName
- lastName
- nationality
description: Create Person requestUpdate DTO - All fields optional, supports partial updates:
PersonUpdate:
type: object
properties:
firstName:
type: string
nullable: true
lastName:
type: string
nullable: true
nationality:
$ref: '#/components/schemas/Nationality'
description: Update Person requestEnums use JSON Schema enum validation:
Nationality:
type: string
enum:
- German
- French
- American
description: Nationality enumerationList responses include data array and pagination metadata:
PersonList:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Person'
meta:
type: object
properties:
page:
type: integer
description: Current page number
pageSize:
type: integer
description: Items per page
total:
type: integer
description: Total number of items
totalPages:
type: integer
description: Total number of pages
required:
- page
- pageSize
- total
- totalPages
required:
- data
- metaList Operation - GET /api/{resources}:
/api/people:
get:
tags:
- Person
summary: List people
description: Retrieve a paginated list of people
operationId: list_Person
parameters:
- $ref: '#/components/parameters/page'
- $ref: '#/components/parameters/pageSize'
responses:
"200":
description: List of people
content:
application/json:
schema:
$ref: '#/components/schemas/PersonList'
"400":
$ref: '#/components/responses/Error'
"500":
$ref: '#/components/responses/Error'Create Operation - POST /api/{resources}:
post:
tags:
- Person
summary: Create person
description: Create a new person
operationId: create_Person
requestBody:
description: Person to create
content:
application/json:
schema:
$ref: '#/components/schemas/PersonCreate'
required: true
responses:
"201":
description: Created person
content:
application/json:
schema:
$ref: '#/components/schemas/Person'
"400":
$ref: '#/components/responses/Error'
"500":
$ref: '#/components/responses/Error'Get Operation - GET /api/{resources}/{id}:
/api/people/{id}:
get:
tags:
- Person
summary: Get person
description: Retrieve a single person by ID
operationId: get_Person
parameters:
- name: id
in: path
description: Person ID
required: true
schema:
type: integer
format: int64
responses:
"200":
description: Person details
content:
application/json:
schema:
$ref: '#/components/schemas/Person'
"404":
$ref: '#/components/responses/Error'
"500":
$ref: '#/components/responses/Error'Update Operation - PATCH /api/{resources}/{id}:
patch:
tags:
- Person
summary: Update person
description: Update an existing person
operationId: update_Person
parameters:
- name: id
in: path
description: Person ID
required: true
schema:
type: integer
format: int64
requestBody:
description: Person updates
content:
application/json:
schema:
$ref: '#/components/schemas/PersonUpdate'
required: true
responses:
"200":
description: Updated person
content:
application/json:
schema:
$ref: '#/components/schemas/Person'
"400":
$ref: '#/components/responses/Error'
"404":
$ref: '#/components/responses/Error'
"500":
$ref: '#/components/responses/Error'Delete Operation - DELETE /api/{resources}/{id}:
delete:
tags:
- Person
summary: Delete person
description: Delete a person
operationId: delete_Person
parameters:
- name: id
in: path
description: Person ID
required: true
schema:
type: integer
format: int64
responses:
"204":
description: Successfully deleted
"404":
$ref: '#/components/responses/Error'
"500":
$ref: '#/components/responses/Error'Resources follow configurable naming conventions:
| Convention | Example | Collection | Item |
|---|---|---|---|
| kebab-case (default) | ContactInfo | /api/contact-infos |
/api/contact-infos/{id} |
| camelCase | ContactInfo | /api/contactInfos |
/api/contactInfos/{id} |
| snake_case | ContactInfo | /api/contact_infos |
/api/contact_infos/{id} |
Pluralization:
- Enabled by default (
pluralize: true) - Collections use plural form (person → people)
- Irregular plurals handled (company → companies)
Operation IDs:
- Format:
{operation}_{ResourceName} - Examples:
list_Person,create_Company,update_ContactInfo
| Operation | Status Code | Response Body |
|---|---|---|
| List | 200 OK |
{Resource}List with data and meta |
| Create | 201 Created |
Created {Resource} object |
| Get | 200 OK |
{Resource} object |
| Update | 200 OK |
Updated {Resource} object |
| Delete | 204 No Content |
Empty body |
Standard error response schema:
Error:
description: Error response
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Error code
message:
type: string
description: Error message
required:
- code
- message
required:
- errorError Status Codes:
400 Bad Request- Invalid request payload or parameters404 Not Found- Resource not found500 Internal Server Error- Server error
Shared pagination parameters:
parameters:
page:
name: page
in: query
description: Page number
schema:
type: integer
minimum: 1
pageSize:
name: pageSize
in: query
description: Number of items per page
schema:
type: integer
minimum: 1
maximum: 100Default mode - Single OpenAPI file:
openapi.yaml (660 lines)
Characteristics:
- ✅ Single file for easy distribution
- ✅ Standard OpenAPI tooling compatible
- ✅ No annotations (clean spec)
- ❌ Hard to collaborate on
- ❌ Large diffs on changes
Use Cases:
- API documentation sites
- Client SDK generation
- Third-party integration
- Simple projects
Team-friendly mode - Modular fragments:
openapi/
generated/
entities/
Person.entity.yaml
Company.entity.yaml
dtos/
Person.create.yaml
Person.update.yaml
Person.list.yaml
Company.create.yaml
...
enums/
Nationality.enum.yaml
paths/
people.paths.yaml
companies.paths.yaml
parameters/
pagination.parameters.yaml
responses/
error.response.yaml
composed/
root.yaml
dist/
openapi.yaml
Characteristics:
- ✅ Small, focused files
- ✅ Easy to review changes
- ✅ Team collaboration friendly
- ✅ Includes kalo-morphe annotations
- ✅ Clean bundled output in dist/
- ❌ More files to manage
Use Cases:
- Large teams
- Iterative API design
- Morphe schema evolution
- Custom fragment editing
Reference-based composition - Uses $ref for modularity:
# composed/root.yaml
components:
schemas:
Person:
$ref: ./generated/entities/Person.entity.yaml#/schema
PersonCreate:
$ref: ./generated/dtos/Person.create.yaml#/schema
PersonList:
$ref: ./generated/dtos/Person.list.yaml#/schema
paths:
/api/people:
$ref: ./generated/paths/people.paths.yamlCharacteristics:
- ✅ DRY (Don't Repeat Yourself)
- ✅ Selective imports
- ✅ Custom composition
- ❌ Requires bundling for standard tools
The Kalo OpenAPI plugin supports extensive configuration:
# Resource Configuration
resourceSource: "entities" # entities | models | both
modelsPathsMode: "none" # none | namespaced | replace_entities
modelsPathsNamespace: "/_models"
# Naming
naming: "kebab" # kebab | camel | snake
collections:
pluralize: true
# Paths
basePath: "/api"
idParam: "id"
responseEnvelope: false # Wrap responses in {data, meta}
# Schemas
includeAllSchemas: false # Include unreferenced enums/structures
# Output
outputFormat: "yaml" # yaml | json
segmentedOutput: false # Enable modular output
emitAnnotations: true # Include kalo-morphe-* metadata
# Pagination
pagination:
type: "page" # page | cursor
maxPageSize: 100
defaultPageSize: 20
# Relations
relations:
expand: false # Expand relations in responses
# Authentication
auth:
scheme: "none" # none | bearer | oauth2
# Servers
servers:
- url: "http://localhost:8080"
description: "Development server"See Configuration Reference for detailed option descriptions.
Kalo OpenAPI documents include custom annotations for traceability:
kalo-morphe-composed: true
kalo-morphe-version: 1.0.0Resource Schemas:
kalo-morphe-name: Person
kalo-morphe-origin: model
kalo-morphe-resource-type: model
kalo-morphe-id-strategy: autoincrementDTO Schemas:
kalo-morphe-name: PersonCreate
kalo-morphe-origin: dtoEnum Schemas:
kalo-morphe-name: Nationality
kalo-morphe-origin: enumkalo-morphe-operation-type: crud
kalo-morphe-resource: people
kalo-morphe-resource-type: modelkalo-morphe-origin: parameter
kalo-morphe-shared: truekalo-morphe-origin: response
kalo-morphe-shared: true| Annotation | Scope | Values | Description |
|---|---|---|---|
kalo-morphe-composed |
Document | true, false |
Indicates $ref-based composition |
kalo-morphe-version |
Document | Version string | Plugin version |
kalo-morphe-name |
Schema | Resource name | Original Morphe model/entity name |
kalo-morphe-origin |
Schema, Parameter, Response | model, entity, dto, enum, parameter, response |
Source type |
kalo-morphe-resource-type |
Schema, Path | model, entity |
Resource classification |
kalo-morphe-id-strategy |
Schema | autoincrement, uuid |
ID field type |
kalo-morphe-operation-type |
Path | crud |
Operation category |
kalo-morphe-resource |
Path | Resource name (plural) | Target resource |
kalo-morphe-shared |
Parameter, Response | true |
Indicates shared/reusable component |
resourceSource: "entities"Rationale: Entities represent business domain, hiding implementation details.
includeAllSchemas: falseRationale: Only include referenced schemas for cleaner specifications.
Small Teams/Solo: Bundled mode
segmentedOutput: falseLarge Teams: Segmented mode
segmentedOutput: truenaming: "kebab"Rationale: Standard REST convention, URL-safe without encoding.
Edit composed/root.yaml to:
- Add custom paths
- Include selective schemas
- Override generated operations
Then regenerate dist/openapi.yaml without losing customizations.
info:
version: 1.0.0Update version on breaking changes.
Use descriptive tag descriptions:
tags:
- name: Person
description: Manage people and their contact informationInput - Morphe model:
# person.mod
name: Person
fields:
ID:
type: AutoIncrement
FirstName:
type: String
LastName:
type: String
identifiers:
primary: IDOutput - OpenAPI (bundled):
openapi: 3.1.0
info:
title: Generated API
version: 1.0.0
paths:
/api/people:
get:
operationId: list_Person
# ... list operation
post:
operationId: create_Person
# ... create operation
/api/people/{id}:
get:
operationId: get_Person
# ... get operation
patch:
operationId: update_Person
# ... update operation
delete:
operationId: delete_Person
# ... delete operation
components:
schemas:
Person:
type: object
properties:
id:
type: integer
readOnly: true
firstName:
type: string
lastName:
type: string
required:
- firstName
- lastNameSee format/YAML.md for comprehensive examples including:
- Enums
- Relationships
- Multiple resources
- Pagination
- Error handling
Type: string
Default: "entities"
Options: "entities", "models", "both"
Controls which Morphe definitions generate CRUD endpoints.
Type: string
Default: "none"
Options: "none", "namespaced", "replace_entities"
Controls how model paths are exposed when resourceSource is "both".
Type: string
Default: "/_models"
Namespace prefix for model paths when modelsPathsMode is "namespaced".
Type: string
Default: "kebab"
Options: "kebab", "camel", "snake"
URL path naming convention.
Type: string
Default: "/api"
Base path prefix for all endpoints.
Type: boolean
Default: true
Pluralize collection resource names.
Type: string
Default: "id"
Parameter name for ID fields in path parameters.
Type: boolean
Default: false
Wrap responses in {data, meta} structure.
Type: string
Default: "page"
Options: "page", "cursor"
Pagination strategy.
Type: integer
Default: 100
Maximum items per page.
Type: integer
Default: 20
Default items per page.
Type: boolean
Default: false
Whether to expand relations in responses.
Type: string
Default: "none"
Options: "none", "bearer", "oauth2"
Authentication scheme.
Type: array
Default: [{url: "http://localhost:8080", description: "Development server"}]
List of server configurations with URL and optional description.
Type: string
Default: "yaml"
Options: "yaml", "json"
Output file format.
Type: boolean
Default: false
Enable modular fragment output.
Type: boolean
Default: false
Include all enums and structures, even if unreferenced.
Type: boolean
Default: true
Include kalo-morphe-* metadata annotations.
We welcome contributions to the Kalo OpenAPI specification! Here's how you can help:
-
Specification Improvements
- Clarifying conventions
- Adding examples
- Documenting edge cases
- Improving best practices
-
Implementation Feedback
- Testing with OpenAPI tools
- Identifying compatibility issues
- Suggesting optimizations
- Reporting bugs
-
Issues First
- Open an issue to discuss proposed changes
- Reference specification version (KA:OA1)
- Provide examples and use cases
-
Pull Requests
- Fork the repository
- Create descriptive branch names
- Update relevant documentation
- Include examples for new features
-
Specification Changes
- Use clear, concise language
- Follow existing formatting patterns
- Provide YAML examples
- Maintain consistency with Morphe spec
-
Examples
- Include minimal reproducible examples
- Show both input (Morphe) and output (OpenAPI)
- Demonstrate best practices
- Cover common use cases
This project is licensed under the MIT License.