From 53d74aa130d734cdcedbb069fb05ad0007763709 Mon Sep 17 00:00:00 2001 From: Michael Brusegard <56915010+michaelbrusegard@users.noreply.github.com> Date: Sat, 31 Aug 2024 16:25:35 +0200 Subject: [PATCH] feat: started adding trpc --- bun.lockb | Bin 211506 -> 224786 bytes package.json | 10 +- src/app/api/data/[trpc]/route.ts | 33 ++++++ src/components/providers/RootProviders.tsx | 5 +- src/components/providers/TRPCProvider.tsx | 57 +++++++++++ src/components/providers/ThemeProvider.tsx | 10 +- src/lib/api/client.ts | 23 +++++ src/lib/api/queryClient.ts | 28 ++++++ src/lib/api/server.ts | 31 ++++++ src/server/api/root.ts | 25 +++++ src/server/api/routers/test.ts | 14 +++ src/server/api/trpc.ts | 111 +++++++++++++++++++++ 12 files changed, 337 insertions(+), 10 deletions(-) create mode 100644 src/app/api/data/[trpc]/route.ts create mode 100644 src/components/providers/TRPCProvider.tsx create mode 100644 src/lib/api/client.ts create mode 100644 src/lib/api/queryClient.ts create mode 100644 src/lib/api/server.ts create mode 100644 src/server/api/root.ts create mode 100644 src/server/api/routers/test.ts create mode 100644 src/server/api/trpc.ts diff --git a/bun.lockb b/bun.lockb index 747835e41d95da1d433e33972333db8a34b137c7..ebf6923c44a4393c76b0f648ffb143ae6b546a67 100755 GIT binary patch delta 49728 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 delta 41952 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 diff --git a/package.json b/package.json index 58fa80e..61d917a 100644 --- a/package.json +++ b/package.json @@ -30,11 +30,12 @@ "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.1", "@t3-oss/env-nextjs": "^0.10.1", - "@tanstack/react-query": "^5.45.1", - "@trpc/client": "^10.45.2", - "@trpc/react-query": "^10.45.2", - "@trpc/server": "^10.45.2", + "@tanstack/react-query": "^5.53.1", + "@trpc/client": "^11.0.0-rc.490", + "@trpc/react-query": "^11.0.0-rc.490", + "@trpc/server": "^11.0.0-rc.490", "autoprefixer": "^10.4.19", + "client-only": "^0.0.1", "cmdk": "1.0.0", "country-flag-icons": "^1.5.12", "cva": "^1.0.0-beta.1", @@ -52,6 +53,7 @@ "reading-time": "^1.5.0", "server-only": "^0.0.1", "sharp": "^0.33.4", + "superjson": "^2.2.1", "tailwind-merge": "^2.5.2", "zod": "^3.23.8" }, diff --git a/src/app/api/data/[trpc]/route.ts b/src/app/api/data/[trpc]/route.ts new file mode 100644 index 0000000..754ffb8 --- /dev/null +++ b/src/app/api/data/[trpc]/route.ts @@ -0,0 +1,33 @@ +import { env } from '@/env'; +import { appRouter } from '@/server/api/root'; +import { createTRPCContext } from '@/server/api/trpc'; +import { fetchRequestHandler } from '@trpc/server/adapters/fetch'; +import type { NextRequest } from 'next/server'; + +/** + * This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when + * handling a HTTP request (e.g. when you make requests from Client Components). + */ +const createContext = async (request: NextRequest) => { + return createTRPCContext({ + headers: request.headers, + }); +}; + +const handler = (request: NextRequest) => + fetchRequestHandler({ + endpoint: '/api/data', + req: request, + router: appRouter, + createContext: () => createContext(request), + onError: + env.NODE_ENV === 'development' + ? ({ path, error }) => { + console.error( + `❌ tRPC failed on ${path ?? ''}: ${error.message}`, + ); + } + : undefined, + }); + +export { handler as GET, handler as POST }; diff --git a/src/components/providers/RootProviders.tsx b/src/components/providers/RootProviders.tsx index 0f2502c..d4f5704 100644 --- a/src/components/providers/RootProviders.tsx +++ b/src/components/providers/RootProviders.tsx @@ -1,4 +1,5 @@ import { IntlErrorProvider } from '@/components/providers/IntlErrorProvider'; +import { TRPCProvider } from '@/components/providers/TRPCProvider'; import { ThemeProvider } from '@/components/providers/ThemeProvider'; type RootProvidersProps = { @@ -9,7 +10,9 @@ type RootProvidersProps = { function RootProviders({ children, locale }: RootProvidersProps) { return ( - {children} + + {children} + ); } diff --git a/src/components/providers/TRPCProvider.tsx b/src/components/providers/TRPCProvider.tsx new file mode 100644 index 0000000..45b6cad --- /dev/null +++ b/src/components/providers/TRPCProvider.tsx @@ -0,0 +1,57 @@ +'use client'; + +import { env } from '@/env'; +import { api } from '@/lib/api/client'; +import { createQueryClient } from '@/lib/api/queryClient'; +import { type QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { loggerLink, unstable_httpBatchStreamLink } from '@trpc/client'; +import { useState } from 'react'; +import SuperJSON from 'superjson'; + +let clientQueryClientSingleton: QueryClient | undefined = undefined; +const getQueryClient = () => { + if (typeof window === 'undefined') { + // Server: always make a new query client + return createQueryClient(); + } + // Browser: use singleton pattern to keep the same query client + if (!clientQueryClientSingleton) { + clientQueryClientSingleton = createQueryClient(); + } + return clientQueryClientSingleton; +}; + +function TRPCProvider(props: { children: React.ReactNode }) { + const queryClient = getQueryClient(); + + const [trpcClient] = useState(() => + api.createClient({ + links: [ + loggerLink({ + enabled: (op) => + process.env.NODE_ENV === 'development' || + (op.direction === 'down' && op.result instanceof Error), + }), + unstable_httpBatchStreamLink({ + transformer: SuperJSON, + url: `${env.SITE_URL}/api/data`, + headers: () => { + const headers = new Headers(); + headers.set('x-trpc-source', 'nextjs-react'); + return headers; + }, + }), + ], + }), + ); + + return ( + + + {props.children} + + + ); +} + +export { TRPCProvider }; diff --git a/src/components/providers/ThemeProvider.tsx b/src/components/providers/ThemeProvider.tsx index 6c06483..39919b9 100644 --- a/src/components/providers/ThemeProvider.tsx +++ b/src/components/providers/ThemeProvider.tsx @@ -1,18 +1,18 @@ 'use client'; -import { ThemeProvider } from 'next-themes'; +import { ThemeProvider as NextThemeProvider } from 'next-themes'; -function NextThemeProvider({ children }: { children: React.ReactNode }) { +function ThemeProvider({ children }: { children: React.ReactNode }) { return ( - {children} - + ); } -export { NextThemeProvider as ThemeProvider }; +export { ThemeProvider }; diff --git a/src/lib/api/client.ts b/src/lib/api/client.ts new file mode 100644 index 0000000..df56eaf --- /dev/null +++ b/src/lib/api/client.ts @@ -0,0 +1,23 @@ +'use client'; + +import type { AppRouter } from '@/server/api/root'; +import { createTRPCReact } from '@trpc/react-query'; +import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server'; + +const api = createTRPCReact(); + +/** + * Inference helper for inputs. + * + * @example type HelloInput = RouterInputs['example']['hello'] + */ +type RouterInputs = inferRouterInputs; + +/** + * Inference helper for outputs. + * + * @example type HelloOutput = RouterOutputs['example']['hello'] + */ +type RouterOutputs = inferRouterOutputs; + +export { api, type RouterInputs, type RouterOutputs }; diff --git a/src/lib/api/queryClient.ts b/src/lib/api/queryClient.ts new file mode 100644 index 0000000..b121db5 --- /dev/null +++ b/src/lib/api/queryClient.ts @@ -0,0 +1,28 @@ +import { + QueryClient, + defaultShouldDehydrateQuery, +} from '@tanstack/react-query'; +import SuperJSON from 'superjson'; + +function createQueryClient() { + return new QueryClient({ + defaultOptions: { + queries: { + // With SSR, we usually want to set some default staleTime + // above 0 to avoid refetching immediately on the client + staleTime: 30 * 1000, + }, + dehydrate: { + serializeData: SuperJSON.serialize, + shouldDehydrateQuery: (query) => + defaultShouldDehydrateQuery(query) || + query.state.status === 'pending', + }, + hydrate: { + deserializeData: SuperJSON.deserialize, + }, + }, + }); +} + +export { createQueryClient }; diff --git a/src/lib/api/server.ts b/src/lib/api/server.ts new file mode 100644 index 0000000..6b37eda --- /dev/null +++ b/src/lib/api/server.ts @@ -0,0 +1,31 @@ +import 'server-only'; + +import { createQueryClient } from '@/lib/api/queryClient'; +import { type AppRouter, createCaller } from '@/server/api/root'; +import { createTRPCContext } from '@/server/api/trpc'; +import { createHydrationHelpers } from '@trpc/react-query/rsc'; +import { headers } from 'next/headers'; +import { cache } from 'react'; + +/** + * This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when + * handling a tRPC call from a React Server Component. + */ +const createContext = cache(() => { + const heads = new Headers(headers()); + heads.set('x-trpc-source', 'rsc'); + + return createTRPCContext({ + headers: heads, + }); +}); + +const getQueryClient = cache(createQueryClient); +const caller = createCaller(createContext); + +const { trpc: api, HydrateClient } = createHydrationHelpers( + caller, + getQueryClient, +); + +export { api, HydrateClient }; diff --git a/src/server/api/root.ts b/src/server/api/root.ts new file mode 100644 index 0000000..40ea9cb --- /dev/null +++ b/src/server/api/root.ts @@ -0,0 +1,25 @@ +import { testRouter } from '@/server/api/routers/test'; +import { createCallerFactory, createTRPCRouter } from '@/server/api/trpc'; + +/** + * This is the primary router for your server. + * + * All routers added in /api/routers should be manually added here. + */ +const appRouter = createTRPCRouter({ + test: testRouter, +}); + +// export type definition of API +type AppRouter = typeof appRouter; + +/** + * Create a server-side caller for the tRPC API. + * @example + * const trpc = createCaller(createContext); + * const res = await trpc.post.all(); + * ^? Post[] + */ +const createCaller = createCallerFactory(appRouter); + +export { appRouter, createCaller, type AppRouter }; diff --git a/src/server/api/routers/test.ts b/src/server/api/routers/test.ts new file mode 100644 index 0000000..41a3340 --- /dev/null +++ b/src/server/api/routers/test.ts @@ -0,0 +1,14 @@ +import { createTRPCRouter, publicProcedure } from '@/server/api/trpc'; +import { posts } from '@/server/db/schema'; + +const testRouter = createTRPCRouter({ + getLatest: publicProcedure.query(async ({ ctx }) => { + const post = await ctx.db.query.posts.findFirst({ + orderBy: (posts, { desc }) => [desc(posts.createdAt)], + }); + + return post ?? null; + }), +}); + +export { testRouter }; diff --git a/src/server/api/trpc.ts b/src/server/api/trpc.ts new file mode 100644 index 0000000..db0f9d6 --- /dev/null +++ b/src/server/api/trpc.ts @@ -0,0 +1,111 @@ +import { auth } from '@/server/auth'; +import { db } from '@/server/db'; +import { s3 } from '@/server/s3'; +/** + * YOU PROBABLY DON'T NEED TO EDIT THIS FILE, UNLESS: + * 1. You want to modify request context (see Part 1). + * 2. You want to create a new middleware or type of procedure (see Part 3). + * + * TL;DR - This is where all the tRPC server stuff is created and plugged in. The pieces you will + * need to use are documented accordingly near the end. + */ +import { initTRPC } from '@trpc/server'; +import superjson from 'superjson'; +import { ZodError } from 'zod'; + +/** + * 1. CONTEXT + * + * This section defines the "contexts" that are available in the backend API. + * + * These allow you to access things when processing a request, like the database, the session, etc. + * + * This helper generates the "internals" for a tRPC context. The API handler and RSC clients each + * wrap this and provides the required context. + * + * @see https://trpc.io/docs/server/context + */ +export const createTRPCContext = async (opts: { headers: Headers }) => { + return { + auth, + db, + s3, + ...opts, + }; +}; + +/** + * 2. INITIALIZATION + * + * This is where the tRPC API is initialized, connecting the context and transformer. We also parse + * ZodErrors so that you get typesafety on the frontend if your procedure fails due to validation + * errors on the backend. + */ +const t = initTRPC.context().create({ + transformer: superjson, + errorFormatter({ shape, error }) { + return { + ...shape, + data: { + ...shape.data, + zodError: + error.cause instanceof ZodError ? error.cause.flatten() : null, + }, + }; + }, +}); + +/** + * Create a server-side caller. + * + * @see https://trpc.io/docs/server/server-side-calls + */ +const createCallerFactory = t.createCallerFactory; + +/** + * 3. ROUTER & PROCEDURE (THE IMPORTANT BIT) + * + * These are the pieces you use to build your tRPC API. You should import these a lot in the + * "/src/server/api/routers" directory. + */ + +/** + * This is how you create new routers and sub-routers in your tRPC API. + * + * @see https://trpc.io/docs/router + */ +const createTRPCRouter = t.router; + +/** + * Middleware for timing procedure execution and adding an artificial delay in development. + * + * You can remove this if you don't like it, but it can help catch unwanted waterfalls by simulating + * network latency that would occur in production but not in local development. + */ +const timingMiddleware = t.middleware(async ({ next, path }) => { + const start = Date.now(); + + if (t._config.isDev) { + // artificial delay in dev + const waitMs = Math.floor(Math.random() * 400) + 100; + await new Promise((resolve) => setTimeout(resolve, waitMs)); + } + + const result = await next(); + + const end = Date.now(); + console.log(`[TRPC] ${path} took ${end - start}ms to execute`); + + return result; +}); + +/** + * Public (unauthenticated) procedure + * + * This is the base piece you use to build new queries and mutations on your tRPC API. It does not + * guarantee that a user querying is authorized, but you can still access user session data if they + * are logged in. + */ +const publicProcedure = t.procedure.use(timingMiddleware); + +export { createTRPCRouter, createCallerFactory, publicProcedure };