What it is
Apple's build plugin that generates type-safe Swift client and server code from an OpenAPI document.
Add the plugin to the target with an openapi.yaml and a config file. Generated code appears at build time and is never committed.
Installation
.package(url: "https://github.com/apple/swift-openapi-generator", from: "1.5.0")Getting started
The smallest useful thing you can do with it, and what each part means.
swift
// Package.swift
.target(
name: "BookClient",
dependencies: [
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
.product(name: "OpenAPIURLSession", package: "swift-openapi-urlsession"),
],
plugins: [.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator")]
)
// Usage — every operation and response is typed from the document.
let client = Client(
serverURL: try Servers.server1(),
transport: URLSessionTransport()
)
let response = try await client.getBook(path: .init(id: 42))
switch response {
case .ok(let ok):
let book = try ok.body.json
print(book.title)
case .notFound:
print("no such book")
case .undocumented(let status, _):
print("unexpected status \(status)")
}Advanced usage
Where the library earns its place over a simpler alternative.
swift
struct AuthMiddleware: ClientMiddleware {
let token: String
func intercept(
_ request: HTTPRequest, body: HTTPBody?, baseURL: URL,
operationID: String,
next: (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?)
) async throws -> (HTTPResponse, HTTPBody?) {
var request = request
request.headerFields[.authorization] = "Bearer \(token)"
return try await next(request, body, baseURL)
}
}
let client = Client(serverURL: url, transport: transport,
middlewares: [AuthMiddleware(token: token)])
// The same document can generate a server protocol for Vapor to implement.Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- Type has no member for an operation
- The operationId is missing from the document, or the file was not picked up. Check the plugin's config and file naming.
- Everything falls into the undocumented case
- The spec does not describe those responses. Add them to the document — the generator can only expose what is declared.
Best practices
- Do not commit generated code; the plugin regenerates it on every build.
- Document every response status in the OpenAPI file, or callers land in the undocumented case.
- Use middleware for authentication rather than passing tokens to each call.
- Version the OpenAPI document alongside the code so changes are reviewable.
Background
Why it exists, and what it was reacting to.
Rather than hand-writing request structs and response models for every endpoint, the generator derives them from the API's own contract at build time, so client and server cannot drift apart silently.
