a Swift client for the Anthropic API, generated with swift-openapi-generator.
- Strongly typed request/response models from OpenAPI
- Async client transport via
OpenAPIAsyncHTTPClient - Built-in authentication middleware (
x-api-key,anthropic-version, optionalanthropic-beta) - Support for both JSON responses and SSE streaming (
text/event-stream)
- Swift 5.9+
- Supported platforms: macOS 14+, iOS 16+, tvOS 16+, watchOS 9+
dependencies: [
.package(url: "https://github.com/atacan/AnthropicAPI", branch: "main")
],
targets: [
.target(
name: "YourTarget",
dependencies: [
.product(name: "AnthropicAPI", package: "AnthropicAPI"),
.product(name: "AnthropicAPITypes", package: "AnthropicAPI")
]
)
]import AnthropicAPI
import AnthropicAPITypes
import OpenAPIAsyncHTTPClient
import OpenAPIRuntime
import Foundation
let client = Client(
serverURL: URL(string: "https://api.anthropic.com")!,
transport: AsyncHTTPClientTransport(),
middlewares: [
AuthenticationMiddleware(apiKey: ProcessInfo.processInfo.environment["API_KEY"]!)
]
)
let response = try await client.messages_post(
.init(
body: .json(
.init(
model: .init(value1: Model.haiku4_5.alias ?? Model.haiku4_5.rawValue),
messages: [
.init(
content: .init(value1: "Hello, Claude!"),
role: .user
)
],
max_tokens: 256
)
)
)
)
switch response {
case .ok(let ok):
let message = try ok.body.json
for block in message.content {
if case .text(let text) = block {
print(text.text)
}
}
case .clientError(let statusCode, let err):
let errorBody = try err.body.json
print("Client error \(statusCode): \(errorBody._type)")
case .undocumented(let statusCode, _):
print("Undocumented response status: \(statusCode)")
}let response = try await client.messages_post(
.init(
body: .json(
.init(
model: .init(value1: Model.haiku4_5.alias ?? Model.haiku4_5.rawValue),
messages: [
.init(content: .init(value1: "Say hello in exactly 3 words."), role: .user)
],
max_tokens: 100,
stream: true
)
)
)
)
switch response {
case .ok(let ok):
let stream = try ok.body.text_event_hyphen_stream
.asDecodedServerSentEventsWithJSONData(of: Components.Schemas.MessageStreamEvent.self)
for try await event in stream {
guard let data = event.data else { continue }
if case .content_block_delta(let delta) = data,
case .text_delta(let textDelta) = delta.delta {
print(textDelta.text, terminator: "")
}
}
case .clientError(let statusCode, _):
print("Client error: \(statusCode)")
case .undocumented(let statusCode, _):
print("Undocumented response: \(statusCode)")
}Tool use is a multi-step flow:
- Send
toolsandtool_choicein the request. - Read
tool_useblocks from the model response. - Execute your local tool.
- Send a follow-up message with a
tool_resultblock.
End-to-end examples are in:
Tests/AnthropicAPITests/AnthropicAPITests.swift
AuthenticationMiddleware sets:
x-api-key(required)anthropic-version(default:2023-06-01)anthropic-beta(optional list)
Example:
let middleware = AuthenticationMiddleware(
apiKey: "...",
anthropicVersion: .v2023_06_01,
anthropicBeta: [.interleavedThinking2025_05_14]
)Use Model from AnthropicAPITypes instead of hardcoded strings:
let versioned = Model.sonnet4_5.rawValue // fixed snapshot
let alias = Model.sonnet4_5.alias // moving alias, optional
let recommended = Model.current // current models
let legacy = Model.legacy // older modelsFor production stability, prefer rawValue (versioned model ID).
Create .env in the repository root:
API_KEY=your-anthropic-api-key
# Optional
BASE_URL=https://api.anthropic.comThen run:
swift testSources/AnthropicAPITypes/GeneratedSources/: generated schema/typesSources/AnthropicAPI/GeneratedSources/: generated client operationsSources/AnthropicAPITypes/AuthenticationMiddleware.swift: custom auth middlewareTests/AnthropicAPITests/AnthropicAPITests.swift: real integration-style usage examples
Do not edit files under GeneratedSources/ directly.