PageSourceSearch

https://matthuggins.com/assets/structuring-the-graphql-request-context-OGmELVnA.js

js matthuggins.com collected 2026-09-25 15:16:00 UTC 118,226 bytes, 492 lines download raw bytes

1import{t as n}from"./jsx-runtime-D_bcST6I.js";var s=n(),a={title:"Structuring the GraphQL Request Context",date:"2026-06-09",published:!0,tags:["graphql","node.js","typescript","javascript"],summary:"My approach to shaping an Apollo server's GraphQL context around three fields: a resolved current user, a shared data layer, and a fresh set of DataLoaders.",image:"/blog/structuring-the-graphql-request-context.jpg",thumbnail:"/blog/structuring-the-graphql-request-context.thumb.jpg"};function i(r){const e={a:"a",blockquote:"blockquote",button:"button",code:"code",div:"div",em:"em",h2:"h2",h3:"h3",li:"li",ol:"ol",p:"p",pre:"pre",span:"span",strong:"strong",ul:"ul",...r.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(e.p,{children:["There's a lot written about modeling a GraphQL schema, but less about the other half of standing up a server: ",(0,s.jsx)(e.strong,{children:"what I put into the per-request context every resolver receives."})]}),`
2`,(0,s.jsx)(e.p,{children:"The context is an important design decision in an Apollo server, because every resolver receives it and nothing else ambient is allowed in. It's powerful because a well-shaped context keeps your resolvers small, testable, and free of import-time coupling. It helps avoid reaching for module-level singletons, leaking state between requests, or firing one database query per row."}),`
3`,(0,s.jsx)(e.p,{children:"I'll use a small, recognizable e-commerce domain throughout (users, products, orders, order line items) so the examples stay concrete. My context has exactly three things on it:"}),`
4`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes github-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`// src/server/types/RequestContext.ts
5import type { PrismaClient, User } from '@prisma/client';
6import { DataLoaders } from '@/server/dataLoaders';
7
8export interface RequestContext {
9  currentUser?: User;
10  prisma: PrismaClient;
11  dataLoaders: DataLoaders;
12}`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#6A737D","--shiki-dark":"#6A737D"},children:"// src/server/types/RequestContext.ts"})}),`
13`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" type"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { PrismaClient, User } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@prisma/client'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
14`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { DataLoaders } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@/server/dataLoaders'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
15`,(0,s.jsx)(e.span,{className:"line"}),`
16`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"export"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" interface"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" RequestContext"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
17`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB
1770"},children:"  currentUser"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"?:"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" User"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
18`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"  prisma"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" PrismaClient"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
19`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"  dataLoaders"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" DataLoaders"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
20`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})]})}),`
21`,(0,s.jsxs)(e.ul,{children:[`
22`,(0,s.jsxs)(e.li,{children:[(0,s.jsx)(e.code,{children:"currentUser"}),": who's making the request, resolved from the auth token (or ",(0,s.jsx)(e.code,{children:"undefined"})," if anonymous)"]}),`
23`,(0,s.jsxs)(e.li,{children:[(0,s.jsx)(e.code,{children:"prisma"}),": the Prisma client the resolvers read and write through"]}),`
24`,(0,s.jsxs)(e.li,{children:[(0,s.jsx)(e.code,{children:"dataLoaders"}),": a fresh set of batching loaders, created once per request"]}),`
25`]}),`
26`,(0,s.jsxs)(e.p,{children:["Let's build the server around that shape and then dig into ",(0,s.jsx)(e.em,{children:"why"})," the last two are valuable."]}),`
27`,(0,s.jsx)(e.h2,{children:"The server bootstrap"}),`
28`,(0,s.jsx)(e.p,{children:"The entire server is one file. Here it is, then I'll walk through it:"}),`
29`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes github-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`// src/server/index.ts
30import '@/env';
31import { ApolloServer } from '@apollo/server';
32import { startStandaloneServer } from '@apollo/server/standalone';
33import { Prisma, type User } from '@prisma/client';
34import { GraphQLError } from 'graphql';
35import { z } from 'zod';
36import { jwtSecret } from '@/constants/jwt';
37import { prisma } from '@/db/prisma';
38import { decorateValidationError } from '@/errors/decorateValidationError';
39import { RequestContext } from '@/server/types/RequestContext';
40import { verifyToken } from '@/utils/authToken';
41import { createDataLoaders } from './dataLoaders';
42import { schema } from './schema';
43
44const port = parseInt(process.env.PORT || '3000', 10);
45
46const getToken = (authorizationHeader: string | undefined) => {
47  if (!authorizationHeader) {
48    return undefined;
49  }
50  const [scheme, parameters] = authorizationHeader.split(/ +/, 2);
51  return scheme === 'Bearer' ? parameters : undefined;
52};
53
54const getCurrentUser = async (token: string | undefined): Promise<User | undefined> => {
55  if (!token) {
56    return undefined;
57  }
58  const payload = verifyToken({ token, secret: jwtSecret });
59  const user = payload && (await prisma.user.findUnique({ where: { email: payload.email } }));
60  return user ?? undefined;
61};
62
63const server = new ApolloServer<RequestContext>({
64  schema,
65  formatError: (formattedError, error) => {
66    const { originalError } = error as GraphQLError;
67    if (
68      originalError instanceof Prisma.PrismaClientKnownRequestError ||
69      originalError instanceof z.ZodError
70    ) {
71      return decorateValidationError(formattedError, originalError);
72    }
73    if (originalError) {
74      console.error(originalError);
75    }
76    return formattedError;
77  },
78});
79
80startStandaloneServer(server, {
81  listen: { port },
82  context: async ({ req }) => ({
83    currentUser: await getCurrentUser(getToken(req.headers.authorization)),
84    prisma,
85    dataLoaders: createDataLoaders(),
86  }),
87})
88  .then(({ url }) => {
89    console.log(\`🚀  Server started: \${url}\`);
90  })
91  .catch((err) => {
92    throw err;
93  });`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#6A737D","--shiki-dark":"#6A737D"},children:"// src/server/index.ts"})}),`
94`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@/env'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
95`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { ApolloServer } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@apollo/server'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
96`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { startStandaloneServer } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@apollo/server/standalone'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
97`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { Prisma, "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"type"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" User } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@prisma/client'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
98`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { GraphQLError } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" 'graphql'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
99`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { z } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" 'zod'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
100`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { jwtSecret } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@/constants/jwt'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
101`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { prisma } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@/db/prisma'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
102`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { decorateValidationError } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@/errors/decorateValidationError'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
103`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { RequestContext } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@/server/types/RequestContext'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
104`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { verifyToken } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@/utils/authToken'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
105`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { createDataLoaders } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" './dataLoaders'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
106`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { schema } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" './schema'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
107`,(0,s.jsx)(e.span,{className:"line"}),`
108`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" port"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" parseInt"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(process.env."}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"PORT"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ||"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '3000'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"10"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),`
109`,(0,s.jsx)(e.span,{className:"line"}),`
110`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" getToken"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB
11070"},children:"authorizationHeader"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" string"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" |"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:") "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
111`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  if"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"!"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"authorizationHeader) {"})]}),`
112`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    return"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
113`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  }"})}),`
114`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  const"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ["}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"scheme"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"parameters"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"] "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" authorizationHeader."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"split"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:"/"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" +"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:"/"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"2"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),`
115`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  return"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" scheme "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"==="}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" 'Bearer'"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ?"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" parameters "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
116`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"};"})}),`
117`,(0,s.jsx)(e.span,{className:"line"}),`
118`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" getCurrentUser"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" async"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB
11870"},children:"token"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" string"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" |"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:")"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" Promise"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"User"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" |"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
119`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  if"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"!"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"token) {"})]}),`
120`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    return"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
121`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  }"})}),`
122`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" payload"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" verifyToken"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"({ token, secret: jwtSecret });"})]}),`
123`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" user"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" payload "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"&&"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" prisma.user."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"findUnique"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"({ where: { email: payload.email } }));"})]}),`
124`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  return"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" user "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"??"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
125`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"};"})}),`
126`,(0,s.jsx)(e.span,{className:"line"}),`
127`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" server"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" new"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" ApolloServer"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"RequestContext"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:">({"})]}),`
128`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  schema,"})}),`
129`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"  formatError"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": ("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB
12970"},children:"formattedError"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"error"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:") "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
130`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    const"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"originalError"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" error "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"as"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" GraphQLError"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
131`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    if"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("})]}),`
132`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"      originalError "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"instanceof"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" Prisma"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"PrismaClientKnownRequestError"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ||"})]}),`
133`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"      originalError "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"instanceof"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" z"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"ZodError"})]}),`
134`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    ) {"})}),`
135`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"      return"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" decorateValidationError"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(formattedError, originalError);"})]}),`
136`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    }"})}),`
137`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    if"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" (originalError) {"})]}),`
138`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"      console."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"error"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(originalError);"})]}),`
139`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    }"})}),`
140`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    return"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" formattedError;"})]}),`
141`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  },"})}),`
142`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"});"})}),`
143`,(0,s.jsx)(e.span,{className:"line"}),`
144`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"startStandaloneServer"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(server, {"})]}),`
145`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  listen: { port },"})}),`
146`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"  context"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ({ "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB
14670"},children:"req"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" }) "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ({"})]}),`
147`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    currentUser: "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" getCurrentUser"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"getToken"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(req.headers.authorization)),"})]}),`
148`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    prisma,"})}),`
149`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    dataLoaders: "}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"createDataLoaders"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),`
150`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  }),"})}),`
151`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"})"})}),`
152`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  ."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"then"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(({ "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"url"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" }) "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
153`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    console."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"log"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:"`🚀  Server started: ${"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"url"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:"}`"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:");"})]}),`
154`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  })"})}),`
155`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  ."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"catch"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"err"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:") "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
156`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    throw"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" err;"})]}),`
157`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  });"})})]})]})}),`
158`,(0,s.jsxs)(e.p,{children:[(0,s.jsx)(e.code,{children:"new ApolloServer<RequestContext>"})," is typed with the context interface, so every resolver gets full IntelliSense on ",(0,s.jsx)(e.code,{children:"context"})," and the compiler rejects any resolver that assumes a field the context doesn't actually provide."]}),`
159`,(0,s.jsxs)(e.p,{children:["The piece that runs on every single request is the ",(0,s.jsx)(e.code,{children:"context"})," factory:"]}),`
160`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes g
160ithub-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`context: async ({ req }) => ({
161  currentUser: await getCurrentUser(getToken(req.headers.authorization)),
162  prisma,
163  dataLoaders: createDataLoaders(),
164}),`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"context"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ({ "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"req"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" }) "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ({"})]}),`
165`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  currentUser: "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" getCurrentUser"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"getToken"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(req.headers.authorization)),"})]}),`
166`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  prisma,"})}),`
167`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  dataLoaders: "}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"createDataLoaders"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),`
168`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"}),"})})]})]})}),`
169`,(0,s.jsx)(e.p,{children:"Each line handles one of the three context fields, which I'll dissect throughout the remainder of this post."}),`
170`,(0,s.jsxs)(e.h2,{children:[(0,s.jsx)(e.code,{children:"currentUser"}),": resolved per request"]}),`
171`,(0,s.jsx)(e.p,{children:"Authentication is request-scoped by definition, so it belongs in the context factory and nowhere else. The flow is deliberately small:"}),`
172`,(0,s.jsxs)(e.ol,{children:[`
173`,(0,s.jsxs)(e.li,{children:[(0,s.jsx)(e.code,{children:"getToken"})," pulls the ",(0,s.jsx)(e.code,{children:"Bearer <token>"})," value out of the ",(0,s.jsx)(e.code,{children:"Authorization"})," header (returning ",(0,s.jsx)(e.code,{children:"undefined"})," for anything that isn't a well-formed bearer scheme)."]}),`
174`,(0,s.jsxs)(e.li,{children:[(0,s.jsx)(e.code,{children:"getCurrentUser"})," verifies the JWT and, if valid, looks up the matching user."]}),`
175`]}),`
176`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes github-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`const getCurrentUser = async (token: string | undefined): Promise<User | undefined> => {
177  if (!token) {
178    return undefined;
179  }
180  const payload = verifyToken({ token, secret: jwtSecret });
181  const user = payload && (await prisma.user.findUnique({ where: { email: payload.email } }));
182  return user ?? undefined;
183};`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" getCurrentUser"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" async"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB
18370"},children:"token"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" string"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" |"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:")"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" Promise"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"User"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" |"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"> "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
184`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  if"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"!"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"token) {"})]}),`
185`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    return"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
186`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  }"})}),`
187`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" payload"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" verifyToken"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"({ token, secret: jwtSecret });"})]}),`
188`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" user"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" payload "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"&&"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"await"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" prisma.user."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"findUnique"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"({ where: { email: payload.email } }));"})]}),`
189`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  return"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" user "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"??"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
190`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"};"})})]})]})}),`
191`,(0,s.jsx)(e.p,{children:"The JWT helper keeps verification honest by validating the decoded payload with Zod, so a malformed or tampered token can't smuggle a bad shape into the rest of the app:"}),`
192`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes g
192ithub-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`// src/utils/authToken.ts
193import jwt from 'jsonwebtoken';
194import { z } from 'zod';
195import type { User } from '@prisma/client';
196
197type TokenPayload = Pick<User, 'id' | 'email'>;
198
199const tokenSchema = z.object({
200  id: z.string().uuid(),
201  email: z.string(),
202});
203
204export const verifyToken = ({ token, secret }: { token: string; secret: string }):
205  | TokenPayload
206  | undefined => {
207  try {
208    const payload = jwt.verify(token, secret);
209    return tokenSchema.parse(payload);
210  } catch (err) {
211    return undefined;
212  }
213};`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#6A737D","--shiki-dark":"#6A737D"},children:"// src/utils/authToken.ts"})}),`
214`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" jwt "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" 'jsonwebtoken'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
215`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { z } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" 'zod'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
216`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" type"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { User } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@prisma/client'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
217`,(0,s.jsx)(e.span,{className:"line"}),`
218`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"type"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" TokenPayload"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" Pick"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"User"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:"'id'"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" |"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" 'email'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:">;"})]}),`
219`,(0,s.jsx)(e.span,{className:"line"}),`
220`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" tokenSchema"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" z."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"object"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"({"})]}),`
221`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  id: z."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"string"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"}
221,children:"()."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"uuid"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),`
222`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  email: z."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"string"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),`
223`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"});"})}),`
224`,(0,s.jsx)(e.span,{className:"line"}),`
225`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"export"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" verifyToken"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ({ token, secret }: { token: string; secret: string }):"})]}),`
226`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  |"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" TokenPayload"})]}),`
227`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  |"}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" =>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
228`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  try"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
229`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" payload"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" jwt."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"verify"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(token, secret);"})]}),`
230`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    return"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" tokenSchema."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"parse"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(payload);"})]}),`
231`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"catch"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" (err) {"})]}),`
232`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    return"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" undefined"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
233`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  }"})}),`
234`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"};"})})]})]})}),`
235`,(0,s.jsxs)(e.p,{children:["By the time a resolver runs, ",(0,s.jsx)(e.code,{children:"currentUser"})," is either a fully populated ",(0,s.jsx)(e.code,{children:"User"})," record or ",(0,s.jsx)(e.code,{children:"undefined"}),". Resolvers never parse headers or verify tokens themselves; they just check ",(0,s.jsx)(e.code,{children:"context.currentUser"}),". An authentication middleware can lean on that, and so can a plain resolver:"]}
235),`
236`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes github-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":"currentUser: (_parent, _args, { currentUser }) => currentUser ?? null,"})]}),(0,s.jsx)(e.code,{children:(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"currentUser"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": ("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"_parent"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"_args"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:", { "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"currentUser"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" }) "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" currentUser "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"??"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" null"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:","})]})})]})}),`
237`,(0,s.jsxs)(e.p,{children:["Notice that ",(0,s.jsx)(e.code,{children:"getCurrentUser"})," already goes through ",(0,s.jsx)(e.code,{children:"prisma.user"}),": even authentication reads through the same client everything else does. Which brings us to the first of the two interesting context fields."]}),`
238`,(0,s.jsxs)(e.h2,{children:[(0,s.jsx)(e.code,{children:"prisma"}),": why pass the client around at all?"]}),`
239`,(0,s.jsxs)(e.p,{children:[(0,s.jsx)(e.code,{children:"prisma"})," is just the generated ",(0,s.jsx)(e.a,{href:"https://www.prisma.io/",children:"Prisma"})," client, instantiated once and shared across the whole process:"]}),`
240`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes github-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`// src/db/prisma.ts
241import { PrismaClient } from '@prisma/client';
242import { isProduction } from '@/env';
243
244const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient };
245
246export const prisma = globalForPrisma.prisma ?? new PrismaClient();
247
248if (!isProduction) {
249  globalForPrisma.prisma = prisma;
250}`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#6A737D","--shiki-dark":"#6A737D"},children:"// src/db/prisma.ts"})}),`
251`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { PrismaClient } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@prisma/client'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
252`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { isProduction } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@/env'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
253`,(0,s.jsx)(e.span,{className:"line"}),`
254`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" globalForPrisma"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" globalThis "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"as"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" unknown"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" as"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB
25470"},children:"prisma"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"?:"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" PrismaClient"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" };"})]}),`
255`,(0,s.jsx)(e.span,{className:"line"}),`
256`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"export"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" prisma"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" globalForPrisma.prisma "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"??"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" new"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" PrismaClient"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"();"})]}),`
257`,(0,s.jsx)(e.span,{className:"line"}),`
258`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"if"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"!"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"isProduction) {"})]}),`
259`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  globalForPrisma.prisma "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" prisma;"})]}),`
260`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})]})}),`
261`,(0,s.jsxs)(e.p,{children:["The client owns a connection pool and a query engine, so it's meant to be created once and reused. The ",(0,s.jsx)(e.code,{children:"globalThis"})," guard just keeps hot reloads in development from spawning a fresh pool on every code change. The models themselves, and the relations between them, are declared in the Prisma schema rather than wired up in code:"]}),`
262`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes github-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"prisma",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"prisma"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`// prisma/schema.prisma (abridged)
263model User {
264  id     String  @id @default(uuid())
265  email  String  @unique
266  orders Order[]
267}
268
269model Order {
270  id        String      @id @default(uuid())
271  userId    String
272  createdAt DateTime    @default(now())
273  user      User        @relation(fields: [userId], references: [id])
274  items     OrderItem[]
275}
276
277model OrderItem {
278  id        String  @id @default(uuid())
279  orderId   String
280  productId String
281  quantity  Int
282  order     Order   @relation(fields: [orderId], references: [id])
283  product   Product @relation(fields: [productId], references: [id])
284}
285
286model Product {
287  id         String      @id @default(uuid())
288  name       String
289  orderItems OrderItem[]
290}`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#6A737D","--shiki-dark":"#6A737D"},children:"// prisma/schema.prisma (abridged)"})}),`
291`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"model"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" User"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
292`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  id     "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"  @id"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" @default"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"uuid"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"}
292,children:"())"})]}),`
293`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  email  "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"  @unique"})]}),`
294`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  orders "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"Order"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"[]"})]}),`
295`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})}),`
296`,(0,s.jsx)(e.span,{className:"line"}),`
297`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"model"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" Order"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
298`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  id        "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"      @id"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" @default"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"uuid"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"())"})]}),`
299`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  userId    "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"String"})]}),`
300`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  createdAt "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"DateTime"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"    @default"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"now"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"())"})]}),`
301`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  user      "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"User"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"        @relation"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"fields"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": ["}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"userId"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"], "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"references"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": ["}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"id"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"])"})]}),`
302`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  items     "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"OrderItem"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"[]"})]}),`
303`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})}),`
304`,(0,s.jsx)(e.span,{className:"line"}),`
305`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"model"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" OrderItem"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
306`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  id        "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"  @id"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" @default"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"uuid"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"}
306,children:"())"})]}),`
307`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  orderId   "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"String"})]}),`
308`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  productId "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"String"})]}),`
309`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  quantity  "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"Int"})]}),`
310`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  order     "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"Order"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"   @relation"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"fields"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": ["}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"orderId"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"], "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"references"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": ["}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"id"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"])"})]}),`
311`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  product   "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"Product"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" @relation"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"fields"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": ["}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"productId"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"], "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"references"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": ["}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"id"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"])"})]}),`
312`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})}),`
313`,(0,s.jsx)(e.span,{className:"line"}),`
314`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"model"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" Product"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
315`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  id         "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"String"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"      @id"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" @default"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"uuid"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"())"})]}),`
316`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  name       "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"String"})]}),`
317`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  orderItems "}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:"OrderItem"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"[]"})]}),`
318`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})]})}),`
319`,(0,s.jsxs)(e.p,{children:["Running ",(0,s.jsx)(e.code,{children:"prisma generate"})," turns that schema into a fully typed client, with every model hanging off it as a property: ",(0,s.jsx)(e.code,{children:"prisma.user"}),", ",(0,s.jsx)(e.code,{children:"prisma.order"}),", ",(0,s.jsx)(e.code,{children:"prisma.orderItem"}),", each exposing ",(0,s.jsx)(e.code,{children:"findUnique"}),", ",(0,s.jsx)(e.code,{children:"findMany"}),", ",(0,s.jsx)(e.code,{children:"create"}),", and the rest."]}),`
320`,(0,s.jsxs)(e.p,{children:["A reasonable question: ",(0,s.jsx)(e.code,{children:"prisma"})," is a plain module export, so a resolver could just ",(0,s.jsx)(e.code,{children:"import { prisma } from '@/db/prisma'"})," directly. Why thread it through the context as a field at all?"]}),`
321`,(0,s.jsx)(e.p,{children:"A few reasons, in roughly the order I care about them:"}),`
322`,(0,s.jsxs)(e.p,{children:[(0,s.jsx)(e.strong,{children:"1. Testability and seam control."})," When the data layer arrives through the context, a test can construct a context with a stand-in ",(0,s.jsx)(e.code,{children:"prisma"})," (a mock client, or one pointed at a test database) and a resolver doesn't know the difference. Resolvers become pure functions of ",(0,s.jsx)(e.code,{children:"(args, context)"}),": no hidden imports to intercept, no module mocking, no ",(0,s.jsx)(e.code,{children:"jest.mock('@/db/prisma')"})," at the top of every test file. The dependency is ",(0,s.jsx)(e.em,{children:"injected"}),", not reached for."]}),`
323`,(0,s.jsxs)(e.p,{children:[(0,s.jsx)(e.strong,{children:"2. One blessed surface."})," ",(0,s.jsx)(e.code,{children:"context.prisma"})," is the ",(0,s.jsx)(e.em,{children:"only"})," sanctioned way into the database from a resolver. That convention makes data access trivially greppable and gives me one obvious place to add cross-cutting behavior later (query logging, a read-replica router, per
323-tenant scoping, all of which Prisma's client extensions make easy) without editing hundreds of import statements."]}),`
324`,(0,s.jsxs)(e.p,{children:[(0,s.jsx)(e.strong,{children:"3. Consistency with everything else on the context."})," ",(0,s.jsx)(e.code,{children:"currentUser"})," and ",(0,s.jsx)(e.code,{children:"dataLoaders"})," are already request-scoped values handed in via context. Routing database access the same way means a resolver has a single mental model: ",(0,s.jsxs)(e.em,{children:["everything I need comes from ",(0,s.jsx)(e.code,{children:"context"}),"."]}),' No special cases, no "well, the client is different."']}),`
325`,(0,s.jsxs)(e.p,{children:[(0,s.jsx)(e.strong,{children:"4. It documents intent in the type."})," Because ",(0,s.jsx)(e.code,{children:"RequestContext"})," declares ",(0,s.jsx)(e.code,{children:"prisma: PrismaClient"}),", the context's type spells out exactly what a resolver is allowed to reach for. The capability is visible at the type level rather than implied by whatever a file happens to import."]}),`
326`,(0,s.jsxs)(e.p,{children:["In practice, resolvers that need direct, un-batched access (typically mutations and top-level queries) pull ",(0,s.jsx)(e.code,{children:"prisma"})," straight off the context:"]}),`
327`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes github-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`// src/server/resolvers/userResolvers.ts
328export const userResolvers = {
329  Mutation: {
330    createUser: async (_parent, { input }, { prisma }) => {
331      const user = await prisma.user.create({ data: input });
332      const token = createToken({ user, secret: jwtSecret });
333      return { user, token };
334    },
335    createSession: async (_parent, { input }, { prisma }) => {
336      const user = await prisma.user.findUnique({
337        where: { email: input.email },
338      });
339      validateCreateSessionInput(input, user);
340      const token = createToken({ user, secret: jwtSecret });
341      return { user, token };
342    },
343  },
344} satisfies Resolvers;`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#6A737D","--shiki-dark":"#6A737D"},children:"// src/server/resolvers/userResolvers.ts"})}),`
345`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"export"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" userResolvers"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
346`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  Mutation: {"})}),`
347`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"    createUser"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"_parent"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:", { "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"input"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" }, { "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"prisma"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" }) "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
348`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"      const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" user"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" prisma.user."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"create"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"({ data: input });"})]}),`
349`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"      const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" token"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" createToken"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"({ user, secret: jwtSecret });"})]}),`
350`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"      return"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { user, token };"})]}),`
351`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    },"})}),`
352`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"    createSession"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:": "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB
35270"},children:"_parent"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:", { "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"input"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" }, { "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"prisma"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" }) "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
353`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"      const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" user"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" prisma.user."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"findUnique"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"({"})]}),`
354`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"        where: { email: input.email },"})}),`
355`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"      });"})}),`
356`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"      validateCreateSessionInput"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(input, user);"})]}),`
357`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"      const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" token"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" createToken"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"({ user, secret: jwtSecret });"})]}),`
358`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"      return"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { user, token };"})]}),`
359`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    },"})}),`
360`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  },"})}),`
361`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"} "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"satisfies"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" Resolvers"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]})]})]})}),`
362`,(0,s.jsxs)(e.p,{children:["Reaching for ",(0,s.jsx)(e.code,{children:"prisma"})," directly is the right tool when you're loading or writing a single, known record. It is ",(0,s.jsx)(e.em,{children:"not"})," the right tool when you're resolving the same kind of related record once per item in a list, and that's where the third context field earns its place."]}),`
363`,(0,s.jsxs)(e.h2,{children:[(0,s.jsx)(e.code,{children:"dataLoaders"}),": why a fresh batch per request?"]}),`
364`,(0,s.jsxs)(e.p,{children:["The classic GraphQL performance trap is the ",(0,s.jsx)(e.strong,{children:"N+1 query problem"}),". Imagine a query that returns 50 order items and asks for each item's parent order:"]}),`
365`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes github-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"graphql",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"graphql"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`query {
366  orderItems {
367    id
368    quantity
369    order {
370      id
371      createdAt
372    }
373  }
374}`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"query"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
375`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB
37570"},children:"  orderItems"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
376`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"    id"})}),`
377`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"    quantity"})}),`
378`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"    order"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
379`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"      id"})}),`
380`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"      createdAt"})}),`
381`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    }"})}),`
382`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  }"})}),`
383`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})]})}),`
384`,(0,s.jsxs)(e.p,{children:["The naive ",(0,s.jsx)(e.code,{children:"OrderItem.order"})," resolver runs once per item. Fifty items means one query to fetch the items, then fifty more queries to fetch each order individually: 51 round-trips to the database for what should be two. With deeper nesting it gets quadratically worse."]}),`
385`,(0,s.jsxs)(e.p,{children:[(0,s.jsx)(e.a,{href:"https://github.com/graphql/dataloader",children:"DataLoader"})," fixes this by ",(0,s.jsx)(e.strong,{children:"batching"})," and ",(0,s.jsx)(e.strong,{children:"caching"})," within a single request. Instead of querying immediately, each ",(0,s.jsx)(e.code,{children:".load(id)"})," call registers the id; DataLoader collects every id requested during the same tick of the event loop and resolves them all in one batched query. It also memoizes: ask for the same id twice and the second call returns the cached result."]}),`
386`,(0,s.jsxs)(e.blockquote,{children:[`
387`,(0,s.jsxs)(e.p,{children:["Prisma does some batching of its own: it transparently coalesces multiple ",(0,s.jsx)(e.code,{children:"findUnique"})," calls made in the same tick into a single query. That overlaps with DataLoader but doesn't replace it. Prisma's batching only covers ",(0,s.jsx)(e.code,{children:"findUnique"})," lookups by id, not the filtered ",(0,s.jsx)(e.code,{children:"findMany"})," loads below, and it doesn't memoize across resolver paths within a request. The two are complementary."]}),`
388`]}),`
389`,(0,s.jsx)(e.p,{children:"I create one set of loaders per request:"}),`
390`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes github-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`// src/server/dataLoaders/index.ts
391import { createOrderLoader } from './createOrderLoader';
392import { createProductLoader } from './createProductLoader';
393
394export const createDataLoaders = () => ({
395  orderLoader: createOrderLoader(),
396  productLoader: createProductLoader(),
397});
398
399export type DataLoaders = ReturnType<typeof createDataLoaders>;`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#6A737D","--shiki-dark":"#6A737D"},children:"// src/server/dataLoaders/index.ts"})}),`
400`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { createOrderLoader } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" './createOrderLoader'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
401`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { createProductLoader } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" './createProductLoader'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
402`,(0,s.jsx)(e.span,{className:"line"}),`
403`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"export"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" createDataLoaders"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" () "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ({"})]}),`
404`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  orderLoader: "}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"createOrderLoader"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"}
404,children:"(),"})]}),`
405`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  productLoader: "}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"createProductLoader"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(),"})]}),`
406`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"});"})}),`
407`,(0,s.jsx)(e.span,{className:"line"}),`
408`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"export"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" type"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" DataLoaders"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" ReturnType"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"<"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"typeof"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" createDataLoaders>;"})]})]})]})}),`
409`,(0,s.jsxs)(e.p,{children:["A single loader is just a batch function: given a list of ids, return the records in the ",(0,s.jsx)(e.em,{children:"same order"}),", with a slot for every id even if it wasn't found."]}),`
410`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes github-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`// src/server/dataLoaders/createOrderLoader.ts
411import DataLoader from 'dataloader';
412import type { Order } from '@prisma/client';
413import { prisma } from '@/db/prisma';
414
415export const createOrderLoader = () =>
416  new DataLoader(async (ids: readonly Order['id'][]) => {
417    const orders = await prisma.order.findMany({
418      where: { id: { in: [...ids] } },
419    });
420    return ids.map((id) => orders.find((order) => order.id === id));
421  });`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#6A737D","--shiki-dark":"#6A737D"},children:"// src/server/dataLoaders/createOrderLoader.ts"})}),`
422`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" DataLoader "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" 'dataloader'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
423`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" type"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { Order } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@prisma/client'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
424`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"import"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" { prisma } "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"from"}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:" '@/db/prisma'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
425`,(0,s.jsx)(e.span,{className:"line"}),`
426`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"export"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" createOrderLoader"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" () "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"})]}),`
427`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"  new"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" DataLoader"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB
42770"},children:"ids"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" readonly"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" Order"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"["}),(0,s.jsx)(e.span,{style:{color:"#032F62","--shiki-dark":"#9ECBFF"},children:"'id'"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"][]) "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
428`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" orders"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" prisma.order."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"findMany"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"({"})]}),`
429`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"      where: { id: { in: ["}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"..."}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"ids] } },"})]}),`
430`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    });"})}),`
431`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"    return"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ids."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"map"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"id"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:") "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" orders."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"find"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"order"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:") "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" order.id "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"==="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" id));"})]}),`
432`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  });"})})]})]})}),`
433`,(0,s.jsxs)(e.p,{children:["The contract DataLoader requires is subtle but important: the array you return must be ",(0,s.jsxs)(e.strong,{children:["exactly the same length as ",(0,s.jsx)(e.code,{children:"ids"}),", in the same order"]}),". That's why I map back over ",(0,s.jsx)(e.code,{children:"ids"})," and ",(0,s.jsx)(e.code,{children:"find"})," the matching row rather than just returning whatever ",(0,s.jsx)(e.code,{children:"findMany"})," produced, since the batch may come back in any order, and some ids may have no row at all."]}),`
434`,(0,s.jsxs)(e.blockquote,{children:[`
435`,(0,s.jsxs)(e.p,{children:["A nice bonus of routing loads through a function like this: the batch function is the natural place to shape each record before it reaches the schema, whether that's pulling in a relation with ",(0,s.jsx)(e.code,{children:"include"})," or mapping a derived field like ",(0,s.jsx)(e.code,{children:"lineTotal"})," onto every row, so resolvers receive records already in the form the schema expects."]}),`
436`]}),`
437`,(0,s.jsxs)(e.p,{children:["Now the ",(0,s.jsx)(e.code,{children:"OrderItem.order"})," resolver becomes a one-liner that participates in batching automatically:"]}),`
438`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes g
438ithub-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`// src/server/resolvers/orderItemResolvers.ts
439export const orderItemResolvers = {
440  OrderItem: {
441    order: composeResolvers(isAuthenticated(), async (orderItem, _args, { dataLoaders }) => {
442      const order = await dataLoaders.orderLoader.load(orderItem.orderId);
443      assertTruthy(order);
444      return order;
445    }),
446  },
447} satisfies Resolvers;`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#6A737D","--shiki-dark":"#6A737D"},children:"// src/server/resolvers/orderItemResolvers.ts"})}),`
448`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"export"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" orderItemResolvers"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
449`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  OrderItem: {"})}),`
450`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    order: "}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"composeResolvers"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"("}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"isAuthenticated"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(), "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"async"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" ("}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"orderItem"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:", "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"_args"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:", { "}),(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"dataLoaders"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" }) "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"=>"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
451`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"      const"}),(0,s.jsx)(e.span,{style:{color:"#005CC5","--shiki-dark":"#79B8FF"},children:" order"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" ="}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" await"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" dataLoaders.orderLoader."}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"load"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(orderItem.orderId);"})]}),`
452`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:"      assertTruthy"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"(order);"})]}),`
453`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"      return"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" order;"})]}),`
454`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"    }),"})}),`
455`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"  },"})}),`
456`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"} "}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"satisfies"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" Resolvers"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]})]})]})}),`
457`,(0,s.jsxs)(e.p,{children:["Fifty order items now produce ",(0,s.jsx)(e.strong,{children:"one"})," batched ",(0,s.jsx)(e.code,{children:"WHERE id IN (...)"})," query for their orders instead of fifty. The resolver code reads as if it's loading a single order; DataLoader handles the coalescing underneath."]}),`
458`,(0,s.jsxs)(e.h3,{children:["Why ",(0,s.jsx)(e.em,{children:"per request"}
458),", and not a singleton?"]}),`
459`,(0,s.jsxs)(e.p,{children:["This detail is easy to overlook, so it's worth stating plainly: ",(0,s.jsx)(e.strong,{children:"the loaders are created inside the context factory"}),", which means a brand-new set is built for every request. That's deliberate, and the per-request lifetime is exactly what makes them safe."]}),`
460`,(0,s.jsxs)(e.p,{children:["DataLoader caches by id ",(0,s.jsx)(e.em,{children:"for the lifetime of the loader"}),". That caching is a feature within one request (don't load the same order twice while resolving one query) and a ",(0,s.jsx)(e.strong,{children:"bug"})," if it outlives the request:"]}),`
461`,(0,s.jsxs)(e.ul,{children:[`
462`,(0,s.jsxs)(e.li,{children:["A long-lived, shared loader would happily serve ",(0,s.jsx)(e.strong,{children:"stale data"}),": once an order is cached, a later request would keep seeing the old version even after it changed."]}),`
463`,(0,s.jsxs)(e.li,{children:["It would leak data ",(0,s.jsx)(e.strong,{children:"across users and requests"}),". Request A loads order ",(0,s.jsx)(e.code,{children:"123"}),"; the cache now holds it; request B (possibly a different user) calls ",(0,s.jsx)(e.code,{children:".load('123')"})," and gets A's cached copy, sidestepping any fresh authorization or scoping."]}),`
464`]}),`
465`,(0,s.jsxs)(e.p,{children:["Creating the loaders per request gives each request its own short-lived cache that is born and discarded with the request. You get the batching and de-duplication benefits exactly where they're safe, and none of the cross-request hazards. ",(0,s.jsx)(e.code,{children:"prisma"}),", by contrast, holds no per-request state (just a connection pool that's built to be shared), so it's instantiated once and the same reference is handed to every context. The split is intentional: ",(0,s.jsx)(e.strong,{children:"share the stateless data layer, isolate the stateful cache."})]}),`
466`,(0,s.jsx)(e.h2,{children:"The whole picture"}),`
467`,(0,s.jsxs)(e.p,{children:["Standing up the server comes down to one typed ",(0,s.jsx)(e.code,{children:"ApolloServer<RequestContext>"})," and a context factory that, on every request:"]}),`
468`,(0,s.jsxs)(e.ol,{children:[`
469`,(0,s.jsxs)(e.li,{children:[(0,s.jsxs)(e.strong,{children:["Resolves ",(0,s.jsx)(e.code,{children:"currentUser"})]})," from the bearer token, so authorization is just a property check."]}),`
470`,(0,s.jsxs)(e.li,{children:[(0,s.jsxs)(e.strong,{children:["Hands over ",(0,s.jsx)(e.code,{children:"prisma"})]})," (the shared, stateless client) as the single, injectable, type-documented door to the database."]}),`
471`,(0,s.jsxs)(e.li,{children:[(0,s.jsxs)(e.strong,{children:["Builds a fresh ",(0,s.jsx)(e.code,{children:"dataLoaders"})]})," set, so related records batch into single queries and the per-request cache can't leak across requests."]}),`
472`]}),`
473`,(0,s.jsxs)(e.p,{children:[(0,s.jsx)(e.code,{children:"prisma"})," is shared because it holds no request state; ",(0,s.jsx)(e.code,{children:"dataLoaders"})," is rebuilt because it holds exactly the kind of state that must not outlive the request. Keep those two facts straight and the context does its job: every resolver is a small, testable function of ",(0,s.jsx)(e.code,{children:"(args, context)"}),", with nothing ambient hiding in the imports."]}),`
474`,(0,s.jsx)(e.h2,{children:"Room for improvement"}),`
475`,(0,s.jsxs)(e.p,{children:["This design has one more step in it, and it's the one I'd take next: drop ",(0,s.jsx)(e.code,{children:"prisma"})," from the context entirely and route ",(0,s.jsx)(e.em,{children:"every"})," database read through a loader."]}),`
476`,(0,s.jsxs)(e.p,{children:["Right now the context offers two doors to the database. Mutations and top-level queries reach for ",(0,s.jsx)(e.code,{children:"prisma"})," directly; relation fields go through ",(0,s.jsx)(e.code,{children:"dataLoaders"}),". That split works, but it leaves a gap that's easy to fall into: nothing stops a resolver from calling ",(0,s.jsx)(e.code,{children:"prisma.order.findUnique"})," inside a ",(0,s.jsx)(e.code,{children:".map"})," over a list and quietly reintroducing the exact N+1 problem the loaders exist to prevent. The batched path is ",(0,s.jsx)(e.em,{children:"available"})," when it should be ",(0,s.jsx)(e.em,{children:"mandatory"}),"."]}),`
477`,(0,s.jsxs)(e.p,{children:["So make ",(0,s.jsx)(e.code,{children:"dataLoaders.order.load(id)"})," the only way to read a record. Every keyed lookup is then batched and accounted for by construction, an accidental N+1 takes real effort to write, and the context shrinks back to two honest fields:"]}),`
478`,(0,s.jsx)(s.Fragment,{children:(0,s.jsxs)(e.pre,{className:"shiki shiki-themes g
478ithub-light github-dark",style:{backgroundColor:"#fff","--shiki-dark-bg":"#24292e",color:"#24292e","--shiki-dark":"#e1e4e8"},tabIndex:"0","data-language":"typescript",children:[(0,s.jsxs)(e.div,{className:"code-block-header",children:[(0,s.jsx)(e.span,{className:"font-mono text-xs text-gray-600",children:"typescript"}),(0,s.jsx)(e.button,{className:"copy-code-btn ml-2",title:"Copy code","data-code":`export interface RequestContext {
479  currentUser?: User;
480  dataLoaders: DataLoaders;
481}`})]}),(0,s.jsxs)(e.code,{children:[(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"export"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:" interface"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" RequestContext"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:" {"})]}),`
482`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"  currentUser"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:"?:"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" User"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
483`,(0,s.jsxs)(e.span,{className:"line",children:[(0,s.jsx)(e.span,{style:{color:"#E36209","--shiki-dark":"#FFAB70"},children:"  dataLoaders"}),(0,s.jsx)(e.span,{style:{color:"#D73A49","--shiki-dark":"#F97583"},children:":"}),(0,s.jsx)(e.span,{style:{color:"#6F42C1","--shiki-dark":"#B392F0"},children:" DataLoaders"}),(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:";"})]}),`
484`,(0,s.jsx)(e.span,{className:"line",children:(0,s.jsx)(e.span,{style:{color:"#24292E","--shiki-dark":"#E1E4E8"},children:"}"})})]})]})}),`
485`,(0,s.jsxs)(e.p,{children:["with ",(0,s.jsx)(e.code,{children:"prisma"})," demoted to an implementation detail that only the loaders module is allowed to import."]}),`
486`,(0,s.jsx)(e.p,{children:"This isn't free, but the cost is bounded and worth paying:"}),`
487`,(0,s.jsxs)(e.ul,{children:[`
488`,(0,s.jsxs)(e.li,{children:[(0,s.jsx)(e.strong,{children:"Writes still need the client."})," A loader batches reads; it can't ",(0,s.jsx)(e.code,{children:"create"})," or ",(0,s.jsx)(e.code,{children:"update"}),". So ",(0,s.jsx)(e.code,{children:"prisma"})," doesn't disappear so much as move behind a small set of mutation helpers, each of which ",(0,s.jsx)(e.code,{children:"prime"}),"s or ",(0,s.jsx)(e.code,{children:"clear"}),"s the relevant loader afterward so a later read in the same request never serves the pre-write cache."]}),`
489`,(0,s.jsxs)(e.li,{children:[(0,s.jsx)(e.strong,{children:"Filtered and paginated queries don't reduce to a single key."})," A top-level ",(0,s.jsx)(e.code,{children:"orders(filter, page)"})," query isn't a ",(0,s.jsx)(e.code,{children:".load(id)"}),"; it's an arbitrary ",(0,s.jsx)(e.code,{children:"findMany"}),". Those live on the same explicit helpers as the writes, while every by-key entity fetch, which is where N+1 actually bites, goes through a loader."]}),`
490`,(0,s.jsxs)(e.li,{children:[(0,s.jsx)(e.strong,{children:"More loaders to write."})," Each access pattern becomes its own loader. That's more boilerplate, but it's boilerplate that names every access pattern in one place and drags it into code review, which is most of the point."]}),`
491`]}),`
492`,(0,s.jsxs)(e.p,{children:["The principle underneath all three is simple: the fewer raw ",(0,s.jsx)(e.code,{children:"prisma"})," calls a resolver can make, the harder it is to bring back the N+1 problem the context was built to solve. Push it to the end and a resolver can't touch the database in an unbatched way even if it tries, and that's exactly the guarantee I want the context to make."]})]})}function o(r={}){const{wrapper:e}=r.components||{};return e?(0,s.jsx)(e,{...r,children:(0,s.jsx)(i,{...r})}):i(r)}export{o as default,a as frontmatter};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.