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"
}
}
}
}
}
}