| name | add-client |
| description | Set up swift-openapi-generator for a client target (URLSession or AsyncHTTPClient). Use when adding a new client that consumes an openapi.yaml. |
Set up swift-openapi-generator for a client target using URLSession or AsyncHTTPClient.
Ask for:
- Transport: URLSession (Apple platforms) or AsyncHTTPClient (server-side / Linux)
- Target name (e.g., ApiClient)
- Path to the existing openapi.yaml (or create a new one)
- Whether to share types with a server target via a shared ApiShared package
Then:
Package.swift dependencies
URLSession (Apple platforms):
swift-openapi-generator (build plugin)
swift-openapi-runtime
swift-openapi-urlsession
AsyncHTTPClient (server-side):
swift-openapi-generator (build plugin)
swift-openapi-runtime
swift-openapi-async-http-client
async-http-client
Target setup
- Add the client target to Package.swift with the OpenAPI build plugin:
.target(
name: "{TargetName}",
dependencies: [
.product(name: "OpenAPIRuntime", package: "swift-openapi-runtime"),
],
plugins: [
.plugin(name: "OpenAPIGenerator", package: "swift-openapi-generator"),
]
)
Configuration files
Create openapi-generator-config.yaml next to the openapi.yaml:
generate:
- types
- client
Shared types pattern (if sharing with server)
If types are shared between client and server, split generation across three targets:
ApiShared target generates only types from openapi.yaml
ApiClient target generates only client, depends on ApiShared
ApiServer target generates only server, depends on ApiShared
Each has its own openapi-generator-config.yaml, but they all reference the same openapi.yaml (via symlink or copy).
Implementation scaffold
import OpenAPIRuntime
import OpenAPIURLSession
let client = Client(
serverURL: URL(string: "http://localhost:8080")!,
transport: URLSessionTransport()
)
let response = try await client.listProducts()
Middleware setup
Ask if the user wants to add middleware (auth, logging, caching). If yes, show how to pass them:
let client = Client(
serverURL: serverURL,
transport: transport,
middlewares: [
AuthMiddleware(token: accessToken),
LoggingMiddleware(),
]
)
Tests
Always create a test target {TargetName}Tests with:
- A mock transport that returns canned responses without hitting the network
- At least one test per generated operation verifying the request path, method, and headers
- A test for each middleware confirming it modifies requests/responses correctly
- Use Swift Testing framework (
@Test, @Suite, #expect)
- Use
withDependencies for injecting the mock transport
@Test func listProductsSendsCorrectRequest() async throws {
let transport = MockTransport { request, body, baseURL, operationID in
#expect(operationID == "listProducts")
#expect(request.method == .get)
return (HTTPResponse(status: .ok), try JSONEncoder().encode(mockProducts))
}
let client = Client(serverURL: serverURL, transport: transport)
let response = try await client.listProducts()
}
Final steps
- Run
swift build to confirm generation + compilation works
- Run
swift test to confirm tests pass
- Show the generated client type and available operations