npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@qualisero/openapi-endpoint

v0.23.1

Published

Type-safe OpenAPI integration for Vue Query

Readme

OpenApiEndpoint

npm version CI License: MIT Documentation

Type-safe API composables for Vue using TanStack Query. Generate fully-typed API clients from your OpenAPI specification.

Quick Start

// 1. Generate types from your OpenAPI spec
npx @qualisero/openapi-endpoint ./api/openapi.json ./src/generated

// 2. Initialize the API client
import { createApiClient } from '@qualisero/openapi-endpoint'
import axios from 'axios'

const api = createApiClient(axios.create({ baseURL: 'https://api.example.com' }))

// 3. Use in your Vue components
const { data: pets, isLoading } = api.listPets.useQuery()
const { data: pet } = api.getPet.useQuery({ petId: '123' })

const createPet = api.createPet.useMutation()
await createPet.mutateAsync({ data: { name: 'Fluffy', species: 'cat' } })

Features

  • Fully typed - Operations, parameters, and responses type-checked against your OpenAPI spec
  • Reactive parameters - Query params automatically refetch when values change
  • Automatic cache management - Mutations invalidate and update related queries
  • Vue 3 + TanStack Query - Built on proven reactive patterns
  • File uploads - Support for multipart/form-data endpoints

Installation

npm install @qualisero/openapi-endpoint

Code Generation

# From local file
npx @qualisero/openapi-endpoint ./api/openapi.json ./src/generated

# From remote URL
npx @qualisero/openapi-endpoint https://api.example.com/openapi.json ./src/generated

Generated files:

| File | Description | | ------------------- | -------------------------------------------- | | api-client.ts | createApiClient factory (main entry point) | | api-operations.ts | Operations map and type helpers | | api-types.ts | Type namespace for response/request types | | api-enums.ts | Schema enums | | api-schemas.ts | Schema type aliases | | openapi-types.ts | Raw OpenAPI types |

API Reference

Initialization

import { createApiClient } from '@qualisero/openapi-endpoint'
import axios from 'axios'

const api = createApiClient(axiosInstance, queryClient?)

Queries (GET/HEAD/OPTIONS)

// No parameters
const { data, isLoading, error, refetch } = api.listPets.useQuery()

// With path parameters
const { data } = api.getPet.useQuery({ petId: '123' })

// With query parameters
const { data } = api.listPets.useQuery({
  queryParams: { limit: 10, status: 'available' },
})

// Reactive parameters
const limit = ref(10)
const { data } = api.listPets.useQuery({
  queryParams: computed(() => ({ limit: limit.value })),
})
// Automatically refetches when limit.value changes

// With options
const { data, onLoad } = api.listPets.useQuery({
  enabled: computed(() => isLoggedIn.value),
  staleTime: 5000,
  onLoad: (data) => console.log('Loaded:', data),
})

// onLoad callback method
const query = api.getPet.useQuery({ petId: '123' })
query.onLoad((pet) => console.log('Pet:', pet.name))

Getting a URL without fetching

Every query operation also exposes urlFor(), which returns a plain URL string without performing a request. This is the right tool for <img :src>, anchor href, window.open, or native fetch:

const url = api.getAssetDocumentFile.urlFor({ asset_id, document_ref }, { view: true })
// → "https://api.example.com/api/v3/document/asset/.../file?view=true"

Notes:

  • Synchronous; takes plain values only (not refs or getters). Wrap in computed(...) for reactivity.
  • Only flat scalar query params (string | number | boolean) are supported.
  • baseURL is read from the axios instance at call time.
  • Available on query operations only (GET / HEAD / OPTIONS), not mutations.

Mutations (POST/PUT/PATCH/DELETE)

// Simple mutation
const createPet = api.createPet.useMutation()
await createPet.mutateAsync({ data: { name: 'Fluffy' } })

// With path parameters
const updatePet = api.updatePet.useMutation({ petId: '123' })
await updatePet.mutateAsync({ data: { name: 'Updated' } })

// Deferred path params: omit at hook time, provide at call time
const deletePet = api.deletePet.useMutation()
await deletePet.mutateAsync({ pathParams: { petId: '123' } })

// Deferred path params with options
const updateWithCache = api.updatePet.useMutation(undefined, {
  invalidateOperations: { listPets: {} },
})
await updateWithCache.mutateAsync({
  data: { name: 'Updated' },
  pathParams: { petId: '123' },
})

// With options
const mutation = api.createPet.useMutation({
  dontInvalidate: true,
  invalidateOperations: ['listPets'],
  onSuccess: (response) => console.log('Created:', response.data),
})

Serialised mutations

The serialize option queues mutations so they run one at a time in submission order, preventing last-write-wins races in auto-save flows. It maps directly to TanStack Query v5's scope mechanism.

// Auto-scope: derived from the resolved path — same resource, same queue
const patch = api.updateContract.useMutation({ contract_id: '123' }, { serialize: true })
await patch.mutateAsync({ data: changes1 })
await patch.mutateAsync({ data: changes2 }) // waits for changes1 to complete first

// String scope: share a queue across different operations
const updatePet = api.updatePet.useMutation({ petId: '1' }, { serialize: 'pet-editor' })
const updateStatus = api.updatePetStatus.useMutation({ petId: '1' }, { serialize: 'pet-editor' })
// Both mutations queue behind each other in submission order

// Raw TanStack scope passthrough also works without serialize:
const mutation = api.updatePet.useMutation({ petId: '1' }, { scope: { id: 'my-scope' } })

serialize: true scope derivation: the scope id is serialize:<METHOD>:<resolvedPath>, e.g. serialize:PATCH:/api/contract/123. Two components mutating the same resource (same path params at hook time) share a queue automatically; different resources do not block each other. The scope id is reactive: if hook-time path params are refs/getters and change, subsequent mutations use the updated scope.

Deferred path params caveat: when path parameters are supplied at mutateAsync time rather than hook time, the scope id falls back to the path template (e.g. serialize:PATCH:/api/contract/{contract_id}), serialising all mutations of that operation regardless of target resource. For per-resource granularity, supply path parameters at hook-creation time or use a string scope.

Explicit scope always wins: if both scope and serialize are set, scope takes precedence and a warning is logged.

Axios Configuration

Pass custom Axios options through the axiosOptions parameter for advanced HTTP configuration:

// Custom headers
const { data } = api.listPets.useQuery({
  axiosOptions: {
    headers: {
      'X-Custom-Header': 'custom-value',
      Authorization: 'Bearer token123',
    },
  },
})

// Timeout configuration
const { data } = api.getPet.useQuery(
  { petId: '123' },
  {
    axiosOptions: {
      timeout: 5000, // 5 second timeout
    },
  },
)

// Request/response transforms
const { data } = api.createPet.useMutation(
  {},
  {
    axiosOptions: {
      transformRequest: [(data) => JSON.stringify(data)],
      transformResponse: [(data) => JSON.parse(data)],
    },
  },
)

// Override baseURL for specific requests
const { data } = api.listPets.useQuery({
  axiosOptions: {
    baseURL: 'https://custom-api.example.com',
  },
})

// Custom properties (via AxiosRequestConfigExtended)
const { data } = api.listPets.useQuery({
  axiosOptions: {
    timeout: 5000,
    manualErrorHandling: true, // Custom property
    handledByAxios: false, // Custom property
    customRetryCount: 3, // Custom property
  },
})

Common Axios options supported:

  • headers - Custom request headers
  • timeout - Request timeout in milliseconds
  • baseURL - Override base URL for this request
  • auth - Basic authentication
  • withCredentials - Include cookies in cross-origin requests
  • params - URL parameters (merged with queryParams)
  • paramsSerializer - Custom parameter serializer
  • transformRequest / transformResponse - Request/response transformers
  • onUploadProgress / onDownloadProgress - Progress callbacks
  • signal - Request cancellation with AbortController
  • validateStatus - Custom status code validation

Note: The AxiosRequestConfigExtended type also supports arbitrary custom properties beyond standard Axios options.

Return Types

Query Return:

{
  data: ComputedRef<T | undefined>
  isLoading: ComputedRef<boolean>
  error: ComputedRef<Error | null>
  isEnabled: ComputedRef<boolean>
  queryKey: ComputedRef<unknown[]>
  onLoad: (cb: (data: T) => void) => void
  refetch: () => Promise<void>
}

Mutation Return:

{
  data: ComputedRef<AxiosResponse<T> | undefined>
  isPending: ComputedRef<boolean>
  error: ComputedRef<Error | null>
  mutate: (vars) => void
  mutateAsync: (vars) => Promise<AxiosResponse>
  extraPathParams: Ref<PathParams> // for dynamic path params
}

Type Helpers

import type {
  ApiResponse, // Response type (ALL fields required - default)
  ApiResponseStrict, // Response type (only readonly/required fields required - strict mode)
  ApiRequest, // Request body type
  ApiPathParams, // Path parameters type
  ApiQueryParams, // Query parameters type
} from './generated/api-operations'

// ApiResponse - default, ALL fields required
type PetResponse = ApiResponse<OpType.getPet>
// { readonly id: string, name: string, tag: string, status: 'available' | ... }

// ApiResponseStrict - strict mode, only readonly/required fields required
type PetResponseStrict = ApiResponseStrict<OpType.getPet>
// { readonly id: string, name: string, tag?: string, status?: 'available' | ... }

Enums

The CLI generates type-safe enum constants:

import { PetStatus } from './generated/api-enums'

// Use enum for intellisense and typo safety
const { data } = api.listPets.useQuery({
  queryParams: { status: PetStatus.Available },
})

// Still works with string literals
const { data } = api.listPets.useQuery({
  queryParams: { status: 'available' }, // also valid
})

Documentation

For detailed guides, see docs/manual/:

License

MIT