Courier's proxy runs behind one route of your app. An official adapter mounts it in your framework: install its package and add that route. The handler takes no arguments, because it reads the sources the app registered, so moving to another framework changes only the import and the one call.
Full-stack frameworks
The proxy lives in an API route of the app itself.
| Framework | Package | Route | Guide |
|---|---|---|---|
| Next.js | @noverax/courier-next | app/api/request/route.ts | Next.js |
| Nuxt | @noverax/courier-nuxt | server/api/request.ts | Nuxt |
| SvelteKit | @noverax/courier-sveltekit | src/routes/api/request/+server.ts | SvelteKit |
| Astro | @noverax/courier-astro | src/pages/api/request.ts | Astro |
| Remix & React Router | @noverax/courier-remix | app/routes/api.request.ts | Remix & React Router |
| SolidStart | @noverax/courier-solid | src/routes/api/request.ts | SolidStart |
Server frameworks
The proxy is one route of your server.
| Framework | Package | Mounted with | Guide |
|---|---|---|---|
| Express | @noverax/courier-express | app.all("/api/request", courierHandler()) | Express |
| Hono | @noverax/courier-hono | app.all("/api/request", courierHandler()) | Hono |
| Fastify | @noverax/courier-fastify | app.register(courierPlugin, { prefix: "/api/request" }) | Fastify |
| NestJS | @noverax/courier-nestjs | consumer.apply(courierMiddleware()).forRoutes("api/request") | NestJS |
The user's session in server code
An API that keeps a session gets the user's session with every call server code makes for a request, once the framework serves the request with it at hand. Each adapter does that in one line; the versions listed are the ones checked in a real application on every change.
| Framework | Serve each request with the session | Checked |
|---|---|---|
| Next.js | createServerCaller(api) | 14, 15, 16 |
| Nuxt | export default defineNitroPlugin(requestContextPlugin) | 3, 4 |
| SvelteKit | registerRequestContext(svelteKitRequestContext(getRequestEvent)), or requestContextHandle() | 2.19, 2 |
| Astro | export const onRequest = requestContext() | 5 |
| React Router | export const middleware = [requestContext()] | 7, 8 |
| Remix | app.use(requestContext()) from @noverax/courier-express, before Remix's handler | 2 |
| SolidStart | registerRequestContext(solidStartRequestContext(getRequestEvent)) | 1, 2 |
| Express | app.use(requestContext()) | 4, 5 |
| Fastify | app.addHook("onRequest", requestContext()) | 4, 5 |
| Hono | app.use(requestContext()) | 4 |
| NestJS | app.use(requestContext()), on the Express or the Fastify platform | 10, 11, 12 |
Where each goes, and what each framework does differently, is in User Sessions.
The client side
The adapters serve the proxy. The typed caller the browser calls it with has guides of its own: React, with React Query, and Vue. A mobile app calls its API directly: see React Native & Expo.
Another framework
A framework that hands its route a Web-standard Request and takes a Response back can mount Courier's own handler without an adapter: see Server Handler.