Early alpha Chronicler is pre-release software and changes often. Join the waitlist
Developers

Typed clients

Generate a typed API client from the Chronicler OpenAPI document. One generator per language keeps the models and calls in step with the server, so you never hand-write a request.

The Chronicler API ships a full OpenAPI 3 document. Do not hand-write requests or model types. Point a generator at the document, and it produces typed models and one function per operation for your language. When the API changes, you regenerate, and your compiler shows you every call that moved.

The code samples across these docs, such as the one in Quickstart, call a generated client of this kind.

The OpenAPI document

Every Chronicler server serves its own document. Use it as the generator input.

  • Hosted: https://api.chronicler.one/openapi.json
  • Self-hosted or local: http://127.0.0.1:7777/openapi.json

The document names each operation with a stable operationId, such as relationship.create. Every generator turns that id into the function or method name, so the names stay predictable across languages.

Generate against a running server

The document is served by the API, not committed to a repository. Start the server first, then point the generator at its URL. A CI job that regenerates the client starts the server, or reads a document you export in a build step.

TypeScript (Node & Bun)

Use Orval, just like we do in the frontend application. It reads the document and writes typed fetch functions plus their models.

Generate the TypeScript client

  1. Add Orval as a dev dependency.
  2. Write orval.config.ts with the document URL and the output paths.
  3. Add the mutator file that sets the base URL and the bearer token.
  4. Run bunx orval to write the client. Rerun it after any API change.

The generator writes one function per operation, named from the operationId. So relationship.create becomes relationshipCreate, and it takes the typed body and returns the typed result.

import { relationshipCreate } from "./api-client/endpoints/chronicler"

await relationshipCreate(chronicleId, {
  from: "res_01jq8p9k7mf4rb2xn0z9v6t3wy",
  type: "rel_ally_of",
  to: "res_01jqb2m5x8k7wr4n0z9v6t3sya",
})

Go

Use oapi-codegen. It reads the document and writes a typed client with the request and response models. It is the closest Go match to the Orval setup, since both give you typed models and a thin client with no runtime reflection.

Generate the Go client

  1. Add oapi-codegen as a tool dependency with go get -tool.
  2. Write config.yaml with the package name and what to generate.
  3. Add a //go:generate directive that points at the document URL.
  4. Run go generate ./... to write client.gen.go. Rerun it after any API change.

The generator writes one method per operation on a ClientWithResponses, named from the operationId. So relationship.create becomes RelationshipCreate, and it takes a typed body and a context.

client, err := chronicler.NewClientWithResponses("https://api.chronicler.one")
if err != nil {
    return err
}

_, err = client.RelationshipCreate(ctx, chronicleID, chronicler.CreateRelationshipBody{
    From: "res_01jq8p9k7mf4rb2xn0z9v6t3wy",
    Type: "rel_ally_of",
    To:   "res_01jqb2m5x8k7wr4n0z9v6t3sya",
})
if err != nil {
    return err
}

A fully typed alternative

For a spec-first client with strict validation and no reflection, use ogen. It generates a complete typed client and server from the same document. Prefer oapi-codegen for a lighter client that drops into an existing HTTP setup.

Python

Use openapi-python-client. It writes a typed package with dataclass models and one module per operation.

Generate the Python client

  1. Run the generator against the document URL.
  2. Import the operation module and its typed model.
  3. Build the client with the base URL and the bearer token.
  4. Call the operation. Regenerate after any API change.

Authenticating the client

Every call carries a bearer token in the Authorization header. See Authentication for how to get one, and Service accounts & tokens for a machine identity.

Set the token in one place, not on every call.

  • TypeScript: add it in the Orval mutator, so customFetch attaches it to every request.
  • Go: pass a request editor to NewClientWithResponses that sets the header.
  • Python: pass it in the Client headers, as shown above.

Where to go next