Skip to main content
The Vertz codegen produces a fully typed SDK from your entity and service definitions. Every method returns a Result — no thrown exceptions for HTTP errors. SDK methods plug directly into query() and form().

Creating the client

The codegen generates createClient() based on your entity definitions. Each entity becomes a property on the client with typed CRUD methods.

Entity methods

Read methods return QueryDescriptor

Calling .list() or .get() returns a QueryDescriptor — not a raw Promise. This descriptor carries the fetch function, a deterministic cache key, and entity metadata. Pass it directly to query():
Two components calling api.tasks.list({ status: 'todo' }) share the same cache entry — the cache key is derived from the HTTP method, path, and sorted query parameters.

Mutation methods work with form()

Pass a mutation method (.create, .update) to form(). The codegen attaches the entity’s validation schema to the method metadata, so form() picks it up automatically:

Result type

Every SDK method returns Result<T, FetchError> — a discriminated union, never a thrown exception.

Checking results

Error status codes

When result.ok is false, result.error has a status property matching the HTTP response:

Handling errors in SDK calls

SDK methods never throw for HTTP errors. Always check result.ok before accessing result.data. If you await a QueryDescriptor directly (outside of query()), you get a Result back — not the data directly.

QueryDescriptor vs await

A QueryDescriptor is PromiseLike — you can await it directly for one-off calls. But for reactive UI, always use query():

List responses

List endpoints return ListResponse<T>:

Invalidation

After a mutation, invalidate related queries to trigger a refetch: