a Swift client for the Anthropic API, generated with swift-openapi-generator.
What You Get
- 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)
Requirements
- Swift 5.9+
- Supported platforms: macOS 14+, iOS 16+, tvOS 16+, watchOS 9+
Install
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") ] ) ]
Quick Start
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)") }
Streaming Responses (SSE)
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 Pattern
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
Authentication Middleware
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] )
Model Selection
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 models
For production stability, prefer rawValue (versioned model ID).
Run Tests Locally
Create .env in the repository root:
API_KEY=your-anthropic-api-key
# Optional
BASE_URL=https://api.anthropic.comThen run:
Project Structure
Sources/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.