Skip to content

OpenAPI Specification Generation Guidelines

Version: 1.0.0
Target: OpenAPI 3.0.3
Purpose: Generate REST API specifications from entity specifications

Type Mappings

Map data types from specs/_meta/data-types.md to OpenAPI schema types:

type_mappings:
  # Primitive Types
  string:
    type: string
  text:
    type: string
  integer:
    type: integer
    format: int32
  long:
    type: integer
    format: int64
  positive_integer:
    type: integer
    minimum: 1
  decimal:
    type: number
    format: double
  boolean:
    type: boolean
  datetime:
    type: string
    format: date-time
  date:
    type: string
    format: date

  # Formatted Types
  uuid:
    type: string
    format: uuid
  uri:
    type: string
    format: uri
  email:
    type: string
    format: email
  language_code:
    type: string
    pattern: "^[a-z]{2}$"
  version_string:
    type: string
    pattern: "^\\d+\\.\\d+\\.\\d+$"

  # Restricted String Types
  short_string:
    type: string
    minLength: 1
    maxLength: 255
  long_string:
    type: string
    minLength: 1
    maxLength: 8000
  identifier_token:
    type: string
    minLength: 1

  # Composite Types
  multilingual_text:
    type: object
    additionalProperties:
      type: string
  reference:
    type: object
    required: [id]
    properties:
      id: {type: string, format: uuid}
      href: {type: string, format: uri}
      type: {type: string}
      name: {type: string}
  date_range:
    type: object
    required: [start, end]
    properties:
      start: {type: string, format: date}
      end: {type: string, format: date}
  date_range_open_ended:
    type: object
    anyOf:
      - required: [start]
      - required: [end]
    properties:
      start: {type: string, format: date}
      end: {type: string, format: date}
  coordinates:
    type: object
    required: [x, y]
    properties:
      x: {type: integer, minimum: 1}
      y: {type: integer, minimum: 1}

OpenAPI Document Template

openapi: 3.0.3
info:
  title: RUT Domain API
  description: |
    REST API for the RUT domain model entities.

    This API is automatically generated from entity specifications
    in the specs/ directory.
  version: {version}
  contact:
    name: API Support
    email: support@example.org
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://api.example.org/v1
    description: Production server
  - url: https://api-staging.example.org/v1
    description: Staging server
  - url: http://localhost:8080/v1
    description: Local development server

tags:
  - name: entities
    description: Domain model entities

paths:
  # Generated from entity api_operations

components:
  schemas:
    # Generated from entity specifications

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    OAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://auth.example.org/oauth/authorize
          tokenUrl: https://auth.example.org/oauth/token
          scopes:
            read: Read access
            write: Write access
            admin: Administrative access

security:
  - BearerAuth: []
  - OAuth2: [read, write]

Schema Generation Rules

1. Entity Schema

For each entity specification, generate a schema component:

components:
  schemas:
    {EntityName}:
      type: object
      description: |
        {description from specification}

        {purpose from specification}
      required:
        # List all required properties
        - {required_property}
      properties:
        {propertyName}:
          type: {openapi_type}
          format: {format}
          description: {property_description}
          example: {example}
          minLength: {min_length}
          maxLength: {max_length}
          pattern: {pattern}
          minimum: {minimum}
          maximum: {maximum}
          readOnly: {true if immutable or auto_generated}
      example:
        # Include JSON example from specification

2. Enumeration Schema

For enumeration types:

components:
  schemas:
    {EnumName}:
      type: string
      description: {description}
      enum:
        - {Value1}
        - {Value2}
        - {Value3}
      example: {example}
      x-enum-descriptions:
        {Value1}: {description}
        {Value2}: {description}
        {Value3}: {description}

3. Path Generation

For each api_operation in the entity specification:

paths:
  {api_endpoint}:
    {http_method}:
      operationId: {operation}_{entity_id}
      tags:
        - entities
      summary: {operation} {entity_name}
      description: {operation description}
      parameters:
        # From api_operation parameters or query_parameters
      requestBody:
        # If operation has request_body
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/{EntityName}'
      responses:
        '{status_code}':
          description: {status description}
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/{EntityName}'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalServerError'

Complete Example

For the Population entity:

paths:
  /api/v1/populations:
    get:
      operationId: list_populations
      tags:
        - entities
      summary: List populations
      description: Retrieve a paginated list of population entities
      parameters:
        - name: page
          in: query
          description: Page number
          schema:
            type: integer
            default: 1
            minimum: 1
        - name: page_size
          in: query
          description: Number of items per page
          schema:
            type: integer
            default: 50
            minimum: 1
            maximum: 100
        - name: search
          in: query
          description: Search in name and description
          schema:
            type: string
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Population'
                  pagination:
                    $ref: '#/components/schemas/PaginationInfo'

    post:
      operationId: create_population
      tags:
        - entities
      summary: Create a new population
      description: Create a new population entity
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PopulationCreate'
      responses:
        '201':
          description: Population created successfully
          headers:
            Location:
              schema:
                type: string
                format: uri
              description: URI of the created resource
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Population'
        '400':
          $ref: '#/components/responses/BadRequest'

  /api/v1/populations/{id}:
    parameters:
      - name: id
        in: path
        required: true
        description: Population identifier
        schema:
          type: string
          format: uuid

    get:
      operationId: get_population
      tags:
        - entities
      summary: Get a population
      description: Retrieve a population by its identifier
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Population'
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      operationId: update_population
      tags:
        - entities
      summary: Update a population
      description: Update an existing population entity
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PopulationUpdate'
      responses:
        '200':
          description: Population updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Population'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'

    delete:
      operationId: delete_population
      tags:
        - entities
      summary: Delete a population
      description: Delete a population entity
      responses:
        '204':
          description: Population deleted successfully
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: Cannot delete (referenced by other entities)
          content:
            application/json:
              schema:
                $ref: '#/components/responses/Conflict'

components:
  schemas:
    Population:
      type: object
      description: |
        A specific subset of a universe that is defined with precise 
        temporal and geographic boundaries.
      required:
        - id
        - createdDate
        - modifiedDate
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the population
          readOnly: true
          example: "123e4567-e89b-12d3-a456-426614174000"
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: The name of the population
          example: "Swedish labour force Q1 2024"
        description:
          type: string
          minLength: 1
          maxLength: 8000
          description: Detailed description of the population
        eventPeriod:
          type: object
          description: The time period during which events occurred
          required:
            - start
          properties:
            start:
              type: string
              format: date
            end:
              type: string
              format: date
        referencePeriod:
          type: object
          description: The time period to which the data refers
          required:
            - start
          properties:
            start:
              type: string
              format: date
            end:
              type: string
              format: date
        geography:
          type: string
          minLength: 1
          maxLength: 8000
          description: Geographic scope or boundaries
          example: "Sweden, all municipalities"
        createdDate:
          type: string
          format: date-time
          description: When the population was created
          readOnly: true
        modifiedDate:
          type: string
          format: date-time
          description: When the population was last modified
          readOnly: true
        version:
          type: string
          pattern: "^\\d+\\.\\d+\\.\\d+$"
          description: Version number (semantic versioning)
          example: "1.0.0"
      example:
        id: "pop-12345678-1234-1234-1234-123456789001"
        name: "Swedish labour force Q1 2024"
        description: "Persons aged 16-64 registered as residents in Sweden..."
        eventPeriod:
          start: "2024-01-01"
        referencePeriod:
          start: "2024-01-01"
          end: "2024-03-31"
        geography: "Sweden, all municipalities"
        createdDate: "2024-01-15T10:30:00Z"
        modifiedDate: "2024-01-15T10:30:00Z"
        version: "1.0.0"

    PopulationCreate:
      type: object
      description: Schema for creating a new population
      properties:
        # Exclude auto-generated fields (id, createdDate, modifiedDate)
        name:
          type: string
          minLength: 1
          maxLength: 255
        description:
          type: string
          minLength: 1
          maxLength: 8000
        eventPeriod:
          $ref: '#/components/schemas/DateRangeOpenEnded'
        referencePeriod:
          $ref: '#/components/schemas/DateRangeOpenEnded'
        geography:
          type: string
          minLength: 1
          maxLength: 8000
        version:
          type: string
          pattern: "^\\d+\\.\\d+\\.\\d+$"

    PopulationUpdate:
      type: object
      description: Schema for updating a population
      properties:
        # Allow updating all writable fields
        name:
          type: string
          minLength: 1
          maxLength: 255
        description:
          type: string
          minLength: 1
          maxLength: 8000
        eventPeriod:
          $ref: '#/components/schemas/DateRangeOpenEnded'
        referencePeriod:
          $ref: '#/components/schemas/DateRangeOpenEnded'
        geography:
          type: string
          minLength: 1
          maxLength: 8000
        version:
          type: string
          pattern: "^\\d+\\.\\d+\\.\\d+$"

    DateRangeOpenEnded:
      type: object
      anyOf:
        - required: [start]
        - required: [end]
      properties:
        start:
          type: string
          format: date
        end:
          type: string
          format: date

    PaginationInfo:
      type: object
      properties:
        page:
          type: integer
          minimum: 1
        pageSize:
          type: integer
          minimum: 1
        totalItems:
          type: integer
          minimum: 0
        totalPages:
          type: integer
          minimum: 0

    Error:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
        message:
          type: string
        details:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
              message:
                type: string

  responses:
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: Conflict
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalServerError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

Best Practices

  1. Versioning: Use semantic versioning in the API path (/v1, /v2)
  2. DTOs: Create separate schemas for Create/Update operations
  3. Pagination: Always include pagination for list operations
  4. Error Handling: Use standard error response schemas
  5. HATEOAS: Include links in responses for discoverability
  6. Filtering: Support filtering via query parameters
  7. Sorting: Support sorting via query parameters
  8. Field Selection: Support sparse fieldsets
  9. Documentation: Include comprehensive descriptions and examples
  10. Security: Define security schemes and apply to operations

Output Location

api/
├── openapi.yaml           # Complete OpenAPI specification
├── openapi-components/    # Reusable components
│   ├── schemas/
│   │   └── entities.yaml
│   ├── parameters.yaml
│   ├── responses.yaml
│   └── security.yaml
└── paths/
    └── entities/
        ├── populations.yaml
        ├── universes.yaml
        └── data-sets.yaml

Validation

After generation: 1. Validate against OpenAPI 3.0.3 schema 2. Use tools like Spectral for linting 3. Generate documentation with Redoc or Swagger UI 4. Test with Postman or similar tools