Next.js Discord

Discord Forum

Typesafe App Router API Routes

Answered
Crested Myna posted this in #help-forum
Open in Discord
Crested MynaOP
A route.ts in the app router is expected to have one or more named functions that are named after the HTTP verb, such as GET. These functions have one param (Request) and return a Response. Is there a way to make Response typesafe to a given return type? This was possible with the pages router, but I can't see a way to do this with this app router, as the Response type is not a generic.
Answered by joulev
Response is not generic, so you can't do something like export function GET(): SomeType. But you can make a wrapper. Something like this

function generateRouteHandler<T>(callback: (request: NextRequest) => Promise<T>) {
  return async (request: NextRequest) => {
    const json = await callback(request);
    return NextResponse.json(json);
  };
}

the wrapper above is very minimal, extend it according to your own application logic
View full answer

6 Replies

Response typesafe to a given return type?
you can always enforce a type in your return function.

But you'd need to create your own typings
export function GET():AppResponse<something> {}
@Crested Myna A `route.ts` in the app router is expected to have one or more named functions that are named after the HTTP verb, such as `GET`. These functions have one param (`Request`) and return a `Response`. Is there a way to make `Response` typesafe to a given return type? This was possible with the pages router, but I can't see a way to do this with this app router, as the `Response` type is not a generic.
Response is not generic, so you can't do something like export function GET(): SomeType. But you can make a wrapper. Something like this

function generateRouteHandler<T>(callback: (request: NextRequest) => Promise<T>) {
  return async (request: NextRequest) => {
    const json = await callback(request);
    return NextResponse.json(json);
  };
}

the wrapper above is very minimal, extend it according to your own application logic
Answer
@Crested Myna thanks. do you know why they made this design choice? I kind of want to write my api routes using the page router and the front end components with the app router. it would even result in a cleaner codebase, imo.
The response can be any http responses, not just json. So it can be a binary file, it can be a stream, it can be empty, it can be literally anything. That’s why it’s impossible to make Response generic.

As for why they transitioned from nodejs res object to the native Response class, it’s because the nodejs res is only usable in nodejs, while the Response class is usable in all runtimes. Easier adaptability. I think this transition is inspired by remix - the more web native features (fetch, Request, Response) are used over nodejs ones (http, req, res) the better
though in the app router, you should prefer server components over GET routes and server actions over mutation (POST/PUT/etc.) routes. there are not many use cases where client-side data fetching is the clear favourite