Tamás Soós
Tamás Soós
Explore posts from servers
TtRPC
Created by Tamás Soós on 11/1/2023 in #❓-help
Next.js app directory
Hi. I have been able to set up tRPC with the app directory in Next.js. It was a frustrating experience at first. You can find a simple setup here. I'm not sure if this is still the best way to do so, or that it has ever been for that matter. Could someone confirm if this is the way to do it right now, or if I'm missing out on some features this way? I found this experimental project. The note says I could use the @trpc/next client too, but I'm not sure how. Maybe I just haven't found the right docs, but it seems like integrating with the app dir isn't officially documented, right? I'd be happy to contribute too.
2 replies
TtRPC
Created by Tamás Soós on 10/27/2023 in #❓-help
tRPC over WebSocket with Next.js and NextAuth
Hi. I'm trying to set up Next 13 with tRPC over a WebSocket and NextAuth. I got it mostly working with:
// route.ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createContext } from '@/server/context';
import { appRouter } from '@/server/routers/app';

const handler = (req: Request) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req,
router: appRouter,
createContext,
batching: {
enabled: true,
},
});

export { handler as GET, handler as POST };
// route.ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createContext } from '@/server/context';
import { appRouter } from '@/server/routers/app';

const handler = (req: Request) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req,
router: appRouter,
createContext,
batching: {
enabled: true,
},
});

export { handler as GET, handler as POST };
// context.ts
import * as trpc from '@trpc/server';
import * as trpcNext from '@trpc/server/adapters/fetch';
import { NodeHTTPCreateContextFnOptions } from '@trpc/server/adapters/node-http';
import { IncomingMessage } from 'node:http';
import ws from 'ws';
import { getSession } from 'next-auth/react';

export async function createContext(
opts:
| NodeHTTPCreateContextFnOptions<IncomingMessage, ws>
| trpcNext.FetchCreateContextFnOptions
) {
const req = opts?.req;

const session = req && (await getSession({ req }));

return {
req,
session,
};
}

export type Context = trpc.inferAsyncReturnType<typeof createContext>;
// context.ts
import * as trpc from '@trpc/server';
import * as trpcNext from '@trpc/server/adapters/fetch';
import { NodeHTTPCreateContextFnOptions } from '@trpc/server/adapters/node-http';
import { IncomingMessage } from 'node:http';
import ws from 'ws';
import { getSession } from 'next-auth/react';

export async function createContext(
opts:
| NodeHTTPCreateContextFnOptions<IncomingMessage, ws>
| trpcNext.FetchCreateContextFnOptions
) {
const req = opts?.req;

const session = req && (await getSession({ req }));

return {
req,
session,
};
}

export type Context = trpc.inferAsyncReturnType<typeof createContext>;
9 replies
TTCTheo's Typesafe Cult
Created by Tamás Soós on 10/27/2023 in #questions
Next.js app router with tRPC context and NextAuth
Hi. I'm trying to set up Next 13 with tRPC over a WebSocket and NextAuth. I got it mostly working with:
// route.ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createContext } from '@/server/context';
import { appRouter } from '@/server/routers/app';

const handler = (req: Request) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req,
router: appRouter,
createContext,
batching: {
enabled: true,
},
});

export { handler as GET, handler as POST };
// route.ts
import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { createContext } from '@/server/context';
import { appRouter } from '@/server/routers/app';

const handler = (req: Request) =>
fetchRequestHandler({
endpoint: '/api/trpc',
req,
router: appRouter,
createContext,
batching: {
enabled: true,
},
});

export { handler as GET, handler as POST };
// context.ts
import * as trpc from '@trpc/server';
import * as trpcNext from '@trpc/server/adapters/fetch';
import { NodeHTTPCreateContextFnOptions } from '@trpc/server/adapters/node-http';
import { IncomingMessage } from 'node:http';
import ws from 'ws';
import { getSession } from 'next-auth/react';

export async function createContext(
opts:
| NodeHTTPCreateContextFnOptions<IncomingMessage, ws>
| trpcNext.FetchCreateContextFnOptions
) {
const req = opts?.req;

const session = req && (await getSession({ req }));

return {
req,
session,
};
}

export type Context = trpc.inferAsyncReturnType<typeof createContext>;
// context.ts
import * as trpc from '@trpc/server';
import * as trpcNext from '@trpc/server/adapters/fetch';
import { NodeHTTPCreateContextFnOptions } from '@trpc/server/adapters/node-http';
import { IncomingMessage } from 'node:http';
import ws from 'ws';
import { getSession } from 'next-auth/react';

export async function createContext(
opts:
| NodeHTTPCreateContextFnOptions<IncomingMessage, ws>
| trpcNext.FetchCreateContextFnOptions
) {
const req = opts?.req;

const session = req && (await getSession({ req }));

return {
req,
session,
};
}

export type Context = trpc.inferAsyncReturnType<typeof createContext>;
6 replies
TTCTheo's Typesafe Cult
Created by Tamás Soós on 10/27/2023 in #questions
Next.js state management and dynamic routes
Hi. I'm working on a web app using Next.js. It's main purpose is to let me easily create and edit some entities related to a task. The entities live in a hierarchy. The actual entities don't matter, I'll use an IoT related example. Let's say we have Device -> Firmware version -> Available parameters as the hierarchy. Let's say the directory structure according to the hierarchy is as follows:
...
- layout.tsx
- navBar.tsx
- deviceList.tsx
- page.tsx
- device
- [deviceId]
- layout.tsx
- firmwareVersionList.tsx
- page.tsx
- firmware
- [firmwareId]
- layout.tsx
- parameterList.tsx
- page.tsx
...
...
...
...
- layout.tsx
- navBar.tsx
- deviceList.tsx
- page.tsx
- device
- [deviceId]
- layout.tsx
- firmwareVersionList.tsx
- page.tsx
- firmware
- [firmwareId]
- layout.tsx
- parameterList.tsx
- page.tsx
...
...
...
The index page would show the list of devices, while the layout provides the nav bar for the entire app. The page inside the [deviceId] folder shows the list of firmwares available for the selected device. The nav bar has search components to allow the user to quickly switch to any device / firmware / parameter. It looks something like the first screenshot. The search components become enabled as the relevant sub route is visited, so the search devices component is always enabled, the search firmware version component is enabled inside /device/[deviceId]/**, etc... Additionally the selected entity is shown on the search component (2nd screenshot). The appropriate entity is fetched in the corresponding layout that lives in the right sub route, for example the selected device is collected here:
...
- layout.tsx
- navBar.tsx
- deviceList.tsx
- page.tsx
- device
- [deviceId]
- layout.tsx <- Get device from db
- firmwareVersionList.tsx
- page.tsx
...
...
...
- layout.tsx
- navBar.tsx
- deviceList.tsx
- page.tsx
- device
- [deviceId]
- layout.tsx <- Get device from db
- firmwareVersionList.tsx
- page.tsx
...
...
Then currently the collected device object is shared with components in the sub routes after that via a context. My issue is with figuring out how to provide the selected device to the search device component in the nav bar.
6 replies