Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
tRPC Nuxt
https://github.com/wobsoriano/trpc-nuxt
Admin
tRPC Nuxt provides end-to-end typesafe APIs for Nuxt applications using tRPC.
Tokens:
40,292
Snippets:
251
Trust Score:
9.8
License:
MIT
Update:
4 weeks ago
Context
Chat
Benchmark
51
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### Install dependencies with pnpm Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/playground/README.md Installs the project dependencies using pnpm. Run this in the project root before starting the development server. ```bash pnpm install ``` -------------------------------- ### Basic useQuery example in Vue script setup Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/decorated-procedures.md Shows the basic usage of useQuery in a Vue component's script setup. It uses useNuxtApp to access $trpc and destructures the AsyncData result to get data and refresh. The query is awaitable in async context. ```vue <script setup lang="ts"> const { $trpc } = useNuxtApp(); // awaitable in async context; destructure the AsyncData result const { data: todos, refresh } = await $trpc.todo.list.useQuery(); </script> ``` -------------------------------- ### Start development server with pnpm dev Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/playground/README.md Starts the development server on http://localhost:3000. Use this for local development with hot reload. ```bash pnpm dev ``` -------------------------------- ### Example: getMutationKey usage Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/getQueryKey.md Shows how to import and use `getMutationKey` to get the mutation key for a procedure. The example logs the key, which is the dotted path like 'todo.add'. ```typescript import { getMutationKey } from 'trpc-nuxt/client'; const mutationKey = getMutationKey($client.todo.add); console.log(mutationKey); // 'todo.add' ``` -------------------------------- ### Example: Nuxt plugin using httpLink Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/links.md Shows how to create a Nuxt plugin that uses `httpLink` with `pickHeaders` and `fetchOptions` to configure the tRPC client. ```typescript // app/plugins/trpc.ts import { createTRPCNuxtClient, httpLink } from 'trpc-nuxt/client'; import type { AppRouter } from '~/server/trpc/routers'; export default defineNuxtPlugin(() => { const trpc = createTRPCNuxtClient<AppRouter>({ links: [ httpLink({ // Only forward the authorization header to the API pickHeaders: ['authorization'], // ofetch options for request/response interception fetchOptions: { onRequest({ request }) { /* e.g. sign the request */ }, }, }), ], }); return { provide: { trpc } }; }); ``` -------------------------------- ### Install tRPC Nuxt dependencies with npm Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/setup.mdx Install the required packages for tRPC Nuxt. This is the first step in setting up tRPC with a new or existing Nuxt project. ```bash npm install trpc-nuxt @trpc/server @trpc/client ``` -------------------------------- ### createTRPCNuxtHandler adapter setup Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/references/createTRPCNuxtHandler.mdx Use this adapter in a Nuxt server route to expose your tRPC router. It extends the Fetch adapter, sets the default endpoint to `/api/trpc`, and passes the H3 event object to your context. The example imports `createTRPCContext` and `appRouter` from your server setup. ```ts // server/api/trpc/[trpc].ts import { createTRPCNuxtHandler } from 'trpc-nuxt/server'; import { createTRPCContext } from '~/server/trpc/init'; import { appRouter } from '~/server/trpc/routers'; export default createTRPCNuxtHandler({ router: appRouter, createContext: createTRPCContext, }); ``` -------------------------------- ### Example: using httpBatchLink in a Nuxt plugin Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/links.md Shows how to set up a tRPC client with httpBatchLink in a Nuxt plugin, providing the client via the Nuxt plugin system. ```typescript // app/plugins/trpc.ts import { createTRPCNuxtClient, httpBatchLink } from 'trpc-nuxt/client'; import type { AppRouter } from '~/server/trpc/routers'; export default defineNuxtPlugin(() => { const trpc = createTRPCNuxtClient<AppRouter>({ links: [ httpBatchLink({ url: '/api/trpc', }), ], }); return { provide: { trpc } }; }); ``` -------------------------------- ### Basic useMutation example in Vue Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/decorated-procedures.md Shows a basic mutation call using useMutation. The mutate function is called with input and optional execute options like dedupe. ```vue <script setup lang="ts"> const { $trpc } = useNuxtApp(); const { mutate: addTodo } = $trpc.todo.add.useMutation(); await addTodo({ title: 'Learn tRPC' }); // or with an execute option await addTodo({ title: 'Another' }, { dedupe: 'defer' }); </script> ``` -------------------------------- ### Vue example using getQueryKey with useNuxtData and refreshNuxtData Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/getQueryKey.md Shows how to keep a query key stable across pages so useNuxtData can read the cached value and refreshNuxtData can invalidate it. Uses getQueryKey with undefined input and demonstrates optimistic update with rollback. ```vue <script setup lang="ts"> import type { inferRouterOutputs } from '@trpc/server'; import type { AppRouter } from '~/server/trpc/routers'; import { getQueryKey } from 'trpc-nuxt/client'; const { $trpc } = useNuxtApp(); const previousTodos = ref([]); const queryKey = getQueryKey($trpc.getTodos, undefined); type RouterOutput = inferRouterOutputs<AppRouter>; // Reads the value cached by $trpc.getTodos.useQuery() elsewhere const { data: todos } = useNuxtData<RouterOutput['getTodos']>(queryKey); async function addTodo(payload) { previousTodos.value = [...todos.value]; todos.value.push(payload); try { await $trpc.addTodo.mutate(payload); await refreshNuxtData(queryKey); // background invalidation } catch { todos.value = previousTodos.value; } } </script> ``` -------------------------------- ### Basic useSubscription example in Vue (from apps/playground/app/pages/index.vue) Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/decorated-procedures.md Shows a basic subscription using $client.todo.onActivity.useSubscription with undefined input. Handles onStarted, onData, onError, onComplete, and onConnectionStateChange callbacks. Logs status changes via watchEffect. ```vue <script setup lang="ts"> const { $client } = useNuxtApp(); const activities = ref<Activity[]>([]); const { status, data, error, reset } = $client.todo.onActivity.useSubscription(undefined, { onStarted: () => console.log('Subscription started'), onData: (activity) => { activities.value.unshift(activity); }, onError: (error) => console.error('Subscription error:', error), onComplete: () => console.log('Subscription completed'), onConnectionStateChange(state) { console.log('Connection state changed:', state); }, }); watchEffect(() => { console.log('Subscription status:', status.value); }); </script> ``` -------------------------------- ### Example: Using mutation key with refreshNuxtData Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/getQueryKey.md Demonstrates using the mutation key as a fixed key for `refreshNuxtData` after a successful mutation. The mutation key is stable per-procedure, making it suitable for this purpose. ```typescript const { mutate } = $trpc.setCount.useMutation({ mutationKey: getMutationKey($trpc.setCount) }); await mutate(nextCount); await refreshNuxtData(getMutationKey($trpc.setCount)); ``` -------------------------------- ### useSubscription Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/decorated-procedures.md Documentation for the `useSubscription` method of `DecoratedSubscription` procedures, including parameters, return type, lifecycle, and examples. ```APIDOC ## `useSubscription` — subscription procedure ### Description Starts a tRPC subscription and returns reactive state (`status`, `data`, `error`) plus a `reset` function. Accepts a static input, a ref, or a getter; when a ref/getter is provided and `enabled` is not `false`, changes automatically re-subscribe. ### Method `useSubscription` ### Parameters | Parameter | Type | Required | Default | Description | |---|---|---|---|---| | `input` | `MaybeRefOrGetter<TDef['input']>` | yes | — | Subscription input (e.g. `undefined` for parameterless subscriptions), ref, or getter. If a ref/getter is passed and `enabled` is not `false`, changes re-subscribe. | | `opts.enabled` | `MaybeRefOrGetter<boolean>` | no | `true` | Master switch: `false` unsubscribes and stays idle; back to truthy re-subscribes. | | `opts.onStarted` | `(opts: { context: OperationContext \| undefined }) => void` | no | — | Called when tRPC reports the stream started; also drives status `'pending'`. | | `opts.onData` | `(data: TOutput) => void` | no | — | Called per yielded value. The SSE link wraps values in `{ data: <actual> }`, so the runtime unwraps with `value?.data ?? value` before storing/callbacking. | | `opts.onError` | `(error: TError) => void` | no | — | Called on tRPC error; sets status `'error'`. | | `opts.onComplete` | `() => void` | no | — | Called on stream completion; sets status `'idle'`. | | `opts.onConnectionStateChange` | `(state: TRPCConnectionState<TError>) => void` | no | — | Pass-through of `TRPCConnectionState` events (e.g. reconnecting). The runtime also mirrors states into `status`. | | `opts.onStopped` | `() => void` | no | — | Called when the subscription is unsubscribed (via `unsubscribe()`/scope dispose/reset). | | `opts.trpc` | `TRPCRequestOptions` | no | — | Spread into the tRPC `subscribe` call options last, overriding the callbacks above if it supplies any keys. | ### Return Type `UseSubscriptionReturn<TOutput, TError>` where `TOutput = inferAsyncIterableYield<TDef['output']>` (each yielded element) and `TError = TRPCClientError<TDef>`. | Field | Type | Description | |---|---|---| | `status` | `Ref<SubscriptionStatus>` | `'idle' \| 'connecting' \| 'pending' \| 'error'` | | `data` | `ShallowRef<TOutput \| undefined>` | Latest received value (unwrapped from the SSE envelope) | | `error` | `ShallowRef<TError \| null>` | Latest subscription error, or `null` | | `reset` | `() => void` | Unsubscribes, clears state, and re-subscribes unless `enabled` is `false`. | ### Lifecycle On subscribe, `status` goes `'idle' → 'connecting'`; `onStarted` moves it to `'pending'`; `onError` → `'error'`; `onComplete` → `'idle'`. Subscriptions start under `import.meta.client` only; the input/enabled watcher is registered with `immediate: false`, and when a Vue component instance is active the subscription is cleaned up via `onScopeDispose`. ### Examples Basic (from `apps/playground/app/pages/index.vue`): ```vue <script setup lang="ts"> const { $client } = useNuxtApp(); const activities = ref<Activity[]>([]); const { status, data, error, reset } = $client.todo.onActivity.useSubscription(undefined, { onStarted: () => console.log('Subscription started'), onData: (activity) => { activities.value.unshift(activity); }, onError: (error) => console.error('Subscription error:', error), onComplete: () => console.log('Subscription completed'), onConnectionStateChange(state) { console.log('Connection state changed:', state); }, }); watchEffect(() => { console.log('Subscription status:', status.value); }); </script> ``` Reactive input with enabled toggle (error handling shown explicitly): ```vue <script setup lang="ts"> const { $trpc } = useNuxtApp(); const roomId = ref('lobby'); const subscribed = ref(true); const { status, data, error } = $trpc.chat.onMessage.useSubscription( () => ({ roomId: roomId.value }), { enabled, onError: (err) => { // tRPC client error — surface it notification.error(err.message); }, }, ); // Changing roomId or setting enabled=false re-subscribes / unsubscribes automatically. </script> ``` ``` -------------------------------- ### Configure tRPC client with split links Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/createTRPCNuxtClient.md Example of using splitLink to route subscription operations differently from regular calls within the Nuxt plugin. ```ts import { splitLink, httpSubscriptionLink } from '@trpc/client'; import superjson from 'superjson'; import { createTRPCNuxtClient, httpBatchLink } from 'trpc-nuxt/client'; export default defineNuxtPlugin(() => { const client = createTRPCNuxtClient<AppRouter>({ links: [ splitLink({ condition: (op) => op.type === 'subscription', true: httpSubscriptionLink({ url: '/api/trpc', transformer: superjson }), false: httpBatchLink({ url: '/api/trpc', transformer: superjson }), }), ], }); return { provide: { client }, }; }); ``` -------------------------------- ### Vanilla query resolver example Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/decorated-procedures.md Shows the direct passthrough query resolver on a decorated procedure. It calls $trpc.getUser.query with an ID and returns the user object. This bypasses useAsyncData and returns a promise directly. ```vue <script setup lang="ts"> const { $trpc } = useNuxtApp(); const bilbo = await $trpc.getUser.query('id_bilbo'); // => { id: 'id_bilbo', name: 'Bilbo' } </script> ``` -------------------------------- ### Configure responseMeta for caching in createTRPCNuxtHandler Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/guides/response-caching.md Use the `responseMeta` option in `createTRPCNuxtHandler` to set cache-control headers. This example caches responses for 1 day with stale-while-revalidate. Place this in `server/api/trpc/[trpc].ts`. ```ts // server/api/trpc/[trpc].ts import { createTRPCNuxtHandler } from 'trpc-nuxt/server'; import { appRouter } from '~/server/trpc/routers'; export default createTRPCNuxtHandler({ router: appRouter, /** * @link https://trpc.io/docs/caching#api-response-caching */ responseMeta(opts) { // cache request for 1 day + revalidate once every second const ONE_DAY_IN_SECONDS = 60 * 60 * 24; return { headers: { 'cache-control': `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`, }, }; }, }); ``` -------------------------------- ### Call tRPC procedures in pages using useNuxtApp Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/setup.mdx Use the provided $trpc client inside a Nuxt page's script setup to fetch data from the hello procedure. The template outputs the greeting. ```vue <script setup lang="ts"> const { $trpc } = useNuxtApp(); const { data: hello } = await $trpc.hello.useQuery({ text: 'client' }); </script> <template> <div>{{ hello?.greeting }}</div> </template> ``` -------------------------------- ### Preview production build with pnpm preview Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/playground/README.md Locally previews the production build. Run after building the application. ```bash pnpm preview ``` -------------------------------- ### Build application for production with pnpm build Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/playground/README.md Builds the application for production. Run this before previewing the production build. ```bash pnpm build ``` -------------------------------- ### Create main app router with hello procedure in server/trpc/routers/index.ts Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/setup.mdx Set up the main app router using createTRPCRouter. It includes a query procedure 'hello' that takes a text input and returns a greeting. The AppRouter type is exported for client-side type inference. ```ts // server/trpc/routers/index.ts import { baseProcedure, createTRPCRouter } from '~/server/trpc/init'; import { z } from 'zod'; export const appRouter = createTRPCRouter({ hello: baseProcedure .input( z.object({ text: z.string(), }), ) .query((opts) => { return { greeting: `hello ${opts.input.text}`, }; }), }); // export type definition of API export type AppRouter = typeof appRouter; ``` -------------------------------- ### Advanced useQuery with reactive input, custom key, and error handling Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/decorated-procedures.md Demonstrates useQuery with a reactive getter input that auto-refetches on change, a fixed queryKey, trpc options like abortOnUnmount, and an onError handler. The input is a function returning the search term from a ref. ```vue <script setup lang="ts"> const { $trpc } = useNuxtApp(); const search = ref(''); const { data, error, status } = await $trpc.search.useQuery( () => ({ term: search.value }), // getter input → auto refetch on change { queryKey: 'search-results', // fixed key, not recomputed from input trpc: { abortOnUnmount: true }, onError: (err) => console.warn('query failed', err.data?.message), }, ); </script> ``` -------------------------------- ### Create tRPC router initialization and context in server/trpc/init.ts Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/setup.mdx Initialize the tRPC backend using initTRPC, define a context creator that extracts auth from the H3 event, and export base router and procedure helpers. The transformer is commented out but can be enabled with superjson. ```ts // server/trpc/init.ts import { initTRPC } from '@trpc/server'; import type { H3Event } from 'h3'; export const createTRPCContext = async (event: H3Event) => { /** * @see: https://trpc.io/docs/server/context */ return { auth: event.context.auth }; }; // Avoid exporting the entire t-object // since it's not very descriptive. // For instance, the use of a t variable // is common in i18n libraries. const t = initTRPC.create({ /** * @see https://trpc.io/docs/server/data-transformers */ // transformer: superjson, }); // Base router and procedure helpers export const createTRPCRouter = t.router; export const createCallerFactory = t.createCallerFactory; export const baseProcedure = t.procedure; ``` -------------------------------- ### UseSubscriptionOptions interface Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/types.md Options for the useSubscription hook. Controls subscription lifecycle with callbacks for start, data, error, completion, connection state, and stop. The 'enabled' option toggles subscription; toggling re-subscribes/unsubscribes. External types come from vue and @trpc/client. ```typescript export interface UseSubscriptionOptions<TOutput, TError> { enabled?: MaybeRefOrGetter<boolean>; onStarted?: (opts: { context: OperationContext | undefined }) => void; onData?: (data: TOutput) => void; onError?: (error: TError) => void; onComplete?: () => void; onConnectionStateChange?: (state: TRPCConnectionState<TError>) => void; onStopped?: () => void; trpc?: TRPCRequestOptions; } ``` -------------------------------- ### Use tRPC client with composables and vanilla methods in Vue component Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/references/createTRPCNuxtClient.mdx Shows how to use the provided `$trpc` client in a Vue component. Demonstrates `useQuery` and `useMutation` composables, and the vanilla `query` and `mutate` methods. The comments show the expected return values. ```vue <script setup lang="ts"> const { $trpc } = useNuxtApp(); // With composables const getUser = await $trpc.getUser.useQuery('id_bilbo'); // => { data: { id: 'id_bilbo', name: 'Bilbo' }, pending: false, error: false }; const createUser = await $trpc.createUser.useMutation(); await createUser.mutate({ name: 'Frodo' }); // => { id: 'id_frodo', name: 'Frodo' }; // With vanilla const bilbo = await $trpc.getUser.query('id_bilbo'); // => { id: 'id_bilbo', name: 'Bilbo' }; const frodo = await $trpc.createUser.mutate({ name: 'Frodo' }); // => { id: 'id_frodo', name: 'Frodo' }; </script> ``` -------------------------------- ### Use Nitro's Cache API with defineCachedEventHandler Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/guides/response-caching.md For server-side calls, use Nitro's `defineCachedEventHandler` to cache responses. This example uses SWR with a max age of 10 seconds. The `caller` is created from the app router and used to fetch a greeting. ```ts import { appRouter } from '~/server/trpc/routers'; const caller = appRouter.createCaller({}); export default defineCachedEventHandler( async (event) => { const { name } = getQuery(event); const greeting = await caller.greeting({ name }); return { greeting, }; }, { swr: true, maxAge: 10, }, ); ``` -------------------------------- ### Option 1: Authorize using resolver Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/guides/authorization.md Shows how to check authorization inside a resolver by throwing a TRPCError with code 'UNAUTHORIZED' if the user is not present. The `hello` procedure is open to anyone, while `secret` is protected. ```ts import { initTRPC, TRPCError } from '@trpc/server'; // ... context function const t = initTRPC.context<Context>().create(); const appRouter = t.router({ // open for anyone hello: t.procedure .input(z.string().nullish()) .query(({ input, ctx }) => `hello ${input ?? ctx.user?.name ?? 'world'}`), // checked in resolver secret: t.procedure.query(({ ctx }) => { if (!ctx.user) { throw new TRPCError({ code: 'UNAUTHORIZED' }); } return { secret: 'sauce', }; }), }); ``` -------------------------------- ### Client call using useNuxtApp and $trpc Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/endpoints.md Makes a client-side tRPC query that maps to POST /api/trpc. Uses the $trpc instance from useNuxtApp to call the hello procedure with a text parameter. ```vue <script setup lang="ts"> const { $trpc } = useNuxtApp(); const { data: greeting } = await $trpc.hello.useQuery({ text: 'client' }); </script> ``` -------------------------------- ### createTRPCNuxtClient<TRouter>(opts) Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/createTRPCNuxtClient.md Creates a fully decorated, type-safe tRPC client for Nuxt. The returned proxy mirrors the router's record, with query, mutation, and subscription procedures decorated with `useQuery`, `useMutation`, and `useSubscription` respectively. ```APIDOC ## createTRPCNuxtClient<TRouter>(opts) ### Description Creates a fully decorated, type-safe tRPC client for Nuxt. The returned proxy mirrors the router's record, with query, mutation, and subscription procedures decorated with `useQuery`, `useMutation`, and `useSubscription` respectively. ### Method Function ### Signature ```ts export function createTRPCNuxtClient<TRouter extends AnyTRPCRouter>( opts: CreateTRPCClientOptions<TRouter>, ): createTRPCFlatProxy<DecorateRouterRecord<TRouter['_def']['_config']['$types'], TRouter['_def']['record']>> ``` ### Parameters - `opts` (CreateTRPCClientOptions<TRouter>) - Required - tRPC v11 client options as defined by `@trpc/client`. The only option exercised in this repository's examples and docs is `links` (the tRPC links array). ### Return Type `createTRPCFlatProxy<DecorateRouterRecord<TRouter['_def']['_config']['$types'], TRouter['_def']['record']>>` - a proxy that mirrors the router's record. Every procedure is replaced by a decorated variant: - **query procedure** → `DecoratedQuery` (adds `useQuery`; retains `query`) - **mutation procedure** → `DecoratedMutation` (adds `useMutation`; retains `mutate`) - **subscription procedure** → `DecoratedSubscription` (adds `useSubscription`; retains `subscribe`) - nested routers are recursed by `DecorateRouterRecord` ### Throws `createTRPCNuxtClient` itself performs no validation in this source file. Errors surface from the underlying `createTRPCUntypedClient` / `createTRPCClientProxy` calls (e.g. invalid link configurations from `@trpc/client`) and are not re-wrapped. ``` -------------------------------- ### Create tRPC Nuxt client with httpLink and pickHeaders Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/references/links.mdx Use this snippet to set up a tRPC Nuxt client in a plugin file. It imports `createTRPCNuxtClient` and `httpLink` from `trpc-nuxt/client`, and configures the link to pass only the `authorization` header to `useRequestHeaders`. The default URL is `/api/trpc`. ```ts // plugins/trpc.ts import { createTRPCNuxtClient, httpLink } from 'trpc-nuxt/client'; import type { AppRouter } from '~/server/trpc/routers'; const client = createTRPCNuxtClient<AppRouter>({ links: [ httpLink({ // Select headers to pass to `useRequestHeaders`. // By default, `useRequestHeaders()` returns all headers. pickHeaders: ['authorization'], }), ], }); ``` -------------------------------- ### Optimistic update with rollback using useMutation Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/decorated-procedures.md Demonstrates optimistic updates with rollback on error. Uses getQueryKey to refresh data after mutation and reverts todos on failure. ```vue <script setup lang="ts"> import { getQueryKey } from 'trpc-nuxt/client'; const { $trpc } = useNuxtApp(); const previousTodos = ref([]); const { data: todos } = await $trpc.getTodos.useQuery(undefined); const { mutate } = $trpc.addTodo.useMutation(); async function addTodo(payload) { previousTodos.value = [...todos.value]; todos.value.push(payload); try { await mutate(payload); await refreshNuxtData(getQueryKey($trpc.getTodos, undefined)); } catch { todos.value = previousTodos.value; } } </script> ``` -------------------------------- ### Set up tRPC HTTP handler in server/api/trpc/[trpc].ts Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/setup.mdx Create the tRPC Nuxt HTTP handler that serves the API at '/api/trpc'. It uses createTRPCNuxtHandler with the router and context created earlier. ```ts // server/api/trpc/[trpc].ts import { createTRPCNuxtHandler } from 'trpc-nuxt/server'; import { createTRPCContext } from '~/server/trpc/init'; import { appRouter } from '~/server/trpc/routers'; export default createTRPCNuxtHandler({ endpoint: '/api/trpc', router: appRouter, createContext: createTRPCContext, }); ``` -------------------------------- ### Query procedure definition (server/trpc/init.ts) Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/apps/docs/src/content/docs/guides/server-side-calls.md Defines a tRPC router with a 'greeting' query procedure that takes a name input and returns a greeting string. ```ts // server/trpc/init.ts import { initTRPC } from '@trpc/server'; import { z } from 'zod'; const t = initTRPC.create(); export const router = t.router({ // Create procedure at path 'greeting' greeting: t.procedure .input(z.object({ name: z.string() })) .query(({ input }) => `Hello ${input.name}`), }); ``` -------------------------------- ### UseSubscriptionOptions<TOutput, TError> Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/types.md Options interface for configuring tRPC subscriptions in Nuxt. ```APIDOC ## UseSubscriptionOptions<TOutput, TError> ### Description Options for configuring a tRPC subscription in a Nuxt application. Controls enabling, lifecycle callbacks, and extra tRPC request options. ### Type TypeScript interface ### Fields - **enabled** (`MaybeRefOrGetter<boolean>`) - Optional - Master switch; subscriptions start unless `false`; toggling re-subscribes/unsubscribes - **onStarted** (`(opts: { context: OperationContext | undefined }) => void`) - Optional - Stream started (also sets status `'pending'`) - **onData** (`(data: TOutput) => void`) - Optional - Per yielded value (SSE-wrapped values are unwrapped first) - **onError** (`(error: TError) => void`) - Optional - Subscription error - **onComplete** (`() => void`) - Optional - Stream completed - **onConnectionStateChange** (`(state: TRPCConnectionState<TError>) => void`) - Optional - Connection-state events; mirrored into `status` - **onStopped** (`() => void`) - Optional - Unsubscribed - **trpc** (`TRPCRequestOptions`) - Optional - Extra options spread into the tRPC `subscribe` call ### Accepted By `DecoratedSubscription.useSubscription` (second argument). ``` -------------------------------- ### httpBatchLink Source: https://github.com/wobsoriano/trpc-nuxt/blob/main/_autodocs/api-reference/links.md Documentation for the httpBatchLink function from trpc-nuxt client. ```APIDOC ## `httpBatchLink` ### Description This is a convenience wrapper around the original `httpBatchLink` that replaces regular `fetch` with `$fetch` from Nuxt. It also sets default headers based on `useRequestHeaders` values. During server-side rendering, calling `$fetch` to fetch internal API routes will directly call the relevant function, saving an additional API call. ### Signature ```ts export function httpBatchLink<TRouter extends AnyTRPCRouter>(opts?: HttpBatchLinkOptions<TRouter>): Link<TRouter> ``` ### Parameters - `opts` (HttpBatchLinkOptions<TRouter>) - Optional - Options object with the same contract as `httpLink`, plus batching behavior. Includes `pickHeaders`, `fetchOptions`, and `url` (defaults to `defaultEndpoint`). ### Example ```ts // app/plugins/trpc.ts import { createTRPCNuxtClient, httpBatchLink } from 'trpc-nuxt/client'; import type { AppRouter } from '~/server/trpc/routers'; export default defineNuxtPlugin(() => { const trpc = createTRPCNuxtClient<AppRouter>({ links: [ httpBatchLink({ url: '/api/trpc', }), ], }); return { provide: { trpc } }; }); ``` ```