Strapi

Node.js/TypeScriptベースのオープンソースヘッドレスCMS。REST/GraphQL API提供、カスタマイズ性が高く開発者フレンドリー。

CMSヘッドレスNode.jsJavaScriptAPIGraphQLREST
ライセンス
MIT
言語
JavaScript/TypeScript
料金
無料プランあり

CMS

Strapi

概要

Strapiは、現代的なWebアプリケーション開発のために設計されたオープンソースのヘッドレスCMSです。

詳細

Strapi(ストラピ)は、フロントエンドとバックエンドを分離したヘッドレス(デカップルド)アーキテクチャを採用したコンテンツ管理システムです。Node.jsとKoa.jsをベースに構築され、開発者に柔軟なAPI開発環境を提供します。RESTとGraphQLの両方のAPIをサポートし、任意のフロントエンド技術(React、Vue.js、Angular、Next.js等)と組み合わせて使用できます。管理画面は直感的で使いやすく、コンテンツタイプの定義、ユーザー管理、権限設定、プラグイン管理等を視覚的に行えます。PostgreSQL、MySQL、SQLite、MariaDBをサポートし、Dockerによるデプロイメント、AWS/GCP/Azureへのクラウドデプロイにも対応しています。企業向けエンタープライズ版では、高度な権限管理、RBAC、SSO、ワークフロー機能が利用できます。

メリット・デメリット

メリット

  • ヘッドレス設計: フロントエンドの選択肢が豊富で柔軟な開発が可能
  • RESTとGraphQL: 両方のAPIタイプをサポート
  • 自己ホスト型: オンプレミスでの完全なデータコントロール
  • 直感的な管理画面: 非技術者でも操作しやすいUI
  • 豊富なプラグイン: 機能拡張が容易
  • オープンソース: 無料で利用でき、コミュニティが活発
  • 多言語対応: 国際化機能を標準搭載

デメリット

  • 自己管理: インフラ管理とメンテナンスが必要
  • 学習コスト: ヘッドレス設計の理解が必要
  • リソース消費: Node.jsアプリケーションとしてのサーバーリソース
  • 複雑な設定: 高度なカスタマイズには技術知識が必要
  • スケーラビリティ: 大規模トラフィックには追加設定が必要

主要リンク

使い方の例

インストールと初期設定

# Strapiプロジェクトの作成
npx create-strapi-app@latest my-project --quickstart

# 開発サーバーの起動
npm run develop

# 管理画面アクセス: http://localhost:1337/admin

コンテンツタイプの定義

// config/api/article/models/article.settings.json
{
  "kind": "collectionType",
  "collectionName": "articles",
  "info": {
    "name": "article"
  },
  "options": {
    "increments": true,
    "timestamps": true
  },
  "attributes": {
    "title": {
      "type": "string",
      "required": true
    },
    "content": {
      "type": "richtext"
    },
    "author": {
      "type": "relation",
      "relation": "manyToOne",
      "target": "plugin::users-permissions.user"
    },
    "published_at": {
      "type": "datetime"
    },
    "slug": {
      "type": "uid",
      "targetField": "title"
    }
  }
}

API の利用

// REST APIでのデータ取得
const response = await fetch('http://localhost:1337/api/articles');
const data = await response.json();

// GraphQLでのデータ取得
const ARTICLES_QUERY = `
  query GetArticles {
    articles {
      data {
        id
        attributes {
          title
          content
          published_at
          author {
            data {
              attributes {
                username
              }
            }
          }
        }
      }
    }
  }
`;

const response = await fetch('http://localhost:1337/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ query: ARTICLES_QUERY }),
});

カスタムAPIエンドポイント

// api/article/controllers/article.js
'use strict';

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

module.exports = createCoreController('api::article.article', ({ strapi }) => ({
  // カスタムエンドポイント
  async findPublished(ctx) {
    const entries = await strapi.entityService.findMany('api::article.article', {
      filters: {
        published_at: {
          $notNull: true,
        },
      },
      populate: {
        author: true,
      },
    });

    return entries;
  },

  // 人気記事の取得
  async findPopular(ctx) {
    const entries = await strapi.entityService.findMany('api::article.article', {
      sort: { views: 'desc' },
      limit: 10,
    });

    return entries;
  }
}));

プラグインの作成

// plugins/custom-plugin/server/controllers/my-controller.js
'use strict';

module.exports = {
  index(ctx) {
    ctx.body = strapi
      .plugin('custom-plugin')
      .service('myService')
      .getWelcomeMessage();
  },
};

// plugins/custom-plugin/server/services/my-service.js
'use strict';

module.exports = {
  getWelcomeMessage() {
    return 'Welcome to Strapi 🚀';
  },
};

Docker設定

# Dockerfile
FROM node:18-alpine
WORKDIR /opt/app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 1337
CMD ["npm", "start"]
# docker-compose.yml
version: '3'
services:
  strapi:
    container_name: strapi
    build: .
    image: strapi:latest
    restart: unless-stopped
    env_file: .env
    environment:
      DATABASE_CLIENT: postgres
      DATABASE_HOST: strapiDB
      DATABASE_PORT: 5432
      DATABASE_NAME: strapi
      DATABASE_USERNAME: strapi
      DATABASE_PASSWORD: strapi
    ports:
      - '1337:1337'
    networks:
      - strapi
    depends_on:
      - strapiDB

  strapiDB:
    container_name: strapiDB
    platform: linux/amd64
    restart: unless-stopped
    env_file: .env
    image: postgres:14.5-alpine
    environment:
      POSTGRES_USER: strapi
      POSTGRES_PASSWORD: strapi
      POSTGRES_DB: strapi
    ports:
      - '5432:5432'
    networks:
      - strapi

networks:
  strapi:
    name: Strapi
    driver: bridge