API collections
voltro build api --target postman | bruno | insomnia | hoppscotch — a collection from the same pipeline as the SDKs, with environments, auth, examples, saved error responses and tests; and publicApi.artifacts, so voltro dev keeps it written beside rpcGroup.generated.ts.
Before anyone programs against /v1, somebody clicks through it — in Postman, Bruno, Insomnia or Hoppscotch. All four import OpenAPI, and what the import cannot bring is exactly what every consumer then adds by hand: the environments, the auth on the collection, the example bodies, the saved error responses, the tests. voltro build api --target <tool> writes those from the same pipeline that generates the TypeScript client and the native SDKs: bindings in, a consumer artifact out.
Generate
voltro build api --target postman --out ./api-collections --name awb
voltro build api --target bruno --out ./api-collections --name awb
voltro build api --target insomnia --out ./api-collections --name awb
voltro build api --target hoppscotch --out ./api-collections --name awb| Target | Writes |
|---|---|
postman |
<name>.postman_collection.json (v2.1) and <name>.<env>.postman_environment.json per server. |
bruno |
<name>.bruno/ — bruno.json, collection.bru, a folder per tag with one .bru per request, environments/<env>.bru. The variant that diffs in git. |
insomnia |
<name>.insomnia.yaml — the v5 export with the collection, environments and a cookie jar. |
hoppscotch |
<name>.hoppscotch.json and <name>.<env>.hoppscotch_environment.json per server. |
What every collection carries
One model, four serializers — the content is the same in all four:
- A folder per tag (
teams), with the tag's description andexternalDocslink; a request per projection, named bysummary, documented bydescriptionas Markdown, with the API version in the docs. - Path parameters as
:teamId/{{ _.teamId }}/<<teamId>>with the example value; query parameters from the input, optional ones disabled by default. - The body from
publicApi.example.request— or the derived one, marked in the docs as derived, so nobody takes a valid shape for the author's word. - A saved response for the
200and one pererrorStatusentry,application/problem+jsonwith the realurn:voltro:error:<Tag>. - Auth on the collection:
bearer {{apiKey}}; every request inherits it. Asecurity: 'optional'projection still inherits, and its docs say it works without a token;security: falsesends none. Idempotency-Key(a generated UUID per attempt) on every mutation whose descriptor saysidempotent: true.- One environment per
serversentry —baseUrl, a secretapiKey,apiVersion— so switching tov2or to staging is one variable. - A test per request that asserts what the spec cannot say: the request succeeded (a generated request is a happy path built from the example, so a non-2xx is a failure of the API — without this a collection stays green against a server answering 500 to everything), a 2xx decodes against the response schema (Postman validates the JSON Schema; the others check the required fields), an error is
application/problem+jsonwhosetypestarts withurn:voltro:error:and whosestatusmatches, a429carriesRetry-AfterandRateLimit-Reset, aGETunder an ETag profile carries anETag.
That makes the collection the smoke test against a running instance:
newman run awb.postman_collection.json -e awb.staging.postman_environment.json --env-var apiKey=$API_KEY
bru run --env staging --env-var apiKey=$API_KEY awb.brunoWritten by voltro dev
// app.config.ts
export default defineApi({
publicApi: { profile: 'standard', artifacts: ['openapi', 'postman', 'bruno'] },
})With artifacts, every voltro dev boot writes openapi.generated.json and the named collections beside rpcGroup.generated.ts — and, with 'typescript' in the list, the generated TypeScript client package as the app's publicApi.client declares it — <app>.generated.postman_collection.json, <app>.generated.bruno/, … — touching only files whose content changed. The .generated. segment is the watcher's rule for codegen output, so a rewrite never restarts the boot that wrote it. Commit them: a review diff then shows the surface change as a change to the collection, Bruno opens the folder from the repository, Postman watches the file. A collection somebody imported once drifts; one the dev loop writes cannot. voltro serve writes nothing.
The way without a build
Postman keeps an API definition in sync from a URL, and Hoppscotch and Insomnia import a spec URL — pointed at /openapi.json of a dev instance, that stays current on its own, without environments, auth or tests. Both ways read the same document; the build is the one that brings the rest.