1.4.1

OpenAPI Generation

The Schema API can automatically generate OpenAPI (Swagger) specifications from your schema definitions.

Basic OpenAPI Metadata

Add OpenAPI metadata to your schemas:

class CreateUserSchema < Amber::Schema::Definition
  openapi do
    operation_id "createUser"
    tags ["Users", "Registration"]
    summary "Create a new user account"
    description "Creates a new user with the provided information"

    responses do
      success 201, "User created successfully"
      error 400, "Invalid request data"
      error 409, "Email already exists"
    end
  end

  field :email, String,
    required: true,
    format: :email,
    description: "User's email address",
    example: "[email protected]"

  field :name, String,
    required: true,
    description: "User's full name",
    example: "John Doe"

  field :role, String,
    enum: ["admin", "user", "guest"],
    default: "user",
    description: "User's role in the system"

  validates_to UserRequest, UserValidationError
end

Field Documentation

Document each field for the API spec:

field :email, String,
  required: true,
  format: :email,
  description: "User's email address",
  example: "[email protected]",
  deprecated: false

field :password, String,
  required: true,
  min_length: 8,
  description: "User's password (min 8 characters)",
  example: "securepassword123",
  write_only: true  # Won't appear in response schemas

Generating the Spec

Generate the OpenAPI specification:

# config/initializers/openapi.cr
OpenAPI.configure do |config|
  config.title = "My API"
  config.version = "2.0.0"
  config.description = "API documentation for My Application"

  config.servers = [
    {url: "https://api.example.com", description: "Production"},
    {url: "https://staging-api.example.com", description: "Staging"}
  ]

  config.contact = {
    name: "API Support",
    email: "[email protected]"
  }
end

# Generate spec
spec = OpenAPI.generate_from_schemas([
  CreateUserSchema,
  UpdateUserSchema,
  ListUsersSchema
])

File.write("public/openapi.json", spec.to_json)

Route Integration

Connect schemas to routes:

# config/routes.cr
routes :api do
  post "/users", UsersController, :create,
    schema: CreateUserSchema,
    response_schema: UserResponseSchema

  get "/users/:id", UsersController, :show,
    schema: GetUserSchema,
    response_schema: UserResponseSchema
end

Response Schemas

Define response schemas:

class UserResponseSchema < Amber::Schema::Response
  field :id, Int64
  field :email, String
  field :name, String
  field :role, String
  field :created_at, Time

  openapi do
    description "User object response"
  end
end

class ErrorResponseSchema < Amber::Schema::Response
  field :message, String
  field :errors, Hash(String, Array(String))
  field :error_code, String

  openapi do
    description "Error response with validation details"
  end
end

Security Definitions

Define authentication schemes:

OpenAPI.configure do |config|
  config.security_schemes = {
    "bearerAuth" => {
      type: "http",
      scheme: "bearer",
      bearer_format: "JWT"
    },
    "apiKey" => {
      type: "apiKey",
      in: "header",
      name: "X-API-Key"
    }
  }
end

# Apply to schema
class ProtectedSchema < Amber::Schema::Definition
  openapi do
    security ["bearerAuth"]
  end

  # ...fields
end

Serving the Spec

Serve the OpenAPI spec and Swagger UI:

# config/routes.cr
routes :api do
  # OpenAPI JSON spec
  get "/openapi.json", OpenAPIController, :spec

  # Swagger UI (if using swagger-ui assets)
  get "/docs", OpenAPIController, :swagger_ui
end
# src/controllers/openapi_controller.cr
class OpenAPIController < ApplicationController
  def spec
    spec = OpenAPI.generate
    respond_with 200, spec.to_json, "application/json"
  end

  def swagger_ui
    render "openapi/swagger_ui.ecr"
  end
end

Example Generated Spec

The generated OpenAPI spec looks like:

{
  "openapi": "3.0.3",
  "info": {
    "title": "My API",
    "version": "2.0.0"
  },
  "paths": {
    "/users": {
      "post": {
        "operationId": "createUser",
        "tags": ["Users", "Registration"],
        "summary": "Create a new user account",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateUser"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User created successfully"
          },
          "400": {
            "description": "Invalid request data"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CreateUser": {
        "type": "object",
        "required": ["email", "name"],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "User's email address",
            "example": "[email protected]"
          },
          "name": {
            "type": "string",
            "description": "User's full name",
            "example": "John Doe"
          },
          "role": {
            "type": "string",
            "enum": ["admin", "user", "guest"],
            "default": "user"
          }
        }
      }
    }
  }
}