JSTAcademy
0 XP
Dashboard
Crash Courses
Pagination & Filtering
10 min
Masters+175 XP
Crash Courses · Masters

Pagination & Filtering

Implement cursor-based pagination and advanced filtering for REST collections.
10 min read+175 XP on completionCert: REST APIs Crash Course
Tap any word in the text below to start reading from there.

Pagination & Filtering

APIs returning large collections need pagination. Cursor pagination is more robust than offset for real-time data.

Offset Pagination

// GET /api/courses?page=1&limit=20&track=crash&level=Basic

export async function GET(req: NextRequest) {
  const page = parseInt(req.nextUrl.searchParams.get('page') ?? '1')
  const limit = Math.min(parseInt(req.nextUrl.searchParams.get('limit') ?? '20'), 100)
  const track = req.nextUrl.searchParams.get('track')
  const level = req.nextUrl.searchParams.get('level')

  let courses = COURSES
  if (track) courses = courses.filter(c => c.track === track)
  if (level) courses = courses.filter(c => c.level === level)

  const total = courses.length
  const offset = (page - 1) * limit
  const paginated = courses.slice(offset, offset + limit)

  return NextResponse.json({
    data: paginated,
    meta: {
      page,
      limit,
      total,
      total_pages: Math.ceil(total / limit),
      has_more: offset + limit < total,
    },
  })
}

Cursor Pagination

// GET /api/progress?cursor=base64_encoded_id&limit=20

export async function GET(req: NextRequest) {
  const limit = 20
  const rawCursor = req.nextUrl.searchParams.get('cursor')
  const cursor = rawCursor ? Buffer.from(rawCursor, 'base64').toString() : null

  const query = supabase
    .from('progress')
    .select('*')
    .order('id')
    .limit(limit + 1)  // fetch one extra to check has_more

  if (cursor) query.gt('id', cursor)

  const { data } = await query
  const has_more = data!.length > limit
  const items = has_more ? data!.slice(0, limit) : data!
  const next_cursor = has_more
    ? Buffer.from(items[items.length - 1].id).toString('base64')
    : null

  return NextResponse.json({ data: items, next_cursor, has_more })
}

Sort and Filter Parameters

GET /api/courses?
  track=crash                 filter by track
  level=Basic                 filter by level
  sort=xp                     sort field
  order=desc                  sort direction
  search=javascript           full-text search
  min_xp=150&max_xp=200      range filter
0%