I'm using Prisma (4.2.1) in a Next.js API Route for cursor-based pagination of posts.
When I pass the cursor to the API endpoint, I get the following error message (500) in the console:
TypeError: Cannot read properties of undefined (reading 'createdAt')
at getPost (webpack-internal:///(api)/./lib/api/post.ts:67:46)
error - TypeError [ERR_INVALID_ARG_TYPE]: The "string" argument must be of type string or an instance of Buffer or ArrayBuffer. Received an instance of TypeError
I'm using Postman to access the API endpoint.
When I remove the cursor from the API Route, there are no errors and the posts are returned as expected.
I've tried upgrading to the latest Prisma version (4.2.1), using .toString() on the cursor, and changing the AllPosts interface to 'any' but I've been unable to solve the TypeError.
How can I fix this error and get Prisma to accept the cursor as valid?
import prisma from "@/lib/prisma";
import type { NextApiRequest, NextApiResponse } from "next";
import type { Post, Site } from ".prisma/client";
import type { Session } from "next-auth";
import { revalidate } from "@/lib/revalidate";
import type { WithSitePost } from "@/types";
interface AllPosts {
posts: Array<Post>;
site: Site | null;
}
export async function getPost(
req: NextApiRequest,
res: NextApiResponse,
session: Session
): Promise<void | NextApiResponse<AllPosts | (WithSitePost | null)>> {
const { postId, siteId, published, cursor } = req.query;
if (
Array.isArray(postId) ||
Array.isArray(siteId) ||
Array.isArray(published) ||
Array.isArray(cursor)
)
return res.status(400).end("Bad request. Query parameters are not valid.");
if (!session.user.id)
return res.status(500).end("Server failed to get session user ID");
try {
if (postId) {
const post = await prisma.post.findFirst({
where: {
id: postId,
site: {
user: {
id: session.user.id,
},
},
},
include: {
site: true,
},
});
return res.status(200).json(post);
}
const site = await prisma.site.findFirst({
where: {
id: siteId,
user: {
id: session.user.id,
},
},
});
const posts = !site
? []
: await prisma.post.findMany({
take: 10,
skip: cursor === undefined ? 0 : 1,
cursor: {
id: cursor,
},
where: {
site: {
id: siteId,
},
published: JSON.parse(published || "true"),
},
orderBy: {
createdAt: "desc",
},
});
const lastPostInResults = posts[9];
const nextCursor = lastPostInResults.createdAt;
return res.status(200).json({
posts,
site,
nextCursor,
});
} catch (error) {
console.error(error);
return res.status(500).end(error);
}
}
model Post {
id String @id @default(cuid())
title String? @db.Text
content String? @db.LongText
slug String @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
published Boolean @default(false)
site Site? @relation(fields: [siteId], references: [id], onDelete: Cascade)
siteId String?
@@unique([id, siteId], name: "post_site_constraint")
}
model Site {
id String @id @default(cuid())
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User? @relation(fields: [userId], references: [id])
userId String?
posts Post[]
}
This was solved by adding @unique
to the Post model, pushing the schema changes and using prisma generate
.
model Post {
createdAt DateTime @default(now())
...
}