TypeScript Clients
ShipQ automatically generates TypeScript HTTP clients from your handler registry. Every time you run shipq handler compile, ShipQ produces a fully typed client that mirrors your API surface — including request/response types, path parameters, and cookie-based authentication.
Configuration
Section titled “Configuration”TypeScript codegen is controlled by the [typescript] section in shipq.ini:
[typescript]framework = reacthttp_output = .| Key | Description | Default |
|---|---|---|
framework | Which framework helpers to generate alongside the base HTTP client. Options: react, svelte, or omit for plain TypeScript. | react |
http_output | Output directory for generated TypeScript files, relative to your project root. | . |
This section is created automatically by shipq init.
What Gets Generated
Section titled “What Gets Generated”When you run shipq handler compile, ShipQ generates TypeScript files based on your configuration:
Base HTTP Client (always generated)
Section titled “Base HTTP Client (always generated)”The base client is a plain TypeScript module with:
- Typed request/response interfaces for every handler in your API
- A function per endpoint with correct HTTP method, URL construction (including path parameters), request body typing, and response typing
- Cookie-based authentication — requests include
credentials: "include"so the browser sends the session cookie automatically - Error handling with typed error responses
This client has zero framework dependencies — it works with fetch and can be used in any TypeScript environment (browser, Node.js, Deno, Bun, etc.).
React Hooks (when framework = react)
Section titled “React Hooks (when framework = react)”When the framework is set to react, ShipQ additionally generates React-specific hooks that wrap the base HTTP client:
- Query hooks for GET endpoints (data fetching with loading/error states)
- Mutation hooks for POST/PATCH/DELETE endpoints
- Automatic cache invalidation patterns
- TypeScript generics that preserve full type safety through the hook layer
Svelte Hooks (when framework = svelte)
Section titled “Svelte Hooks (when framework = svelte)”When the framework is set to svelte, ShipQ generates Svelte-specific store-based helpers:
- Readable stores for GET endpoints
- Action helpers for mutations
- Typed throughout using the same request/response interfaces
No Framework (omit framework)
Section titled “No Framework (omit framework)”If you omit the framework key or leave it empty, only the base HTTP client is generated. This is useful if you’re using a framework ShipQ doesn’t have specific helpers for, or if you prefer to write your own data-fetching layer on top of the typed client.
Generated File Conventions
Section titled “Generated File Conventions”All generated TypeScript files follow ShipQ’s ownership conventions:
- Files with a
zz_generated_prefix or a// Code generated by shipq. DO NOT EDIT.comment at the top are overwritten on everyhandler compile. Do not hand-edit these. - The generated files are designed to be imported directly into your frontend code.
Using the Generated Client
Section titled “Using the Generated Client”Setting Up
Section titled “Setting Up”Point your frontend’s imports at the output directory configured in http_output. For example, if your frontend lives in a sibling directory:
[typescript]framework = reacthttp_output = ../frontend/src/apiAfter running shipq handler compile, your frontend can import directly:
import { createPet, listPets, getPet } from './api/shipq-http';Making Requests
Section titled “Making Requests”The generated client functions accept typed parameters and return typed responses:
// Create a pet (POST /pets)const newPet = await createPet({ name: "Luna", species: "cat", age: 3,});// newPet is fully typed: { id: string, name: string, species: string, age: number, created_at: string }
// Get a single pet (GET /pets/:id)const pet = await getPet({ id: "abc123" });
// List pets (GET /pets)const pets = await listPets();Authentication
Section titled “Authentication”ShipQ uses cookie-based authentication. The generated client sets credentials: "include" on fetch requests so the browser automatically sends the session cookie with every request. There’s no need to manually manage tokens — once the user logs in (which sets the cookie), all subsequent requests are authenticated:
import { login, listPets } from './api/shipq-http';
// Login sets the session cookie automatically
// Subsequent requests include the session cookie automaticallyconst pets = await listPets();React Hooks Usage
Section titled “React Hooks Usage”When using React hooks, the generated code provides ergonomic data-fetching primitives:
import { useListPets, useCreatePet } from './api/shipq-react';
function PetList() { const { data: pets, isLoading, error } = useListPets(); const createPet = useCreatePet();
if (isLoading) return <div>Loading...</div>; if (error) return <div>Error: {error.message}</div>;
return ( <div> <ul> {pets.map(pet => ( <li key={pet.id}>{pet.name} ({pet.species})</li> ))} </ul> <button onClick={() => createPet.mutate({ name: "New Pet", species: "dog", age: 1 })}> Add Pet </button> </div> );}File Upload Helpers
Section titled “File Upload Helpers”If you’ve run shipq files to set up the file upload subsystem, ShipQ also generates a shipq-files.ts TypeScript helper that provides:
- Typed upload functions for managed file uploads
- Presigned URL handling
- Integration with the base HTTP client’s cookie-based auth layer
Channel / Realtime Helpers
Section titled “Channel / Realtime Helpers”If you’ve run shipq workers to set up the workers and channels system, ShipQ generates a shipq-channels.ts TypeScript client that provides:
- Typed WebSocket channel subscriptions via Centrifugo
- Channel-specific message types
- Connection management and reconnection logic
- Integration with the auth system for authenticated channel subscriptions (uses JWTs for Centrifugo WebSocket auth, separate from the cookie-based HTTP auth)
Type Mapping
Section titled “Type Mapping”ShipQ maps Go types to TypeScript types in the generated client:
| Go Type | TypeScript Type |
|---|---|
string | string |
int, int32, int64 | number |
float32, float64 | number |
bool | boolean |
time.Time | string (ISO 8601) |
*T (pointer) | T | null |
[]T (slice) | T[] |
| Nested struct | Inline interface |
Response types avoid raw int64 values where possible — IDs are typically exposed as string (public IDs) to prevent JavaScript number precision issues.
Regenerating Clients
Section titled “Regenerating Clients”The TypeScript client is regenerated every time you run:
shipq handler compileThis is the same command that regenerates server wiring, OpenAPI specs, and test harnesses. Any new or modified handlers are automatically reflected in the TypeScript client.
If you’ve only changed query definitions (not handlers), you only need shipq db compile. But if handler signatures changed — new fields, new endpoints, changed paths — you need shipq handler compile to update the TypeScript client.
- Commit generated TypeScript files to version control. They’re part of your build output and your frontend developers need them.
- Don’t hand-edit generated files. Customize behavior by wrapping the generated functions in your own modules.
- Use
http_outputto place generated files directly in your frontend’s source tree so imports are clean and your editor gets full type inference. - Check the OpenAPI spec at
GET /openapi(dev/test mode) if you want to verify the API surface that drives TypeScript codegen.