category icon
2022-08-29
JavaScript - Strapi

Strapi v4 にカウンター機能を追加する。カスタムAPIのメモ( ..)φ

strapi
4.3.2
profile
hikaru
Software Developer / DIY'er

あらかじめ Strapi Dashboard の Content-Type Builder から、Counter という Collection を追加しておきます。今回はサンプルとして名称を Counter としましたが、好きに決められます。

counter/routes/counter.ts を以下のように書き替えます。

src/api/counter/routes/counter.ts
export default {
  routes: [
    {
      method: `PUT`,                       // GET/PUT/POST/DELETE/PATCH
      path: `/counters/:articleId/view`,   // ルーティングパスの指定。「:articleId」は動的なルーティング
      handler: `counter.increment`,        // コントローラーに追加した独自の処理を指定
    },
  ],
};

counter/controllers/counter.ts を以下のように書き替えます。

src/api/counter/controllers/counter.ts
import { factories } from "@strapi/strapi";

interface ArticleCounter {
  id: number;
  view: number;
  createdAt: string;
  updatedAt: string;
}

interface Article {
  id: number;
  counter: ArticleCounter | null;
}

export default factories.createCoreController(
  `api::counter.counter`,
  ({ strapi }) => ({

    /** コントローラーに追加した独自の処理 */
    increment: async (ctx) => {
      // URLから記事IDを取得
      const articleId = ctx.params.articleId as string; // http://localhost:1337/api/counters/:articleId/view

      // 記事IDからカウンター情報を取得する
      const article = (await strapi.entityService.findOne(
        `api::article.article`,
        articleId,
        {
          fields: [],
          populate: { counter: true },
        }
      )) as Article | null;

      // 記事が無ければ処理を中断
      if (article === null) {
        return;
      }

      let counter: ArticleCounter = null;

      if (article.counter === null) {
        // カウンターデータが無ければ、新規作成
        counter = await strapi.entityService.create(
          `api::counter.counter`,
          {
            data: {
              article: articleId,
              view: 1,
            },
          }
        );
      } else {
        // カウンターデータがあれば、カウントアップした値で更新
        counter = await strapi.entityService.update(
          `api::counter.counter`,
          article.counter.id,
          { data: { view: article.counter.view + 1 } }
        );
      }

      ctx.body = { status: `OK`, counter }; // we could also send a JSON
    },

  })
);

ローカル環境であれば http://localhost:1337/api/counters/1234/view に対して PUT でアクセスすると、記事 ID:1234 に対してカウントアップ処理を行います。

nuxt3 でのフロントエンドサンプル

以下、nuxt3 と @nuxtjs/strapi を使った場合のフロントからのアクセス例です。

package.json
{
  "devDependencies": {
    "@nuxtjs/strapi": "^1.5.0",
    "nuxt": "^3.0.0-rc.6"
  }
}
nuxt.config.ts
import { defineNuxtConfig } from "nuxt";

// https://v3.nuxtjs.org/docs/directory-structure/nuxt.config
export default defineNuxtConfig({
  buildModules: [

    // strapi
    [
      "@nuxtjs/strapi",
      {
        url: process.env?.STRAPI_URL || `http://localhost:1337`,
        prefix: "/api",
        version: "v4",
        cookie: {},
      },
    ],

  ],
});
ts
/**
 * 指定した記事IDのviewカウンタをインクリメントするメソッド
 */
async function view(articleId: number) {
  // strapi通信オブジェクトを取得
  const strapiClient = useStrapiClient();

  // API通信: 指定した記事IDのviewカウンタをインクリメントする
  await strapiClient<any>(`/counters/${articleId}/view`, {
    method: `PUT`,
  });
}

view メソッドの引数に記事IDを渡すと、カウンターをインクリメントするカスタム API を呼び出します。