Files
trpc-nuxt/docs/content/1.get-started/2.usage.md
2022-12-13 18:07:15 +02:00

166 lines
4.1 KiB
Markdown

---
title: Usage
description: tRPC-Nuxt provides first class integration with tRPC.
---
# Usage
## Recommended file structure
Recommended but not enforced file structure. This is what you get when starting from [the examples](../main/example-apps.md).
```graphql
.
server
api
trpc
[trpc].ts # <-- tRPC HTTP handler
[..]
trpc
routers
index.ts # <-- main app router
todo.ts # <-- sub routers
[..]
context.ts # <-- create app context
trpc.ts # <-- procedure helpers
plugins
client.ts # <-- tRPC Client as a plugin
[..]
```
## 1. Create a tRPC router
Initialize your tRPC backend using the `initTRPC` function and create your first router.
::code-group
```ts [server/trpc/trpc.ts]
import { initTRPC } from '@trpc/server'
import { Context } from '@/server/trpc/context'
// Avoid exporting the entire t-object since it's not very
// descriptive and can be confusing to newcomers used to t
// meaning translation in i18n libraries.
const t = initTRPC.context<Context>().create()
// Base router and procedure helpers
export const router = t.router
export const publicProcedure = t.procedure
```
```ts [server/trpc/routers/index.ts]
import { z } from 'zod'
import { publicProcedure, router } from '../trpc'
export const appRouter = router({
hello: publicProcedure
.input(
z.object({
text: z.string().nullish(),
}),
)
.query(({ input }) => {
return {
greeting: `hello ${input?.text ?? 'world'}`,
}
}),
})
// export type definition of API
export type AppRouter = typeof appRouter
```
```ts [server/api/trpc/[trpc].ts]
import { createNuxtApiHandler } from 'trpc-nuxt'
import { appRouter } from '@/server/trpc/routers'
import { createContext } from '@/server/trpc/context'
// export API handler
export default createNuxtApiHandler({
router: appRouter,
createContext,
})
```
```ts [server/trpc/context.ts]
import { inferAsyncReturnType } from '@trpc/server'
/**
* Creates context for an incoming request
* @link https://trpc.io/docs/context
*/
export const createContext = () => {}
export type Context = inferAsyncReturnType<typeof createContext>;
```
::
::alert{type=info}
If you need to split your router into several subrouters, you can implement them in the `server/trpc/routers` directory and import and [merge them](https://trpc.io/docs/v10/merging-routers) to a single root `appRouter`.
::
## 2. Create tRPC client plugin
Create a strongly-typed plugin using your API's type signature.
```ts [plugins/client.ts]
import { httpBatchLink, createTRPCProxyClient } from '@trpc/client'
import type { AppRouter } from '@/server/trpc/routers'
import { FetchError } from 'ofetch'
export default defineNuxtPlugin(() => {
const client = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: '/api/trpc',
/**
* Replace regular `fetch` with a `$fetch` from nuxt
*
* During server-side rendering, calling $fetch to fetch your internal API routes
* will directly call the relevant function (emulating the request),
* saving an additional API call.
*
* @see https://nuxt.com/docs/api/utils/dollarfetch
*/
fetch: (input, options) =>
globalThis.$fetch.raw(input.toString(), options)
.catch((e) => {
if (e instanceof FetchError && e.response)
return e.response
throw e
})
.then(response => ({
...response,
json: () => Promise.resolve(response._data),
})),
}),
],
})
return {
provide: {
client,
},
}
})
```
## 3. Make API requests
```vue [pages/index.vue]
<script setup lang="ts">
const { $client } = useNuxtApp()
const data = await $client.hello.query({ text: 'client' })
</script>
<template>
<p>{{data?.greeting }}</p>
</template>
```