Kubb for the Sume OpenAPI spec: Zod schemas and SWR hooks

Kubb parses an OpenAPI spec once and feeds plugins for TypeScript, Zod and SWR. Here is how that maps to Sume's 3.0.3 spec, jobs and the polling stop rule.

5 min readSume
All posts

The answer

Kubb's home page describes an adapter that parses an API spec into a shared AST, and plugins that consume it: TypeScript, Axios, Fetch, React Query, Vue Query, SWR, Zod, Faker, MSW and MCP among them. Run it with npx kubb generate. For Sume, feed it the OpenAPI document and enable the TypeScript, Zod and SWR plugins to get types, runtime validators and polling hooks from one source.

The value of the Zod plugin is that a status payload is checked at the boundary, not only typed. The value of the SWR plugin is a hook per operation that you can combine with a function-valued refreshInterval.

Which plugin does what

Kubb lists these as separate plugins on the same page, so you can adopt them one at a time. Starting with types alone is a safe first step.

Kubb plugins and how they pair with Sume (read 2026-10-03)
PluginOutputSume use
TypeScriptTypes from the specJob, status and error shapes
ZodZod schemasValidate status and result bodies
SWRSWR hooksPoll a job until terminal
MSWRequest handlersMock Sume in front-end tests
FakerFake dataSeed fixtures from the schemas

Using the generated pieces for a job

A Sume submit returns status_url, result_url, terminal and result_ready fields. With the Zod schema in front of the status call, a malformed or changed payload fails loudly at the edge instead of producing an undefined deep in the UI.

In the SWR hook, return 0 from the interval function when terminal is true and the suggested next_poll_after_seconds times 1000 otherwise. Our SWR polling post shows the interval rule in detail.

Spec caveats

Sume's OpenAPI is 3.0.3, with fields marked nullable: true rather than 3.1 type unions. Check that your generated Zod schema uses .nullable() for next_poll_after_seconds and retry_after_seconds. If it emits a plain number you will get a parse failure on exactly the terminal responses you care about most.

Creates also take an Idempotency-Key header parameter. Generated clients usually expose header parameters as an options argument; set it from your business intent, not from a random value per call.

Keep generation reproducible

Commit the spec file you generated from, record the date you fetched it, and rerun Kubb in CI to detect drift. That turns an API change into a reviewable diff of generated files rather than a production surprise.

A practical rollout order

Start with the TypeScript plugin alone and compile your app against it. Add Zod next, and use it only on the two responses that drive control flow: the create response and the status response. Add SWR last, once the schemas are stable, so the hook's data type is already the validated one.

Resist generating everything for all 183 operations if you call five of them. A smaller generated tree, which you can get by trimming the spec to the operations you use, is quicker to review and to rebuild when the spec moves.

For tests, the MSW and Faker plugins listed on the same page let you serve fake job statuses in a browser or Node test. Script three responses in a row, non-terminal twice and then terminal with result_ready true, and assert that the hook stops polling after the third.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume