Swaroop
Swaroop6mo ago

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

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.
No description
No description
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
2 Replies
Swaroop
Swaroop6mo ago
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
Swaroop
Swaroop5mo ago
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.