This repo existed twice: the forge carried a client regenerated against cloud 70b374b9, github carried one against 54ddf3d6 — its ancestor — plus the examples, hanzo.yml and .gitignore the forge line never had. Neither was a superset, so neither could simply overwrite the other. Merged: the newer generation, and everything only the other line had. The flows had rotted against it exactly as the gate exists to prevent, because the regeneration and the examples were on opposite lines: the newer document tags those operations under AiAPI, and drops /v1/keys entirely. models calls AiAPI, hello calls ToolsAPI.getTools — typed, and still the call that refuses without a credential. hanzo.yml now gates the tree that carries both, so the next such move breaks in CI rather than in a reader's editor.
3.2 KiB
Hanzo Cloud — Swift SDK
Swift client for the Hanzo Cloud API, generated from the API's own OpenAPI document. Async/await, no external dependencies.
.spec-lock names the ref and the digest of the bytes this tree
was cut from.
Install
dependencies: [
.package(url: "https://github.com/hanzo-swift/sdk", from: "8.0.0")
]
.target(name: "App", dependencies: [.product(name: "Hanzo", package: "sdk")])
Swift 6. The package declares swiftLanguageModes: [.v6] because the client
throws typed errors (async throws(ErrorResponse)), which only Swift 6 parses.
It builds on Linux as well as Apple platforms.
Quickstart
import Hanzo
let hanzo = HanzoAPIConfiguration(
basePath: "https://api.hanzo.ai",
customHeaders: ["Authorization": "Bearer \(key)"]
)
try await AiAPI.getModels(apiConfiguration: hanzo)
HanzoAPIConfiguration.shared is the default every call falls back to, so a
program serving one tenant can set it once instead of passing it. basePath
defaults to https://api.hanzo.ai.
GET /v1/models needs no credential, so it runs before you have a key. It
returns nothing to decode — the document states that route's address and not its
shape — so call getModelsWithRequestBuilder(...).execute() and read the
response when you need the body. Operations the document does describe return
their model.
One class per tag under Sources/Hanzo/APIs, request and response types under
Sources/Hanzo/Models. Method names are the document's operation ids, so
GET /v1/billing/balance is getBillingBalance and a path parameter reads as
by: GET /v1/kv/{name} is getKvByName(name:).
Auth
One scheme, a bearer token — an IAM access token or a Cloud API key (sk-
secret, pk- publishable). It goes in Authorization, and every operation
sends it except four: getModels, getModelsProviders, getCommands,
getOpenapiJson.
Errors
A non-2xx throws ErrorResponse.error(Int, Data?, URLResponse?, Error) — the
status, the body, and the response.
Examples
Two flows under examples/, a package of their own so the client's
manifest stays the generator's:
swift build --package-path examples
swift run --package-path examples models # no credential
HANZO_API_KEY=sk-... swift run --package-path examples hello
models calls the open route and prints the catalogue; hello calls
GET /v1/tools, which refuses without a credential — that is what makes it the
proof. HANZO_BASE_URL points either somewhere other than api.hanzo.ai.
The build compiles both against the client, so a document change that renames or drops an operation goes red here.
Regenerate
Sources/Hanzo and Package.swift are generated and replaced wholesale. To
change a name in the output, change the swift row of
hanzoai/openapi sdks.yaml.
OPENAPI=/path/to/openapi SPEC=/path/to/openapi.yaml ./scripts/generate.sh
OPENAPI=/path/to/openapi SPEC=/path/to/openapi.yaml ./scripts/generate.sh --check
Docs
docs.hanzo.ai for the API itself.
License
Apache-2.0. See LICENSE.