diff --git a/docs/api/authentication.md b/docs/api/authentication.md index a6f4d55..b8c06ca 100644 --- a/docs/api/authentication.md +++ b/docs/api/authentication.md @@ -191,7 +191,7 @@ export TRAKRF_API_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ## Testing connectivity -Once you have a key, verify it with the interactive reference at [`/api`](/api) — click any endpoint's **Try it** button and paste your key. Or curl: +Once you have a key, verify it with curl: ```bash curl -i -H "Authorization: Bearer $TRAKRF_API_KEY" \ diff --git a/docs/api/changelog.md b/docs/api/changelog.md index fb3a84a..c3f616f 100644 --- a/docs/api/changelog.md +++ b/docs/api/changelog.md @@ -11,6 +11,14 @@ This log records changes to the TrakRF public API under `/api/v1/` that affect i Initial public API release. Stable contract for paths, field names, response shapes, and error envelopes per the [v1 stability commitment](./versioning). +### BB1 hygiene — Try-it wording dropped, `invalid_context` added to versioning open-enums list, `datamodel-codegen` version string unmangled + +Three docs hygiene items from the BB1 post-launch-asset-location-removal black-box cycle. All pre-launch presentation-layer corrections; no service behavior change. + +- **"Try it" / "try-it-now widget" wording removed from [Authentication → Testing connectivity](./authentication#testing-connectivity) and [Quickstart → Next steps](./quickstart#next-steps).** Both pages previously pointed integrators at a Try-it button on the [interactive reference](/api), but `/api` renders with Redoc — a read-only reference with no request console. The auth page now leads with the curl recipe directly; the quickstart's interactive-reference bullet drops the widget claim. Swapping to a console-bearing renderer (Swagger UI / Scalar) is a separate product decision out of scope for this hygiene pass. +- **`invalid_context` added to the [Versioning → Open (extensible) enums in v1](./versioning#open-extensible-enums-in-v1) field-code list.** The page enumerated 10 of the 11 current `FieldErrorCode` values — the [BB62-introduced](#bb62-fix-wave--body-decode-failures-normalized-to-validation_error-new-invalid_context-code-for-known-field-wrong-context-rejections-x-package-name-spec-extension-ancestors-ordering-prose-fix) `invalid_context` code was missing. An integrator building an exhaustive matcher from the versioning page would silently omit a real code emitted in production. The full set is now on the page and matches both the [errors catalog](./errors#validation-errors) and the spec enum. +- **`datamodel-codegen` version string normalized on [Design notes](./design-notes) and [Quickstart → Raw spec for codegen](./quickstart#5-raw-spec-for-codegen).** The pinned version was rendered with a bare `@` between the package name and the SemVer, which the docs origin's Cloudflare email-obfuscation pass rewrote to a `[email protected]` placeholder for raw-HTML, no-JS, view-source, reader-mode, and scraper consumers — exactly the automated-integrator audience the API targets. The pages now write the package and version separated by a space, so the load-bearing fact (which version is known-broken) survives obfuscation. Disabling the Cloudflare rule on the docs path is a config change tracked separately and not required for this fix. + ### Asset current location removed from the asset resource An asset's current location is fact data — derived from the scan-event stream — not a dimension attribute the asset resource carries. `location_id` and `location_external_key` are removed from the asset response shape and from the `GET /api/v1/assets` filter surface; current location is read from the scan-data endpoints, and `POST` / `PATCH` reject the two fields uniformly on presence. The reporting endpoints (`/reports/asset-locations`, `/assets/{id}/history`) are unchanged — they remain the system of record for asset location. Pre-launch contract change; no `v1.0.0`-or-later wire baseline to break. diff --git a/docs/api/design-notes.md b/docs/api/design-notes.md index 2cdd75d..e6236af 100644 --- a/docs/api/design-notes.md +++ b/docs/api/design-notes.md @@ -33,7 +33,7 @@ We're on OpenAPI 3.0.3. Nullable response fields use `nullable: true` rather tha Generator behavior varies: - **Verified-working:** `openapi-typescript@7.x` (emits `string | null`) and `openapi-generator-cli` python target (emits `Optional[StrictStr]`). Both round-trip CRUD against null-bearing responses unmodified. -- **Known-broken:** `datamodel-codegen@0.57.0` emits nullable fields as non-Optional required types. Pydantic validation fails on every nullable field that's actually `null`. +- **Known-broken:** `datamodel-codegen` 0.57.0 emits nullable fields as non-Optional required types. Pydantic validation fails on every nullable field that's actually `null`. For integrators using `datamodel-codegen`, switch to one of the verified-working targets, or apply `--use-annotated --use-union-operator` flags with custom post-processing. diff --git a/docs/api/quickstart.mdx b/docs/api/quickstart.mdx index 43d39bf..c715cba 100644 --- a/docs/api/quickstart.mdx +++ b/docs/api/quickstart.mdx @@ -187,7 +187,7 @@ The bare-form `/openapi.yaml` and `/openapi.json` at the app origin also resolve The spec declares its security scheme as `BearerAuth` (HTTP Bearer, JWT format), so class-emitting generators surface the credential as a Bearer access token — `openapi-generator-cli`'s `typescript-fetch` target produces a `Configuration` with an `accessToken` field, and the Java/Python targets follow the same shape. The wire format remains `Authorization: Bearer `; pass the API key minted in step 2 wherever the generated client expects an access token. :::tip Verified-working codegen targets -TrakRF spec round-trips end-to-end against `openapi-typescript@7.x` (TypeScript types feeding `openapi-fetch`), `openapi-generator-cli` python (`Optional[...]` for every nullable read field), and the typescript / Java targets from the same generator. If you reach for `datamodel-codegen` (Pydantic from OpenAPI), be aware that `datamodel-codegen@0.57.0` emits `nullable: true` read-shape fields as **non-Optional** required types, so Pydantic raises `ValidationError` on every nullable field that actually comes back `null` (`deleted_at` on every resource, `valid_to`, and the location `parent_id` / `parent_external_key` pair). Either switch to the `openapi-generator-cli` python target or run `datamodel-codegen` with `--use-annotated --use-union-operator` plus a post-processing pass that wraps nullable fields in `Optional[…]`. The same note lives on the [interactive reference's intro](/api). +TrakRF spec round-trips end-to-end against `openapi-typescript@7.x` (TypeScript types feeding `openapi-fetch`), `openapi-generator-cli` python (`Optional[...]` for every nullable read field), and the typescript / Java targets from the same generator. If you reach for `datamodel-codegen` (Pydantic from OpenAPI), be aware that `datamodel-codegen` 0.57.0 emits `nullable: true` read-shape fields as **non-Optional** required types, so Pydantic raises `ValidationError` on every nullable field that actually comes back `null` (`deleted_at` on every resource, `valid_to`, and the location `parent_id` / `parent_external_key` pair). Either switch to the `openapi-generator-cli` python target or run `datamodel-codegen` with `--use-annotated --use-union-operator` plus a post-processing pass that wraps nullable fields in `Optional[…]`. The same note lives on the [interactive reference's intro](/api). ::: :::note Repeatable query parameters in typed clients @@ -252,7 +252,7 @@ If your key was minted without `tracking:read`, the calls return `403 forbidden` ## Next steps -- [Interactive reference](/api) — every endpoint, request/response shape, try-it-now widget +- [Interactive reference](/api) — every endpoint, request/response shape - [Authentication](./authentication) — scopes, key lifecycle, rotation - [Pagination, filtering, sorting](./pagination-filtering-sorting) — conventions for list endpoints - [Resource identifiers](./resource-identifiers) — canonical `id`, natural-key `external_key`, and the `?external_key=` list filter diff --git a/docs/api/versioning.md b/docs/api/versioning.md index 1119520..84c19b0 100644 --- a/docs/api/versioning.md +++ b/docs/api/versioning.md @@ -54,7 +54,7 @@ These enum sets will not grow within v1: These are designed to grow: - **Error `type`** (`ErrorResponse.error.type`) — marked `x-extensible-enum: true` in the spec. Current values are documented in the [errors catalog](./errors#error-type-catalog); future values may appear in any v1 release. Clients should branch on HTTP status (closed) for retry/alerting policy and treat unknown `type` values as generic errors of that status class. -- **Validation field codes** (`fields[i].code` on `validation_error` responses) — current set is `required`, `invalid_value`, `unknown_field`, `too_short`, `too_long`, `too_small`, `too_large`, `fk_not_found`, `ambiguous_fields`, `read_only`. New codes may appear. Treat unknown codes as generic invalid-value and surface the `message` field. +- **Validation field codes** (`fields[i].code` on `validation_error` responses) — current set is `required`, `invalid_value`, `unknown_field`, `invalid_context`, `too_short`, `too_long`, `too_small`, `too_large`, `fk_not_found`, `ambiguous_fields`, `read_only`. New codes may appear. Treat unknown codes as generic invalid-value and surface the `message` field. - **Scope strings** (keys on API-key responses, scope columns in the UI) — TrakRF may introduce new scopes (e.g. `reports:read`, `webhooks:write`) in any v1 release. Clients that display the list of scopes available to a key must render unknown scope strings as-is rather than filtering them out. - **`tag_type` discriminator** (`Tag.tag_type` on every tag variant; the `oneOf` discriminator mapping) — current values are `rfid`, `ble`, `barcode`. New variants may be added as additive minor revisions; integrators should treat unknown variants as forward-compatible and pass them through untouched. See [Resource identifiers → Tag is a polymorphic resource](./resource-identifiers#tag-is-a-polymorphic-resource).