Next 13 API fetch return types
Unanswered
Common Pochard posted this in #help-forum
Common PochardOP
What is the appropriate way to cast my data to the correct return types of Next APIs?
Currently, I have:
This is close, but
This isn't iterable. How would I unwrap the
Currently, I have:
import { GET } from '@/app/api/todos/route';
async function MyPage() {
const data: Awaited<ReturnType<typeof GET>> = await fetch('http://localhost:3000/api/todos').then((r) => r.json());
return <> </>
}This is close, but
data ends up as:const data: NextResponse<{
id: number;
name: string;
}[]>This isn't iterable. How would I unwrap the
NextResponse part of it?11 Replies
@Common Pochard What is the appropriate way to cast my data to the correct return types of Next APIs?
Currently, I have:
ts
import { GET } from '@/app/api/todos/route';
async function MyPage() {
const data: Awaited<ReturnType<typeof GET>> = await fetch('http://localhost:3000/api/todos').then((r) => r.json());
return <> </>
}
This is close, but `data` ends up as:
ts
const data: NextResponse<{
id: number;
name: string;
}[]>
This isn't iterable. How would I unwrap the `NextResponse` part of it?
Kawakawa
I don't think you can as it's just a vanilla HTTPS/RESTful API route.
I would just just tRPC, to be honest. It provides e2e type-safety and has almost no overhead perf wise whatsoever.
Common PochardOP
I'm familiar with TRPC.
I'm just asking from a foundational perspective, there should be a really simple TS solution, I'm guessing.
For instance, I could wrap the internals of
Similar to this project that worked with the pages directory:
https://github.com/alii/nextkit-demo/blob/db7106a99e796b19aebbc2746dea38a16eaaad96/src/pages/index.tsx#L7
I'm just asking from a foundational perspective, there should be a really simple TS solution, I'm guessing.
For instance, I could wrap the internals of
GET in an exported function, call the function inside of GET and use that function for my type declaration, and it would work, just wondering if there's a way where I can do it with GET directly.Similar to this project that worked with the pages directory:
https://github.com/alii/nextkit-demo/blob/db7106a99e796b19aebbc2746dea38a16eaaad96/src/pages/index.tsx#L7
@Common Pochard I'm familiar with TRPC.
I'm just asking from a foundational perspective, there should be a really simple TS solution, I'm guessing.
For instance, I could wrap the internals of `GET` in an exported function, call the function inside of `GET` and use that function for my type declaration, and it would work, just wondering if there's a way where I can do it with `GET` directly.
Similar to this project that worked with the pages directory:
https://github.com/alii/nextkit-demo/blob/db7106a99e796b19aebbc2746dea38a16eaaad96/src/pages/index.tsx#L7
Kawakawa
Can you not do something hacky inferring-wise maybe with the type
NextAPIResponse?Idk just thinking out loud lol
Still would be nicer and easier to use tRPC tho 🙃
Common PochardOP
Yeah, I gotcha, I'm not denying trpc would be better, I'm not building a prod app, not really a 'whats the best way to do this?' question, just more a curious TS one
For instance, I could wrap the internals of GET in an exported function, call the function inside of GET and use that function for my type declaration, and it would work, just wondering if there's a way where I can do it with GET directly.yeah that would be ideal solution, you don't want to add an extra request to your own server if you can execute the logic directly in your RSC
as for the question itself, the easiest solution would be to export your own type from the route handler and use it to type the response, like this:
import { ResponseX } from '@/app/api/todos/route'
// This probably shouldn't be in this file
const get = async <T,>(url) => {
const res = await fetch(url)
const data = await res.json() as T
return data
}
async function Page() {
const data = await get<ResponseX>('...')
}if you want to infer the response from the return of the route handler methods, like
GET, then it is harder because the Response class doesn't contain the type information of the body of the response. so you would need to wrap these methods with your own function that contains the type infoCommon PochardOP
Found a way:
type NextApiRes<T extends (...args: any[]) => Promise<NextResponse<unknown>>> = Awaited<
ReturnType<T>
> extends NextResponse<infer U>
? U
: never;
declare const data: NextApiRes<typeof GET>;