Documentation

API Reference

Review TypeScript behavior, public exports, core config shapes, and the example app.

TypeScript behavior

Endpoint generics flow into query functions, mutation functions, and direct request functions.

No-variable endpoints expose zero-argument helpers, so callers do not need to pass undefined.

toQuery() and toMutation() return structural config types, so they remain assignable to TanStack Query even in monorepos or linked examples with more than one physical @tanstack/react-query install.

TypeScript
1const me = api.resource("me", {2  get: api.get<User>("/me"),3});4 5me.get.toQuery();6me.get.key();7me.get.fn();8 9const detail = users.detail.toQuery("user-1");10// detail.queryFn returns Promise<User>.

Public exports

The root package exports runtime helpers, error classes, and TypeScript types.

Runtime
createMicroApi, createTokenProvider, MicroApiError, MicroAuthRequiredError.
Endpoint types
QueryEndpoint, MutationEndpoint, QueryConfig, MutationConfig, BuiltResource, VariablesArgs.
Config types
CreateMicroApiConfig, RequestMappers, BodyType, PathBuilder, AuthMode, HttpMethod, MicroRequestContext.
Auth and key types
TokenProvider, TokenProviderConfig, MaybePromise, MicroApi, MicroQueryKey.

Core API shapes

These are the main public config shapes. Most users only need them when typing reusable helpers.

TypeScript
1type CreateMicroApiConfig = {2  name: string;3  baseUrl: string;4  headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);5  tokenProvider?: TokenProvider;6  authHeader?: (token: string) => HeadersInit;7  fetcher?: typeof fetch;8  onError?: (error: unknown, context: MicroRequestContext) => void | Promise<void>;9};10 11type RequestMappers<TVariables> = {12  query?: (variables: TVariables) => Record<string, unknown>;13  body?: (variables: TVariables) => unknown;14  bodyType?: "json" | "form-data";15  headers?: (variables: TVariables) => HeadersInit;16  authMode?: "none" | "optional" | "required";17};18 19type MicroApi = {20  extend: (overrides: Partial<CreateMicroApiConfig>) => MicroApi;21  // Also includes get, post, put, patch, delete, and resource helpers.22};

Complete client example

This example shows all client options together. In real apps, start small and add options only when you need them.

The important separation is: client options define shared request behavior; endpoint mappers define endpoint-specific request behavior; TanStack Query options define UI caching behavior.

TypeScript
1import { createMicroApi } from "micro-rq";2 3export const publicApi = createMicroApi({4  name: "public",5  baseUrl: "/api",6});
TypeScript
1import { publicApi } from "./public-api";2 3type AuthTokens = {4  accessToken: string;5  refreshToken: string;6};7 8export const auth = publicApi.resource("auth", {9  refresh: publicApi.post<AuthTokens, { refreshToken?: string | null }>("/auth/refresh", {10    authMode: "none",11  }),12});
TypeScript
1import { createTokenProvider } from "micro-rq";2import { auth } from "./auth";3 4const tokenProvider = createTokenProvider({5  getAccessToken: () => localStorage.getItem("accessToken"),6  getRefreshToken: () => localStorage.getItem("refreshToken"),7  refresh: {8    fn: ({ refreshToken }) => auth.refresh.fn({ refreshToken }),9    selectAccessToken: (tokens) => tokens.accessToken,10    onSuccess: (tokens) => {11      localStorage.setItem("accessToken", tokens.accessToken);12      localStorage.setItem("refreshToken", tokens.refreshToken);13    },14    onError: () => {15      localStorage.removeItem("accessToken");16      localStorage.removeItem("refreshToken");17    },18  },19});
TypeScript
1import { createMicroApi, MicroApiError } from "micro-rq";2import { tokenProvider } from "./token-provider";3 4export const api = createMicroApi({5  name: "main",6  baseUrl: "/api",7  headers: () => ({8    "accept-language": localStorage.getItem("locale") ?? "en",9    "x-client": "web",10  }),11  tokenProvider,12  authHeader: (token) => ({13    Authorization: `Bearer ${token}`,14  }),15  fetcher: fetch,16  onError: (error, context) => {17    if (error instanceof MicroApiError && error.status === 401) {18      console.warn("Unauthorized request", context.url);19    }20  },21});

Next.js SSR hydration

In Server Components, pass the generated query config directly to TanStack Query's prefetchQuery.

Then wrap the Client Component with HydrationBoundary. The client can call useQuery with the same endpoint config and read the prefetched data from the cache.

TypeScript
1// app/products/page.tsx2import { dehydrate, HydrationBoundary, QueryClient } from "@tanstack/react-query";3import { products } from "../api/resources/products";4import { ProductsClient } from "./products-client";5 6export default async function ProductsPage() {7  const queryClient = new QueryClient();8  const params = {9    limit: 12,10    skip: 0,11  };12 13  await queryClient.prefetchQuery(products.list.toQuery(params));14  await queryClient.prefetchQuery(products.categoryList.toQuery());15 16  return (17    <HydrationBoundary state={dehydrate(queryClient)}>18      <ProductsClient params={params} />19    </HydrationBoundary>20  );21}
TypeScript
1// app/products/products-client.tsx2"use client";3 4import { useQuery } from "@tanstack/react-query";5import { products } from "../api/resources/products";6 7export function ProductsClient({ params }: { params: { limit: number; skip: number } }) {8  const productsQuery = useQuery({9    ...products.list.toQuery(params),10  });11 12  const categoriesQuery = useQuery({13    ...products.categoryList.toQuery(),14  });15 16  // Render productsQuery.data and categoriesQuery.data.17}

Example app

The repository includes a structured Next.js App Router example app using DummyJSON.

Open the Example app source on GitHub: examples/next.

It demonstrates server prefetch/hydration, product list/detail pages, login, protected routes, automatic refresh-token retry, infinite posts, mutations, upload, and error handling.

TypeScript
1cd examples/next2npm install3npm run dev