[strapi] id 대신 커스텀 id로 데이터 받아오기

이춘구·2022년 5월 23일
0

strapi에서 collection type을 생성하고 entry를 추가하면,
1부터 시작해서 1씩 증가하는(incremental한) id를 기본으로 부여받는다.

이게 별로라 productId라는 이름의 UID field를 생성해줬다. 그리고 POST 요청으로 product를 추가할 때, nanoid를 사용해서 productId를 새로 넣어줬다.

const productId = `product-${nanoid()}`

그 결과 마음에 드는 아이디를 만들 수 있었다.

그럼 이제 http://localhost:1337/api/products/1처럼 id를 이용하지 않고
http://localhost:1337/api/products/product-16aFYp6Uqed11Ai0BcjmY처럼 productId를 이용한 경로로 product를 검색해서 데이터를 받아올 수 있게 하려면 어떻게 해야할까

route 덮어쓰기

먼저, route를 /products/:id에서 /products/:productId로 override 하기 위해 새로운 파일을 하나 만든다. route를 custom 하는 것이므로 파일명을 custom.js로 하겠다.

주의할 점
새로운 route를 만드는 게 아니라 기존 route에 덮어쓰는 거라면, 새로 만드는 파일명의 첫 글자가 collection-type의 첫 글자보다 알파벳 순(ASCII 순?)으로 뒤에 있으면 안 된다. 여기선 custom.js의 c가 product.js의 p보다 앞서므로 문제가 없었지만, /category/:id라는 route를 덮어쓰려고 /src/api/category/routes/custom.js 라는 파일을 만든다면 custom.js가 category.js 보다 순서 상 뒤에 위치하므로 덮어씌워지지 않는다. 그러니 파일명을 지을 땐 기존에 존재하는 파일보다 앞에 위치할 수 있도록 이름 짓는다. !(느낌표)를 맨 앞에 붙여도 되지만 파일명에 특수문자를 사용하기가 꺼려져서 숫자 0을 붙여 0custom.js로 했다. 좀 더 좋은 파일 명을 고민해봐야겠다.

파일 경로: src/api/product/routes/custom.js

module.exports = {
  routes: [
    {
      method: "GET",
      path: "/products/:productId",
      handler: "product.findOne",
      config: {
        auth: false,
      },
    },
  ],
};

controller 덮어쓰기

그 뒤, product의 controller를 수정해서, db에서 하나의 값을 찾아 반환해주는 메서드 findOne을 override 해준다.

파일 경로: src/api/product/controllers/product.js

수정 전
'use strict';

/**
 *  product controller
 */

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::product.product');
수정 후
"use strict";

/**
 *  product controller
 */

const { createCoreController } = require("@strapi/strapi").factories;

module.exports = createCoreController("api::product.product", ({ strapi }) => ({
  async findOne(ctx) {
    // ctx 객체의 params에서 productId를 빼온다.
    const { productId } = ctx.params;
	
    // db에서 productId에 맞는 product 하나를 찾아서 entity에 할당한다.
    const entity = await strapi.db.query("api::product.product").findOne({
      where: { productId },
    });

    const sanitizedEntity = await this.sanitizeOutput(entity);

    return this.transformResponse(sanitizedEntity);
  },
}));

이것으로 strapi가 기본으로 제공하는 id가 아니라 custom한 field 값인 productId를 이용해서 데이터를 받아올 수 있게 되었다.

Reference

How to replace the Strapi ID field with a slug field

profile
프런트엔드 개발자

0개의 댓글