쿠팡이츠 GraphQL로 페이지네이션 구현하기

shooting star·2024년 5월 10일
0
post-thumbnail

들어가며

이전 편에서 카테고리 분류 기능을 살펴보았습니다. 이번 글에서는 카테고리의 페이지를 나누는 방법에 대해 알아보겠습니다. 대량의 데이터를 다룰 때 필요한 페이지네이션을 구현함으로써 사용자에게 더 나은 경험을 제공할 수 있습니다.

페이지네이션 기본 개념

Nest.js에서 페이지네이션을 구현하기 위해서는 다음의 두 가지 요소를 정의해야 합니다.

  1. PaginationInput: 요청 시 페이지 정보를 전달하는 입력 DTO
  2. PaginationOutput: 응답 시 총 페이지 수 등의 정보를 포함하는 출력 DTO

1. PaginationInput과 PaginationOutput 정의

PaginationInputPaginationOutput을 다음과 같이 정의합니다.

// pagination.dto.ts
import { InputType, Field, Int, ObjectType } from '@nestjs/graphql';
import { CoreOutput } from './output.dto';

@InputType()
export class PaginationInput {
  @Field(type => Int, { defaultValue: 1 })
  page: number;
}

@ObjectType()
export class PaginationOutput extends CoreOutput {
  @Field(type => Int, { nullable: true })
  totalPages?: number;
}
  • PaginationInput: 페이지 번호(page)를 전달하는 입력 구조
  • PaginationOutput: 총 페이지 수(totalPages)를 응답에 포함하는 구조

2. 카테고리 페이지네이션 로직 구현

카테고리 분류와 페이지네이션을 동시에 처리하기 위해 findCategoryBySlug 메서드를 개선합니다.

// categories.service.ts (일부 코드)
async findCategoryBySlug({
  slug,
  page,
}: CategoryInput): Promise<CategoryOutput> {
  try {
    const category = await this.categories.findOne({ slug });
    if (!category) {
      return {
        ok: false,
        error: 'Category not found',
      };
    }
    const restaurants = await this.restaurants.find({
      where: {
        category,
      },
      take: 25, // 한 페이지에 표시할 레코드 수
      skip: (page - 1) * 25, // 건너뛸 레코드 수
    });
    category.restaurants = restaurants;
    const totalResults = await this.countRestaurants(category);
    return {
      ok: true,
      category,
      totalPages: Math.ceil(totalResults / 25),
    };
  } catch {
    return {
      ok: false,
      error: 'Could not load category',
    };
  }
}
  • findCategoryBySlug:
    • slug로 카테고리를 검색하고
    • take로 한 페이지에 표시할 레코드 수를 제한하며
    • skip으로 페이지 번호에 따라 건너뛸 레코드 수를 계산합니다.
    • 최종적으로 totalPages를 계산해 응답에 포함합니다.

3. 카테고리 페이지네이션 입력/출력 DTO 정의

카테고리별로 페이지네이션을 적용하려면 PaginationInputPaginationOutput을 확장해야 합니다.

// category.dto.ts
import { ArgsType, Field, ObjectType } from '@nestjs/graphql';
import { PaginationInput, PaginationOutput } from './pagination.dto';
import { Category } from '../entities/category.entity';

@ArgsType()
export class CategoryInput extends PaginationInput {
  @Field(type => String)
  slug: string;
}

@ObjectType()
export class CategoryOutput extends PaginationOutput {
  @Field(type => Category, { nullable: true })
  category?: Category;
}
  • CategoryInput: PaginationInput을 확장하여 slug 필드를 추가합니다.
  • CategoryOutput: PaginationOutput을 확장하여 category 필드를 추가합니다.

4. 카테고리 리졸버에 페이지네이션 추가

카테고리 리졸버에서 GraphQL 쿼리를 통해 페이지네이션 기능을 제공합니다.

// category.resolver.ts (일부 코드)
import { Resolver, Query, Args } from '@nestjs/graphql';
import { CategoryInput, CategoryOutput } from './dtos/category.dto';
import { CategoriesService } from './categories.service';

@Resolver()
export class CategoryResolver {
  constructor(private readonly categoriesService: CategoriesService) {}

  @Query(returns => CategoryOutput)
  async category(
    @Args('input') categoryInput: CategoryInput,
  ): Promise<CategoryOutput> {
    return this.categoriesService.findCategoryBySlug(categoryInput);
  }
}
  • category 쿼리:
    • CategoryInput을 받아 findCategoryBySlug 서비스를 호출하고
    • 해당 카테고리의 페이지네이션된 식당 목록과 함께 응답합니다.

마치며

이번 글에서는 GraphQL API에서 카테고리의 페이지네이션 기능을 구현하는 방법을 알아보았습니다. PaginationInputPaginationOutput을 통해 카테고리 분류와 페이지네이션을 함께 처리하며, 사용자에게 필요한 데이터를 페이지별로 제공할 수 있습니다.

0개의 댓글