v5.0.0
Breaking changes
Flattened client action arguments
Generated client methods now take semantic route input as the first argument and fetch options as the second argument.
Before:
await client.hello({
path: { name: 'world' },
query: { excited: true },
headers: { 'x-request-id': 'abc' },
signal,
})After:
await client.hello(
{ name: 'world', excited: true },
{ headers: { 'x-request-id': 'abc' }, signal }
)Path params, query params, and JSON object body fields are flattened into the first input object. RequestInit options and request headers belong in the second options object.
This also updates client response plugin request metadata: ClientResponsePluginRequest now exposes input and options directly instead of nesting them under args.
Mutation body schemas must be Zod objects
JSON mutation body schemas are now restricted to z.ZodObject. This is required so the client can pick body fields out of the flattened input object before validating and JSON encoding the request body.
If you need to send a non-object payload, use the new http.rawBody() marker described below.
New features
Raw request bodies
Added http.rawBody() for routes that need to pass a body through to fetch without JSON encoding, such as binary uploads, images, streams, FormData, or text payloads.
import * as http from 'rouzer/http'
export const uploadAvatar = http.post('avatars/:id', {
body: http.rawBody(),
})Client usage:
await client.uploadAvatar(
{ id: 'user-123' },
{ body: imageBytes }
)Raw body routes:
- read path params from the first
inputargument - read the raw fetch body from
options.body - pass the body to
fetchunchanged - skip client-side JSON stringification
- skip server-side JSON body parsing, so handlers can read from
requestdirectly with APIs likearrayBuffer(),blob(),formData(), ortext()
Migration guide
Client calls with path/query/body
Replace nested path, query, and body objects with a single flat input object.
// v4
await client.users.update({
path: { id: '42' },
body: { name: 'Grace' },
})
// v5
await client.users.update({ id: '42', name: 'Grace' })Client calls with request options
Move request options to the second argument.
// v4
await client.search({
query: { q: 'rouzer' },
headers: { authorization: token },
signal,
})
// v5
await client.search(
{ q: 'rouzer' },
{ headers: { authorization: token }, signal }
)Request-level headers remain optional because headers can still be supplied as createClient({ headers }) defaults.
Non-object request bodies
Replace non-object Zod body schemas with http.rawBody() and pass the payload via options.body.
// v5
export const upload = http.post('upload', {
body: http.rawBody(),
})
await client.upload(undefined, { body: file })