Generating servers
The same document generates a server-stub module. The document stays the source of truth: generate the client and the server from one specification and implement one handler function per operation.
using OpenAPI, HTTP
OpenAPI.server(
"https://example.com/openapi.yaml";
framework = :HTTP,
name = "ExampleServer",
path = "ExampleServer.jl",
)framework = :HTTP (the default, available when HTTP.jl is loaded) targets HTTP.Router. Server framework packages add their own emitters through the OpenAPI.server_source extension seam. An extension must assemble its generated module through OpenAPI.server_module_source; this keeps the runtime data, pasted server code, and generated-code contract guard together. OpenAPI.serverplan is the staged sibling of OpenAPI.plan and rejects documents whose requests cannot be decoded faithfully (for example multipart/mixed request bodies, or two exploded object query parameters whose wire names cannot be told apart).
The generated header
The generated module header lists every handler signature the implementation must define. For a small document:
using OpenAPI, HTTP
document = """
openapi: 3.1.0
info: {title: Widgets, version: 1.0.0}
paths:
/widgets/{id}:
get:
operationId: getWidget
parameters:
- {name: id, in: path, required: true, schema: {type: integer, format: int64}}
- {name: verbose, in: query, schema: {type: boolean}}
responses:
"200":
description: one widget
content:
application/json:
schema:
type: object
required: [id, name]
properties:
id: {type: integer, format: int64}
name: {type: string}
delete:
operationId: deleteWidget
parameters:
- {name: id, in: path, required: true, schema: {type: integer, format: int64}}
responses:
"204": {description: deleted}
"""
source_code = OpenAPI.server(document; framework = :HTTP, name = "WidgetsServer")
header = Iterators.takewhile(!startswith("module"), eachsplit(source_code, '\n'))
println(join(header, '\n'))# Generated by OpenAPI.jl v1.0.0 from "Widgets" version "1.0.0". Do not edit.
# Implement these handler functions in a module (or any value
# supporting `getfield`) and mount them with `register!(router, impl)`:
# deletewidget(request, id::Int64) -> Nothing
# getwidget(request, id::Int64; verbose::Union{Absent,Bool} = ABSENT) -> GetwidgetResponse200Implementing handlers
Handler functions receive the raw request first, then typed path parameters in template order, then a required body; optional parameters arrive as keyword arguments only when the request supplied them.
include("ExampleServer.jl")
module Handlers
using HTTP
# GET /widgets/{id} -> get_widget(request, id::Int64; verbose = ABSENT)
function get_widget(request, id; verbose = false)
return lookup_widget(id; verbose) # encoded, validated, 200
end
# This operation documents 204, so nothing becomes an empty 204 response.
delete_widget(request, id) = nothing
# Return an HTTP.Response directly for custom behavior.
create_widget(request, body) = HTTP.Response(409, "already exists")
end
router = HTTP.Router()
ExampleServer.register!(router, Handlers; path_prefix = "/v1")
server = HTTP.serve!(router, "127.0.0.1", 8080)register!(router, impl; path_prefix, middleware) mounts every documented operation and fails eagerly, listing the expected signatures, when impl is missing any handler. middleware wraps each operation handler (middleware(handler) -> handler). register is kept as an alias, and the handler contract — implementation module second, typed positional parameters, typed-value-or-HTTP.Response returns — matches the shape OpenAPI.jl 0.2.x users generated with -g julia-server.
Request decoding and response encoding
Request decoding mirrors client encoding: parameter styles (simple, label, matrix, form, spaceDelimited, pipeDelimited, deepObject), header and cookie parameters, JSON, application/x-www-form-urlencoded, and multipart/form-data request bodies, with request-direction schema validation before handlers run. Decoding failures produce structured JSON 400 (or 415 for undocumented media types) responses without invoking the handler. Response values are validated against the output-direction schema and encoded from the first documented success response. Returning nothing follows that response: it emits an empty body when the response has no content, or JSON null when the selected JSON schema accepts null. A full HTTP.Response bypasses generated status, header, and body validation. The handler owns that validation.
An operation that documents no success response at all (only error entries) produces a missing_success_response planning warning; its handler's nothing return is answered with an empty 200, which the OpenAPI specification permits — response documentation is explicitly non-exhaustive.
Security and unsupported encodings
Generated server stubs do not authenticate or authorize requests. Apply a middleware that enforces the operation's security policy before it calls the handler. serverplan rejects request-body Encoding Objects that the generated HTTP server cannot recover faithfully. This includes nested encodings, custom multipart part headers, and explicit body encoding style modifiers.