[Strapi] Custom API 생성

이춘구·2022년 6월 13일
1

http://localhost:1337/api/products/90?populate=*
현재 위의 URL로 id가 90인 product에 대한 data를 API를 통해 요청하면 아래와 같이 모든 field의 데이터를 response으로 받는다.

"data": {
    "id": 90,
    "attributes": {
        "productName": "아라비카",
        "price": 45000,
        "discountRate": 5,
        "description": "아라비카 원두입니다.",
        "createdAt": "2022-06-09T18:57:04.216Z",
        "updatedAt": "2022-06-09T19:08:37.176Z",
        "publishedAt": "2022-06-09T19:08:09.580Z",
        "images": {...},
        "reviews": {...},
        "inquiries": {...}
    }

하지만 프로젝트에서 특정 productreviews만 불러오는 API가 필요해서 아래와 같은 response를 반환하는 API를 만들려고 한다.

{
    "id": 90,
    "reviews": [...]
}

API 생성

API를 생성하기 위해 필요한 routes, services, controller 폴더와 파일들을 직접 만들 수도 있지만 편하게 CLI를 사용하겠다.

yarn strapi generate

위 명령어를 입력하고,

  1. 첫번째 선택지에서 api - Generate a basic API 선택
  2. product에서 reviews만을 반환하는 api이므로 api의 이름을 product-reviews로 정함
  3. plugin을 위한 API가 아니므로 n 입력 후 엔터

과정이 완료되면 src/api 하위 경로에 product-reviews라는 이름의 폴더가 생성된다.


Routes

URL을 통해 Strapi로 전송된 요청은 route에 의해 처리된다. Strapi는 기본적으로 모든 content-type에 대한 route를 생성하며, route는 추가되거나 수정될 수 있다. 요청이 route에 도달하면 handlercontroller의 코드가 실행된다.

/src/api/product-reviews/routes/product-reviews.js의 코드를 아래와 같이 작성한다.

module.exports = {
  routes: [
    {
      method: "GET",
      path: "/product-reviews/:id",
      handler: "product-reviews.productReviews",
      config: {
        policies: [],
        middlewares: [],
      },
    },
  ],
};

Services

service는 재사용 가능한 함수들의 집합이다. controller의 로직을 단순화하는 데 유용하다. serviceKoactx(request와 response에 대한 모든 정보가 들어있는 객체)에 접근할 수 없다.

src/api/product-reviews/services/product-reviews.js의 코드를 아래와 같이 작성한다.

module.exports = {
  productReviews: async (productId) => {
    try {
      // strapi가 제공하는 entityService의 findOne 메소드로 productId에 해당하는 product를 찾는다.
      const entries = await strapi.entityService.findOne(
        "api::product.product",
        productId,
        // fields에 값으로 넣으면 어떠한 field도 response에 담기지 않는다.
        // populate: "reviews"로 reviews만 response에 담기도록 한다.
        { fields: [], populate: "reviews" }
      );
      return entries;
    } catch (err) {
      return err;
    }
  },
};

Controllers

controller는 Strapi가 action이라고 이름붙인 메소드가 모여있는 자바스크립트 파일이다.
route를 통해 클라이언트의 요청이 들어오면 action이 비즈니스 로직을 실행하고 response를 반환한다.
또한, controllerservice와 달리 Koactx 객체에 접근 가능하다.
controller의 비즈니스 로직이 너무 커지면 재사용 가능한 코드를 service로 분리하는 것이 효율적이다.

src/api/product-reviews/controllers/product-reviews.js를 아래와 같이 작성한다.

module.exports = {
  async productReviews(ctx) {
    // ctx 객체에서 url로 들어온 id를 뽑아 productId에 할당한다.
    const productId = ctx.params.id;
    try {
      const data = await strapi
        .service("api::product-reviews.product-reviews")
      	// services에서 만들어놓은 productReviews에 productId를 넘겨준다.
        .productReviews(productId);
      // service의 결과값인 data를 ctx 객체의 body에 할당한다.
      ctx.body = data;
    } catch (error) {
      ctx.badRequest("product-reviews 컨트롤러에서 에러 발생", {
        moreDetails: error,
      });
    }
  },
};

권한 설정

controller 파일 작성까지 마친 뒤, http://localhost:1337/api/product-reviews/90로 API 요청을 보내면 아래와 같은 403 에러를 반환한다.

이는 product-reviews라는 content-type에 대한 권한이 없어서 발생하는 에러이므로, admin panel로 가서 각 roleproduct-reviews에 대한 권한을 허용해준다.

그리고 동일한 URL로 다시 API 요청을 보내면 의도했던 형식의 response를 받을 수 있다.

profile
프런트엔드 개발자

0개의 댓글