sveltekit-openapi-remote
v0.1.6
Published
Generate SvelteKit remote functions directly from OpenAPI/Swagger specs.
Maintainers
Readme
sveltekit-openapi-remote
Generate typed SvelteKit remote functions (query, command, form) directly from OpenAPI specs. Point it at your API spec and get ready-to-use server functions with full type safety.
How it works
- You provide an OpenAPI spec (URL, file path, or pre-generated
api.d.ts) - The CLI generates TypeScript types via openapi-typescript
- It parses those types and generates SvelteKit remote function files
- Your app imports these generated functions and uses them with full type safety
The generated functions use SvelteKit's query(), command(), and form() from $app/server, wired up to your API through openapi-fetch.
Installation
npm install sveltekit-openapi-remote
# or
pnpm add sveltekit-openapi-remotePeer dependencies
These are required in your SvelteKit project:
npm install openapi-fetch zod
# openapi-typescript is only needed if using --spec (optional)
npm install -D openapi-typescriptQuick start
1. Set up your openapi-fetch client
// src/lib/api/client.ts
import createClient from 'openapi-fetch';
export const client = createClient({
baseUrl: 'https://api.example.com',
});2. Initialize the remote handlers
// src/lib/api/remote.ts
import { createRemoteHandlers } from 'sveltekit-openapi-remote';
import { client } from './client';
export const {
handleGetQuery,
handlePostCommand,
handlePatchCommand,
handlePutCommand,
handleDeleteCommand,
handlePostForm,
handlePatchForm,
handlePutForm,
handleDeleteForm,
} = createRemoteHandlers(client);3. Generate remote functions
# From an OpenAPI spec URL
npx sveltekit-openapi-remote generate \
--spec https://petstore3.swagger.io/api/v3/openapi.json \
--output src/lib/remote/generated \
--client '$lib/api/remote'
# From a local spec file (JSON or YAML)
npx sveltekit-openapi-remote generate \
--spec ./openapi.yaml \
--output src/lib/remote/generated \
--client '$lib/api/remote'
# From an existing api.d.ts (skip openapi-typescript step)
npx sveltekit-openapi-remote generate \
--types-path src/lib/types/api.d.ts \
--output src/lib/remote/generated \
--client '$lib/api/remote'4. Use in your SvelteKit app
<!-- src/routes/pets/+page.svelte -->
<script>
import { getPetFindByStatus } from '$lib/remote/generated/pet.remote';
let pets = $derived(getPetFindByStatus({ query: { status: 'available' } }));
</script>CLI reference
npx sveltekit-openapi-remote generate [options]Options
| Option | Required | Description |
|--------|----------|-------------|
| --spec <path\|url> | * | OpenAPI spec file or URL. Runs openapi-typescript to generate types. |
| --types-path <path> | * | Path to an existing api.d.ts file. Skips type generation. |
| --output <dir> | Yes | Output directory for generated files. |
| --client <path> | Yes | Import path to your initialized handlers file (e.g. $lib/api/remote). |
| --grouping <mode> | No | "segment" (default) or "single". Controls file output. |
| --depth <n> | No | Segment depth for grouping (default: 1). Only used with --grouping segment. |
| --dry-run | No | Preview what files would be generated without writing. |
| --quiet | No | Suppress all output except errors. Useful for CI. |
| --help | No | Show help text. |
* Must provide either --spec or --types-path, not both.
--spec vs --types-path
Use --spec when you want the CLI to handle everything — it runs openapi-typescript internally and writes api.d.ts to the output directory.
Use --types-path if you already generate your api.d.ts separately (e.g. as part of your build pipeline) and just want the remote function generation.
--grouping and --depth
Controls how generated functions are split across files.
--grouping segment --depth 1 (default) groups by the first URL segment:
src/lib/remote/generated/
├── api.d.ts
├── pet.remote.ts # /pet, /pet/{petId}, /pet/findByStatus, ...
├── store.remote.ts # /store/inventory, /store/order, ...
└── user.remote.ts # /user, /user/{username}, /user/login, ...--grouping segment --depth 2 groups by the first two non-parameter segments:
src/lib/remote/generated/
├── api.d.ts
├── pet.remote.ts
├── pet-findByStatus.remote.ts
├── pet-findByTags.remote.ts
├── store-inventory.remote.ts
├── store-order.remote.ts
├── user.remote.ts
├── user-createWithList.remote.ts
├── user-login.remote.ts
└── user-logout.remote.ts--grouping single puts everything in one file:
src/lib/remote/generated/
├── api.d.ts
└── api.remote.ts--client
The import path that generated files will use to import your handlers. This should match how your SvelteKit project resolves imports — typically a $lib alias:
--client '$lib/api/remote'The generated files will contain:
import {
handleGetQuery,
handlePostCommand,
// ...
} from '$lib/api/remote';What gets generated
For each endpoint in your OpenAPI spec, the CLI generates typed SvelteKit remote functions:
| HTTP Method | Has Path Params | Generated Functions |
|-------------|----------------|---------------------|
| GET | any | query() |
| POST | no | command() + form() |
| POST | yes | command() + form() with { path, body } |
| PATCH | no | command() + form() |
| PATCH | yes | command() + form() with { path, body } |
| PUT | no | command() + form() |
| PUT | yes | command() + form() with { path, body } |
| DELETE | any | command() + form() |
Function naming
- HTTP method as prefix:
get,post,put,patch,delete - Path segments in camelCase:
/store/orderbecomesStoreOrder - Path parameters become
By{Param}:/pet/{petId}becomesPetByPetId - Mutations get
CommandandFormsuffixes
Examples:
| Endpoint | Generated name |
|----------|---------------|
| GET /pet/findByStatus | getPetFindByStatus |
| GET /pet/{petId} | getPetByPetId |
| POST /pet | postPetCommand, postPetForm |
| DELETE /store/order/{orderId} | deleteStoreOrderByOrderIdCommand, deleteStoreOrderByOrderIdForm |
| PUT /user/{username} | putUserByUsernameCommand, putUserByUsernameForm |
Example output
For the Petstore API, the generated store.remote.ts looks like:
import { query, command, form } from '$app/server';
import { z } from 'zod';
import type { paths } from './api';
import { type GetParameters, type GetRequestBody } from 'sveltekit-openapi-remote';
import {
handleDeleteCommand,
handleDeleteForm,
handleGetQuery,
handlePostCommand,
handlePostForm,
} from '$lib/api/remote';
/**
* Auto-generated remote functions
* DO NOT EDIT - Run 'npx sveltekit-openapi-remote generate' to regenerate
*/
export const getStoreInventory = query(
z.custom<GetParameters<paths, '/store/inventory', 'get'>>(),
async (params) => handleGetQuery('/store/inventory', params)
);
export const postStoreOrderCommand = command(
z.custom<GetRequestBody<paths, '/store/order', 'post'>>(),
async (body) => handlePostCommand('/store/order', body)
);
export const postStoreOrderForm = form(
z.custom<GetRequestBody<paths, '/store/order', 'post'>>(),
async (body) => handlePostForm('/store/order', body)
);
export const getStoreOrderByOrderId = query(
z.custom<GetParameters<paths, '/store/order/{orderId}', 'get'>>(),
async (params) => handleGetQuery('/store/order/{orderId}', params)
);
export const deleteStoreOrderByOrderIdCommand = command(
z.custom<GetParameters<paths, '/store/order/{orderId}', 'delete'>>(),
async (params) => handleDeleteCommand('/store/order/{orderId}', params)
);
export const deleteStoreOrderByOrderIdForm = form(
z.custom<GetParameters<paths, '/store/order/{orderId}', 'delete'>>(),
async (params) => handleDeleteForm('/store/order/{orderId}', params)
);Regeneration
Running the generator again will:
- Delete previously generated
.remote.tsfiles (identified by theDO NOT EDITheader) - Preserve any hand-written
.remote.tsfiles you've added - Write the new generated files
Add the generate command to your package.json scripts:
{
"scripts": {
"generate:api": "sveltekit-openapi-remote generate --spec https://api.example.com/openapi.json --output src/lib/remote/generated --client '$lib/api/remote'"
}
}Error handling
The runtime handlers throw SvelteKit errors automatically:
- No response (network failure) throws
error(503) - API error response throws
error(statusCode)with the error message - No data returned throws
error(404)
Requirements
- Node.js 20+
- SvelteKit 2.x
- openapi-typescript 7.x (only if using
--spec) - openapi-fetch
- zod 3.x
License
MIT
