Next.js Discord

Discord Forum

tRPC error in a server component

Answered
Cimarrón Uruguayo posted this in #help-forum
Open in Discord
Cimarrón UruguayoOP
const ThankYouPage: React.FC<PageProps> = async ({ searchParams }) => {
  const orderId = parseInt(searchParams["orderId"] as string)

  const { user } = await getServerSideUser(cookies())
  declare const orders: Order[]

  const [order] = orders
  if (!order) return notFound()

  const customerId = typeof order.user === "number" ? order.user : order.user.id
  if (customerId !== user?.id) {
    return redirect(`/sign-in?origin=thank-you`)
  }

  try {
    const { data, isError, isLoading } = trpc.assets.getAssetsZip.useQuery({ orderId })
    console.log(data)
  } catch (error) {
    console.log(error)
  }

  return <Component />
}

117 Replies

Cimarrón UruguayoOP
@Ray you can't use react-query in a server component
Cimarrón UruguayoOP
urgh so how can i get around this?
If i convert into a client component,
then I can't get the cookies from next/headers
that's only possible in server components
check out create-t3-app
it create server caller for you
@Ray check out create-t3-app
Cimarrón UruguayoOP
what exactly should I look at?
?
is this what I'm looking for?
init an app with it or check out this
https://trpc.io/docs/server/server-side-calls
Cimarrón UruguayoOP
ok thanks!
@Ray yes
Cimarrón UruguayoOP
im having trouble with this
@Ray init an app with it or check out this https://trpc.io/docs/server/server-side-calls
Cimarrón UruguayoOP
the docs ask me to create a caller, but this is how i've created my trpc related files:
// index.ts
import { assetsRouter } from "./assets-router";
import { authRouter } from "./auth-router";
import { paymentRouter } from "./payment-router";
import { productRouter } from "./products-router";
import { router } from "./server";

export const appRouter = router({
  auth: authRouter,
  products: productRouter,
  payment: paymentRouter,
  assets: assetsRouter
})

export type AppRouter = typeof appRouter


// server.ts
import { ExpressContext } from "@/server";
import { TRPCError, initTRPC } from "@trpc/server";

import type { PayloadRequest } from "payload/types";
import type { User } from "@/payload-types";

export const t = initTRPC.context<ExpressContext>().create()

export const router = t.router
export const publicProcedure = t.procedure

const isAuth = t.middleware(async ({ ctx, next }) => {
  //
})
export const privateProcedure = t.procedure.use(isAuth)


// client.ts
import { createTRPCReact } from "@trpc/react-query"
import type { AppRouter } from "."

export const trpc = createTRPCReact<AppRouter>()
I would create a caller in my server.ts file right?
@Cimarrón Uruguayo I would create a caller in my server.ts file right?
yes you could create it wherever you like
@Ray yes you could create it wherever you like
Cimarrón UruguayoOP
yep so this is the issue I get
I don't have access to the request and response (express) objects when I want to create the caller
is there a way to receive this "context" in my server component?
bruh 💀
Answer
you should use t.createCallerFactory(appRouter).createCaller() I think
Cimarrón UruguayoOP
yeah I saw that
createCallerFactory is not a valid method
have you create a project with create-t3-app?
Cimarrón UruguayoOP
it should have what you need
Cimarrón UruguayoOP
i don't want to use create-t3-app though
i have created a sample t3-app elsewhere and the createCallerFactory method does show up now
@Cimarrón Uruguayo i don't want to use create-t3-app though
I mean check their template how they create the caller
Cimarrón UruguayoOP
ah yeah
ill learn this another time
tRPC wasn't my focus
I appreciate your help though, I'll keep this noted for the future
Basset Artésien Normand
Hi @Cimarrón Uruguayo I guess you were not using the NextJS server? Did you have a separate backend / server? and did you get it working now ?
Also @Ray Will the suggestions above work when using a separate backend / server ? ( but still within a monorepo )
@Basset Artésien Normand Hi <@473221703418511360> I guess you were not using the NextJS server? Did you have a separate backend / server? and did you get it working now ?
Cimarrón UruguayoOP
I am using a nextjs server, just that it was created manually withing express
as for getting it working, it started working out of nowhere
Basset Artésien Normand
So you are using a custom server within nextJS ?
Cimarrón UruguayoOP
it is still nextjs
just that I construct the nextjs server manually
Basset Artésien Normand
Hm, seems the server side calls are for when you need to call the procedures from the same server they are hosted in.
You may need to call your procedure(s) directly from the same server they're hosted in, createCallerFactory() can be used to achieve this. This is useful for server-side calls and for integration testing of your tRPC procedures. That is at least in regards to the server side calls documentation
Cimarrón UruguayoOP
in a server.ts file, instead of running like next dev
Basset Artésien Normand
But in my case i have a monorepo, but the client and server will be deployed separately
Cimarrón UruguayoOP
how is that possible
nextjs sort of blurs the separation between client and server
Basset Artésien Normand
exactly and i am really struggling to find a good example for what i want to do
mostly because of nextJS v14 and app router
Basset Artésien Normand
I still can't understand how this works. @Ray Are you available to help at all
Basset Artésien Normand
My Setup:
Monorepo
Apps:
api - fastify server with tRPC
web - NextJS v14.0.4 - App Router

These 2 apps will be deployed separately. The Server-side calls you mentioned seem to be aimed at when the application is deployed as a single unit.
I've also looked at: https://trpc.io/docs/v11/client/nextjs/server-side-helpers but the documentations seem to be aimed at the file system router.

I want to be able to make tRPC calls both on the client AND when server side rendering the page.
@Ray check out create-t3-app
have you check out this?
Basset Artésien Normand
yes ive looked at that a lot. and its something that utilises the NextJS server and when the application will be deployed as a single unit.
I would create a trpc package and import it from api and web
Basset Artésien Normand
I don't understand
I'll still need to interface with the tRPC server using HTTP requests
Basset Artésien Normand
i mean. communicate
for api?
are you using turbo repo?
Basset Artésien Normand
Ill need to be able to communicate between trpc client and trpc server using http requests, as trpc will be hosted in a separate location
@Ray are you using turbo repo?
Basset Artésien Normand
no, pnpm workspaces
create a new package and export the trpc router
then you can install it on api and web
Basset Artésien Normand
i can access the appRouter from web
you cant access the appRouter from api?
Basset Artésien Normand
the appRouter is within the apiapp
so you have access to appRouter in api and web?
well, you should create another package for it
Monorepo
Apps:
api - fastify server with tRPC
web - NextJS v14.0.4 - App Router
trpc
Basset Artésien Normand
Ok but how should i setup tRPC within web
you install the trpc package in web and api
Basset Artésien Normand
and then ?
createTRPCReact, or createTRPCNext ?
@Ray you install the trpc package in web and api
Basset Artésien Normand
Do you have an example to hand?
Basset Artésien Normand
thats great thanks
Is it necessary to have tRPC in its own package?
@Basset Artésien Normand Is it necessary to have tRPC in its own package?
yes so you can install it from other app
Basset Artésien Normand
looking in here: apps/nextjs/src/app/api/trpc/edge/[trpc]/route.ts from that repo - It doesn't look like the api endpoint exists elsewhere as its only passing the path
Basset Artésien Normand
hm wait there is also apps/nextjs/src/trpc/server.ts
that's the caller for server component
Basset Artésien Normand
man its a little confusing
i appreciate your help by the way
I think you should init a project with create-t3-app and play with it first
Basset Artésien Normand
yeah ive had a look at that a lot
its just it does not really apply. as its meant to be deployed as a single unit
i see your point though
@Basset Artésien Normand yeah ive had a look at that a lot
have you ever used trpc?
@Ray have you ever used trpc?
Basset Artésien Normand
no this is my first time
but the create-t3-app does it all for you. I wanted to set it all up from scratch myself to learn
why would one use route handlers?
@Basset Artésien Normand no this is my first time
if you are doing server side fetching on nextjs, you don't need to create the route.ts which is for client side fetching
@Basset Artésien Normand why would one use route handlers?
because most of work can be done with server action
Basset Artésien Normand
great thanks
does it work to simply replace endpoint: '/api/trpc', with endpoint: 'https://<server_location>/api/trpc' if its the separate server like in my case
Basset Artésien Normand
i am going to have a search function which will fetch results from a remote 3rd party api
unless its possible to do the fetch and render server side?
Basset Artésien Normand
oh right. will that not appear slow?
How does that work exactly
Basset Artésien Normand
Hi @Ray Thanks for the great help yesterday.
Any advice regarding forwarding the headers when SSR ?
i can see in my client side request that the headers / cookies are sent. But when logging req.cookies in the createContext function its empty. I am thinking it could be something to do with Cors, which i am sure I already fixedits currently set in fastify like this:

  server.register(cors, {
    origin: '*',
    methods: '*',
    credentials: true,
  })


Furthermore

my server.ts for trpc looks like this:

'use server'

import { cookies } from 'next/headers'
import { loggerLink, httpBatchLink } from '@trpc/client'
import { experimental_createTRPCNextAppDirServer } from '@trpc/next/app-dir/server'

import superjson from 'superjson'
import type { AppRouter } from '@api/server/router'

//console.log(cookies().toString())

export const api = experimental_createTRPCNextAppDirServer<AppRouter>({
  config() {
    return {
      transformer: superjson,
      links: [
        loggerLink({
          enabled: (opts) =>
            process.env.NODE_ENV === 'development' ||
            (opts.direction === 'down' && opts.result instanceof Error),
        }),
        httpBatchLink({
          url: 'http://localhost:4000/trpc',
          headers: {
            cookies: cookies().toString(),
          },
          fetch(url, options) {
            return fetch(url, {
              ...options,
              credentials: 'include',
            })
          },
        }),
      ],
    }
  },
})
httpBatchLink({
  url: 'http://localhost:4000/trpc',
  headers: Object.fromEntries(headers()),
  fetch(url, options) {
    return fetch(url, {
      ...options,
      credentials: 'include',
    })
  },
}),
Basset Artésien Normand
damnit
thanks so much 👍
that worked. but it was weird because when logging req.headers in the createContextit showed the cookie.