3.2 KiB
3.2 KiB
Complete API Implementation Examples
Example 1: API Endpoint with Cursor Pagination
import { prisma } from './prisma-client';
type GetPostsParams = {
cursor?: string;
limit?: number;
};
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const cursor = searchParams.get('cursor') || undefined;
const limit = Number(searchParams.get('limit')) || 20;
if (limit > 100) {
return Response.json(
{ error: 'Limit cannot exceed 100' },
{ status: 400 }
);
}
const posts = await prisma.post.findMany({
take: limit,
skip: cursor ? 1 : 0,
cursor: cursor ? { id: cursor } : undefined,
orderBy: { createdAt: 'desc' },
include: {
author: {
select: { id: true, name: true, email: true },
},
},
});
const nextCursor = posts.length === limit
? posts[posts.length - 1].id
: null;
return Response.json({
data: posts,
nextCursor,
hasMore: nextCursor !== null,
});
}
Client usage:
async function loadMorePosts() {
const response = await fetch(`/api/posts?cursor=${nextCursor}&limit=20`);
const { data, nextCursor: newCursor, hasMore } = await response.json();
setPosts(prev => [...prev, ...data]);
setNextCursor(newCursor);
setHasMore(hasMore);
}
Example 2: Filtered Cursor Pagination
type GetFilteredPostsParams = {
cursor?: string;
authorId?: string;
tag?: string;
limit?: number;
};
async function getFilteredPosts({
cursor,
authorId,
tag,
limit = 20,
}: GetFilteredPostsParams) {
const where = {
...(authorId && { authorId }),
...(tag && { tags: { some: { name: tag } } }),
};
const posts = await prisma.post.findMany({
where,
take: limit,
skip: cursor ? 1 : 0,
cursor: cursor ? { id: cursor } : undefined,
orderBy: { createdAt: 'desc' },
});
return {
data: posts,
nextCursor: posts.length === limit ? posts[posts.length - 1].id : null,
};
}
Index requirement:
model Post {
id String @id @default(cuid())
authorId String
createdAt DateTime @default(now())
@@index([authorId, createdAt, id])
}
Example 3: Small Admin Table with Offset
type GetAdminUsersParams = {
page?: number;
pageSize?: number;
search?: string;
};
async function getAdminUsers({
page = 1,
pageSize = 50,
search,
}: GetAdminUsersParams) {
const skip = (page - 1) * pageSize;
const where = search
? {
OR: [
{ email: { contains: search, mode: 'insensitive' as const } },
{ name: { contains: search, mode: 'insensitive' as const } },
],
}
: {};
const [users, total] = await Promise.all([
prisma.user.findMany({
where,
skip,
take: pageSize,
orderBy: { createdAt: 'desc' },
select: {
id: true,
email: true,
name: true,
role: true,
createdAt: true,
},
}),
prisma.user.count({ where }),
]);
return {
data: users,
pagination: {
page,
pageSize,
totalPages: Math.ceil(total / pageSize),
totalRecords: total,
hasNext: page < Math.ceil(total / pageSize),
hasPrev: page > 1,
},
};
}