Skip to content Documentation index for agents (llms.txt)
Glotto Beta
Get started

glotto.yml client behavior

Optional keys

client_settings

client_settings:
  default_timeout: 60s          # per-request overall timeout (default: 30s)
  retry:
    max_attempts: 3
    initial_delay: 200ms
    max_delay: 8s
    jitter: true
    max_elapsed: 90s            # optional overall wall-clock retry deadline
  auth:
    scheme: bearer
    env_var: ACME_API_KEY
    header_prefix: Token        # Authorization: Token <cred> (default: Bearer)
    schemes:                    # per-scheme overrides, keyed by OpenAPI scheme name
      AdminKey:
        env_var: ACME_ADMIN_KEY
      DpopAuth:
        header_prefix: DPoP     # Authorization: DPoP <cred> for this scheme only
  idempotency: true             # or { enabled: true, header: X-Idempotency-Key }
  telemetry_headers: true       # send X-Glotto-Retry-Count + X-Glotto-Timeout

SDK runtime defaults. default_timeout bounds each request attempt in every generated SDK — a duration string (60s, 500ms), defaulting to 30 seconds when unset; see Retries & timeouts for how per-call and per-client overrides compose with it. See Retries & timeouts for the retry block, Authentication for auth, and Idempotency keys for idempotency (a boolean, or an object that customizes the injected header name). telemetry_headers (off by default) makes every request carry X-Glotto-Retry-Count and X-Glotto-Timeout, so your server can see the client’s retry state and timeout budget.

auth.scheme / auth.env_var / auth.header_prefix describe the API’s single security scheme. When your spec declares several — a default token plus a per-endpoint admin key, say — auth.schemes sets the same knobs per scheme, keyed by the scheme name as written in the OpenAPI securitySchemes. env_var names the environment variable that scheme’s credential falls back to, and header_prefix sets its Authorization keyword; both are optional, and a scheme you don’t list keeps the defaults. header_prefix applies to bearer and oauth2 schemes — the ones with an Authorization keyword to vary — and is ignored on apikey, basic, and custom.

The two levels combine, and the two keys reach different schemes on purpose:

  • auth.header_prefix applies to every bearer/oauth2 scheme, so an API that frames all its bearer credentials as Token needs one line rather than an entry per scheme.
  • auth.env_var applies only to the schemes in your spec’s global security requirement. A per-endpoint scheme is a different credential, so it is never given the default scheme’s environment variable — name its own under auth.schemes instead.

A per-scheme value always wins over the top-level one, so header_prefix: Token alongside schemes.DpopAuth.header_prefix: DPoP gives DpopAuth the DPoP keyword and every other bearer-style scheme Token.

default_request_options

Use resource defaults for related calls and method defaults for an exception such as a slow export:

resources:
  exports:
    default_request_options:
      headers:
        X-Export-Route: archive
      timeout: 30s
    methods:
      slowExport:
        endpoint: get /exports/{exportId}
        default_request_options:
          timeout: 120s
          max_retries: 0

Resources, nested subresources and object-form methods accept headers, timeout and max_retries. A timeout must be a positive duration. The retry count must be a nonnegative integer; zero disables retries. Header names are matched without regard to case, and duplicate names in one declaration are rejected.

Each option resolves from the per-call override, then the method, nearest resource, client and generated default. Headers merge across those levels; a more specific value replaces the same header without discarding unrelated headers. A nested resource inherits values it does not set. For SSE, NDJSON and binary downloads, the timeout bounds opening through the first byte or EOF; it does not terminate an established stream. Cancellation and explicit close remain available.

These settings affect generated SDK requests. They do not alter the API specification or its breaking-change classification. Each declaration must address an existing endpoint; a resource with defaults must contain method declarations, directly or beneath a subresource.

transforms

transforms:
  - rename_schema: { from: InvoiceDTO, to: Invoice }
  - dedupe_inline_objects: { threshold: 2 }

An ordered list of in-config OpenAPI rewrites. See the Transforms reference for every transform and its arguments.

naming & parameter_naming

naming:                  # per-language member renames: model → wire property → target → identifier
  Widget:
    public: { java: isPublic }
  User.address:          # dot-path: rename a NESTED inline-object property (User.address.zipCode)
    zipCode: { python: zip_code }
parameter_naming:        # per-language parameter renames: operation → wire param → target → identifier
  listWidgets:
    class: { python: cls }

Rename a model property (naming) or a method parameter (parameter_naming) for a specific target language when the wire name collides with that language’s keywords — the wire name is preserved for serialization.

A naming key may be a dot-path (Model.field[.field…]) to address a property on a nested inline object: the first segment is a named model and each later segment is an object field (or an array-of-object field) that resolves to a deeper object. So User.address with property zipCode renames User.address.zipCode without naming the generator’s synthesized model. A path that doesn’t resolve against the current spec is ignored (like an unknown plain model), so a config can outlive a schema change.

custom_casings

custom_casings:          # declared initialisms: lowercase word → how to render it
  api: API               # getApiKey → getAPIKey
  id: ID                 # widgetId  → widgetID
  url: URL

Declare the initialisms your API uses, so generated identifiers render them the way your team writes them rather than the way a naive word-splitter would. Identifier words are lowercased before matching, so the key is always the lowercase form — api, never API.

The rendering must be a pure re-casing of the key: only letter case may differ. Changing the word itself is a rename, and belongs in naming (model members) or parameter_naming (method parameters). A key that is not a lowercase alphanumeric word, or a rendering that is not a re-casing of its key, is reported as GLOTTO_CONFIG_CUSTOM_CASINGS.

It does not reach every identifier yet. Casings are applied where the IR carries a per-language identifier — model members, method parameters, and enum constants — and not to method names, class and type names, or resource accessors. Declaring { api: API } and still reading getApiKey is that gap, not a mistake in your config; Glotto reports it as GLOTTO_CONFIG_CASING_NOT_APPLIED rather than letting you discover it in the emitted SDK.

positional_params

positional_params:       # per-language argument order: operation → target → wire param names
  getRepo:
    typescript: [repoId, orgId]   # getRepo(repoId, orgId, options?) instead of (orgId, repoId, …)
    go: [repoId]                  # PARTIAL: name the first, the rest keep their derived order

Override the order a method’s positional path arguments are emitted in, for one target language. Useful when your API reads more naturally in another order, or when you are migrating from a hand-written SDK whose signature your users already call.

Name the parameters by their wire name (the {placeholder} in the path), not the emitted identifier — so one entry means the same thing in every language, and it keeps working if you also rename the parameter with parameter_naming.

The list is a prefix: any path parameter you do not name keeps its derived position behind the ones you do, so naming just the first argument is a complete declaration.

It is per target language on purpose, because the languages genuinely differ — Ruby’s arguments are keyword arguments, Go leads with ctx and Elixir with client, and Swift labels every argument at the call site. Reordering never changes the request: the URL, query string, and headers are built from the wire names and are byte-identical whichever order you declare.

An entry naming something that is not one of that operation’s path parameters — or naming one twice — is reported and the whole entry is ignored, so the method keeps its derived order rather than a half-applied one you never reviewed. Reordering the request body relative to the path arguments is not supported yet.

enum_naming

enum_naming:             # per-enum-value renames: enum model → wire value → identifier
  StatusCode:
    "200": Ok            # one LOGICAL name, cased per language (Rust `Ok`, Java `OK`, Swift `ok`)
    "404": NotFound
  Kind:
    "in-progress": { java: RUNNING }   # or pin the identifier per target

Rename the constant an enum value is emitted as. The wire value is always preserved for serialization — only the language identifier changes. A value key is the value’s string form, so a numeric 200 is written "200".

Most specs need no entry here: values whose derived identifier would be illegal in a target language — a leading digit (2xx, 200), punctuation (in-progress, n/a), or a language keyword — are repaired automatically, so generation always produces compiling code. Use enum_naming when you want a meaningful name (Ok) rather than the derived one.

The bare-string form is one logical name that each language cases idiomatically; the object form pins an exact identifier for specific targets. elixir, typescript, and react_native emit no enum constant (they use string lists and literal unions), so entries for them have no effect.