📘️ openapi-typescript-fetch-svelte
A typed fetch client for openapi-typescript compatible with SvelteKit's custom fetch
Installation
npm install @cocreators-ee/openapi-typescript-fetch-svelte
Or
pnpm add @cocreators-ee/openapi-typescript-fetch-svelte
Features
Supports JSON request and responses
Usage
Generate typescript definition from schema
npx openapi-typescript https://petstore.swagger.io/v2/swagger.json --output petstore.ts
Using SvelteFetcher
Configure SvelteFetcher instance and generate functions for making API calls:
import { SvelteFetcher } from '@cocreators-ee/openapi-typescript-fetch-svelte'
import { paths } from './petstore'
const fetcher = Fetcher.for<paths>()
fetcher.configure({
baseUrl: 'https://petstore.swagger.io/v2',
init: {
},
})
export const findPetsByStatus = fetcher
.path('/pet/findByStatus')
.method('get')
.create()
export const addPet = fetcher.path('/pet').method('post').create()
Each API call is represented as a request object that has the following properties:
{
ready,
isLoaded,
resp,
reload,
}
Each response is a Svelte store returning either an undefined
, or the following object:
{
status,
ok,
data
}
Using SvelteFetcher with await syntax in templates
<script lang="ts">
import { findPetByStatus } from './api.ts'
const request = findPetByStatus({ status: 'sold' })
const petsReady = request.ready
</script>
<div>
{#await $petsReady}
<p>Loading..</p>
{:then resp}
{#if resp.ok}
{#each resp.data as pet}
<p>{pet.name}</p>
{/each}
{:else}
<p>Error while loading pets</p>
{/if}
{/await}
<button on:click={() => {request.reload()}}>
Reload pets
</button>
</div>
Subscribing to response store
<script lang="ts">
import { findPetByStatus } from './api.ts'
const request = findPetByStatus({ status: 'sold' })
let names = []
request.resp.subscribe(resp => {
if (resp.ok) {
names = resp.data.map(pet => pet.name)
}
})
</script>
<div>
{#each resp.data as pet}
<p>{pet.name}</p>
{/each}
</div>
Using in load functions
Fetch operations support SvelteKit's load function from +page.ts
and +page.server.ts
:
export async function load({ fetch }) {
const request = findPetByStatus({ status: 'sold' })
const resp = await request.isLoaded
if (resp.ok) {
return { pets: resp.data }
} else {
return { pets: [] }
}
}
Using Fetcher in pure JavaScript
If you work on non-Svelte project, then you can use Fetcher
instead:
import { Fetcher } from 'openapi-typescript-fetch'
import { paths } from './petstore'
const fetcher = Fetcher.for<paths>()
fetcher.configure({
baseUrl: 'https://petstore.swagger.io/v2',
})
const findPetsByStatus = fetcher
.path('/pet/findByStatus')
.method('get')
.create()
const addPet = fetcher.path('/pet').method('post').create()
const resp = await findPetsByStatus({ status: 'available' })
console.log(resp.ok)
console.log(resp.data)
console.log(resp.status)
Typed Error Handling
A non-ok fetch response throws a generic ApiError
But an Openapi document can declare a different response type for each status code, or a default error response type
These can be accessed via a discriminated union
on status, as in code snippet below
const findPetsByStatus = fetcher.path('/pet/findByStatus').method('get').create()
const addPet = fetcher.path('/pet').method('post').create()
try {
await findPetsByStatus({ ... })
await addPet({ ... })
} catch(e) {
if (e instanceof addPet.Error) {
const error = e.getActualType()
if (error.status === 400) {
error.data.validationErrors
} else if (error.status === 500) {
error.data.errorMessage
} else {
...
}
}
}
Utility Types
OpArgType
- Infer argument type of an operationOpReturnType
- Infer return type of an operationOpErrorType
- Infer error type of an operationFetchArgType
- Argument type of a typed fetch operationFetchReturnType
- Return type of a typed fetch operationFetchErrorType
- Error type of a typed fetch operationTypedFetch
- Fetch operation type
import { paths, operations } from './petstore'
type Arg = OpArgType<operations['findPetsByStatus']>
type Ret = OpReturnType<operations['findPetsByStatus']>
type Err = OpErrorType<operations['findPetsByStatus']>
type Arg = OpArgType<paths['/pet/findByStatus']['get']>
type Ret = OpReturnType<paths['/pet/findByStatus']['get']>
type Err = OpErrorType<paths['/pet/findByStatus']['get']>
type FindPetsByStatus = TypedFetch<operations['findPetsByStatus']>
const findPetsByStatus = fetcher
.path('/pet/findByStatus')
.method('get')
.create()
type Arg = FetchArgType<typeof findPetsByStatus>
type Ret = FetchReturnType<typeof findPetsByStatus>
type Err = FetchErrorType<typeof findPetsByStatus>
Utility Methods
arrayRequestBody
- Helper to merge params when request body is an array see issue
const body = arrayRequestBody([{ item: 1 }], { param: 2 })
Happy fetching! 👍