T
tRPC

❓-help

How to pass headers from serverActions in Next.js App router.

SSwaroop2/8/2024
I'm using tRPC with Clerk auth provider in Next.js App directory. I created a serverClient to use tRPC on server-side but the context is complaining about not having request headers, it throws this even on building my application. Attached error and my file structure.
Solution:
Resolved it by moving clerk auth() to tRPC middleware with that server don't need to pass or the inner context doesn't need to have Clerk auth() as it doesn't depend on req or res objects.
Jump to solution
No description
No description
SSwaroop2/8/2024
Related code blocks: server/context.ts
import * as trpc from "@trpc/server";
import * as trpcFetch from "@trpc/server/adapters/fetch";
import { PrismaClient } from "@prisma/client";
import {
SignedInAuthObject,
SignedOutAuthObject,
auth,
getAuth,
} from "@clerk/nextjs/server";
import { NextApiRequest } from "next";
import { headers } from "next/headers";
import { NextRequest } from "next/server";
import { RequestCookies } from "next/dist/compiled/@edge-runtime/cookies";

interface ClerkAuthContext {
auth: SignedInAuthObject | SignedOutAuthObject;
}

/**
* Inner context. Will always be available in your procedures, in contrast to the outer context.
*
* Useful for:
* - testing, database-connection and server-side helpers, so you don't have to mock Next.js' `req`/`res`
*
* @link https://trpc.io/docs/v11/context#inner-and-outer-context
*/
export const createInnerContext = async ({ auth }: ClerkAuthContext) => {
const prisma = new PrismaClient();

return {
auth,
prisma,
};
};

export async function createContext(
opts?: trpcFetch.FetchCreateContextFnOptions
) {
// ? Reference for Clerk Auth in Next.js App Router: https://clerk.com/docs/references/nextjs/read-session-data
const clerkAuth = auth();
const innerContext = await createInnerContext({ auth: clerkAuth });

return { ...innerContext, ...opts };
}

export type Context = trpc.inferAsyncReturnType<typeof createContext>;
import * as trpc from "@trpc/server";
import * as trpcFetch from "@trpc/server/adapters/fetch";
import { PrismaClient } from "@prisma/client";
import {
SignedInAuthObject,
SignedOutAuthObject,
auth,
getAuth,
} from "@clerk/nextjs/server";
import { NextApiRequest } from "next";
import { headers } from "next/headers";
import { NextRequest } from "next/server";
import { RequestCookies } from "next/dist/compiled/@edge-runtime/cookies";

interface ClerkAuthContext {
auth: SignedInAuthObject | SignedOutAuthObject;
}

/**
* Inner context. Will always be available in your procedures, in contrast to the outer context.
*
* Useful for:
* - testing, database-connection and server-side helpers, so you don't have to mock Next.js' `req`/`res`
*
* @link https://trpc.io/docs/v11/context#inner-and-outer-context
*/
export const createInnerContext = async ({ auth }: ClerkAuthContext) => {
const prisma = new PrismaClient();

return {
auth,
prisma,
};
};

export async function createContext(
opts?: trpcFetch.FetchCreateContextFnOptions
) {
// ? Reference for Clerk Auth in Next.js App Router: https://clerk.com/docs/references/nextjs/read-session-data
const clerkAuth = auth();
const innerContext = await createInnerContext({ auth: clerkAuth });

return { ...innerContext, ...opts };
}

export type Context = trpc.inferAsyncReturnType<typeof createContext>;
app/_trpc/serverClient
import { createContext } from "../../server/context";
import { appRouter } from "../../server/router";
import { t } from "../../server/trpc";

const createCaller = t.createCallerFactory(appRouter);
export const serverClient = createCaller(await createContext());
import { createContext } from "../../server/context";
import { appRouter } from "../../server/router";
import { t } from "../../server/trpc";

const createCaller = t.createCallerFactory(appRouter);
export const serverClient = createCaller(await createContext());
serverClient is actually working post login but on building my application and on public pages I'm getting the error.
Solution
SSwaroop2/10/2024
Resolved it by moving clerk auth() to tRPC middleware with that server don't need to pass or the inner context doesn't need to have Clerk auth() as it doesn't depend on req or res objects.

Looking for more? Join the community!