# Account billing details Source: https://docs.strapi.io/cloud/account/account-billing # Account billing & invoices Through the *Profile* page, accessible by clicking on your profile picture on the top right hand corner of the interface then clicking on **Profile**, you can access the [ *Billing*](#account-billing) and [ *Invoices*](#account-invoices) tabs. ## Account billing The *Billing* tab displays and enables you to modify the billing details and payment method set for the account. The *Payment method* section of the *Billing* tab allows you to manage the credit cards that can be used for the Strapi Cloud projects. The *Billing details* section requires to be filled in, at least for the mandatory fields, as this information will be the default billing details for all Strapi Cloud projects related to your account. ### Adding a new credit card 1. In the *Payment method* section of the *Billing* tab, click on the **Add card** button. 2. Fill in the following fields: | Field name | Description | | --- | --- | | Card Number | Write the number of the credit card to add as payment method. | | Expires | Write the expiration date of the credit card. | | CVC | Write the 3-numbers code displayed at the back of the credit card. | 3. Click on the **Save** button. :::tip The first credit card to be added as payment method for the account will by default be the primary one. It is however possible to define another credit card as primary by clicking on the icon, then **Switch as primary**. ::: ### Deleting a credit card To remove a credit card from the list of payment methods for the account: 1. Click on the icon of the credit card you wish to delete. 2. Click **Remove card**. The card is immediately deleted. :::note You cannot delete the primary card as at least one credit card must be available as payment method, and the primary card is by default that one. If the credit card you wish to delete is currently the primary card, you must first define another credit card as primary, then delete it. ::: ## Account invoices The *Invoices* tab displays the complete list of invoices for all your Strapi Cloud projects. :::strapi Invoices are also available per project. In the *Settings > Invoices* tab of any project, you will find the invoices for that project only. Feel free to check the [dedicated documentation](/cloud/projects/settings#invoices). ::: # Profile settings Source: https://docs.strapi.io/cloud/account/account-settings # Profile settings The *Profile* page enables you to manage your account details and preferences. It is accessible by clicking on your profile picture, on the top right hand corner of the interface, and **Profile**. There are 3 tabs available in the *Profile* interface: [*General*](#general), *Billing* and Invoices (the last 2 are documented in the [Account billing details](/cloud/account/account-billing) section of this documentation). ## General The *General* tab enables you to edit the following details for your account profile: - Details: to see the name associated with your account. - Connected accounts: to manage Google, GitHub, GitLab and email accounts connected with your Strapi Cloud account (see [Managing connected accounts](#managing-connected-accounts)). - Delete account: to permanently delete your Strapi Cloud account (see [Deleting Strapi Cloud account](#deleting-strapi-cloud-account)). ### Managing connected accounts You can connect a Google, GitLab, GitHub and email account to your Strapi Cloud account. The _Connected accounts_ section lists accounts that are currently connected to your Strapi Cloud account. From there you can also connect a new Google, GitLab, GitHub and email account if one is not already connected. To connect a new Google, GitLab, GitHub or email account to your Strapi Cloud account, click on the **Connect account** button and follow the next steps on the corresponding website. You can also click on the three dots button of a connected account and click on the "Manage on" button to manage your GitHub, GitLab or Google account directly on the corresponding website. ### Deleting Strapi Cloud account You can delete your Strapi Cloud account, but it will be permanent and irreversible. All associated projects and their data will be deleted as well and the subscriptions for the projects will automatically be canceled. 1. In the *Delete account* section of the *General* tab, click on the **Delete account** button. 2. In the dialog, type `DELETE` in the textbox. 3. Confirm the deletion of your account by clicking on the **Delete** button. # Database Source: https://docs.strapi.io/cloud/advanced/database # Database Strapi Cloud provides a pre-configured PostgreSQL database by default. However, you can also configure it to utilize an external SQL database, if needed. :::prerequisites - A local Strapi project running on `v4.8.2+`. - Credentials for an external database. - If using an existing database, the schema must match the Strapi project schema. ::: :::caution While it's possible to use an external database with Strapi Cloud, you should do it while keeping in mind the following considerations: - Strapi Cloud already provides a managed database that is optimized for Strapi. - Using an external database may result in unexpected behavior and/or performance issues (e.g., network latency may impact performance). For performance reasons, it's recommended to host your external database close to the region where your Strapi Cloud project is hosted. You can find where your Strapi Cloud project is hosted in your Project Settings (see [Project Settings > General > Selected Region](/cloud/projects/settings#general)). - Strapi can't provide security or support with external databases used with Strapi Cloud. ::: :::warning Any environment variable added to your project that starts with `DATABASE_` will cause Strapi Cloud to assume that you will be using an external database and all Strapi Cloud specific database variables will not be injected! ::: ## Configuration The project `./config/database.js` or `./config/database.ts` file must match the configuration found in the [environment variables in database configurations](https://docs.strapi.io/cms/configurations/database#environment-variables-in-database-configurations) section. Before pushing changes, add environment variables to the Strapi Cloud project: 1. Log into Strapi Cloud and click on the corresponding project on the Projects page. 2. Click on the **Settings** tab and choose **Variables** in the left menu. 3. Add the following environment variables: | Variable | Value | Details | | ---------------------------------- | ---------------- |----------| | `DATABASE_CLIENT` | your_db | Should be one of `mysql`, `postgres`, or `sqlite`. | | `DATABASE_HOST` | your_db_host | The URL or IP address of your database host | | `DATABASE_PORT` | your_db_port | The port to access your database | | `DATABASE_NAME` | your_db_name | The name of your database | | `DATABASE_USERNAME` | your_db_username | The username to access your database | | `DATABASE_PASSWORD` | your_db_password | The password associated to this username | | `DATABASE_SSL_REJECT_UNAUTHORIZED` | false | Whether unauthorized connections should be rejected | | `DATABASE_SCHEMA` | public | - | 4. Click **Save**. :::caution To ensure a smooth deployment, it is recommended to not change the names of the environment variables. ::: ## Deployment To deploy the project and utilize the external database, push the changes from earlier. This will trigger a rebuild and new deployment of the Strapi Cloud project. Once the application finishes building, the project will use the external database. ## Reverting to the default database To revert back to the default database, remove the previously added environment variables related to the external database from the Strapi Cloud project dashboard, and save. For the changes to take effect, you must redeploy the Strapi Cloud project. # Email Provider Source: https://docs.strapi.io/cloud/advanced/email # Email Providers configuration for Strapi Cloud Strapi Cloud comes with a basic email provider out of the box. However, it can also be configured to utilize another email provider, if needed. :::caution Please be advised that Strapi is unable to provide support for third-party email providers. ::: :::prerequisites - A local Strapi project running on `v4.8.2+`. - Credentials for another email provider (see :::caution The file structure must match the above path exactly, or the configuration will not be applied to Strapi Cloud. ::: Each provider will have different configuration settings available. Review the respective entry for that provider in the :::tip Before pushing the above changes to GitHub, add environment variables to the Strapi Cloud project to prevent triggering a rebuild and new deployment of the project before the changes are complete. ::: ### Strapi Cloud Configuration 1. Log into Strapi Cloud and click on the corresponding project on the Projects page. 2. Click on the **Settings** tab and choose **Variables** in the left menu. 3. Add the required environment variables specific to the email provider. 4. Click **Save**. **Example:** ## Deployment To deploy the project and utilize another party email provider, push the changes from earlier. This will trigger a rebuild and new deployment of the Strapi Cloud project. Once the application finishes building, the project will use the new email provider. :::strapi Custom Provider If you want to create a custom email provider, please refer to the [Email providers](/cms/features/email#providers) documentation in the CMS Documentation. ::: # Upload Provider Configuration for Strapi Cloud Source: https://docs.strapi.io/cloud/advanced/upload # Upload Provider Configuration for Strapi Cloud Strapi Cloud comes with a local upload provider out of the box. However, it can also be configured to utilize a third-party upload provider, if needed. :::caution Please be advised that Strapi is unable to provide support for third-party upload providers. ::: :::prerequisites - A local Strapi project running on `v4.8.2+`. - Credentials for a third-party upload provider (see :::caution The file structure must match the above path exactly, or the configuration will not be applied to Strapi Cloud. ::: Each provider will have different configuration settings available. Review the respective entry for that provider in the ### Configure the Security Middleware Due to the default settings in the Strapi Security Middleware you will need to modify the `contentSecurityPolicy` settings to properly see thumbnail previews in the Media Library. To do this in your Strapi project: 1. Navigate to `./config/middlewares.js` or `./config/middlewares.ts` in your Strapi project. 2. Replace the default `strapi::security` string with the object provided by the upload provider. **Example:** :::tip Before pushing the above changes to GitHub, add environment variables to the Strapi Cloud project to prevent triggering a rebuild and new deployment of the project before the changes are complete. ::: ### Strapi Cloud Configuration 1. Log into Strapi Cloud and click on the corresponding project on the Projects page. 2. Click on the **Settings** tab and choose **Variables** in the left menu. 3. Add the required environment variables specific to the upload provider. 4. Click **Save**. **Example:** ## Deployment To deploy the project and utilize the third-party upload provider, push the changes from earlier. This will trigger a rebuild and new deployment of the Strapi Cloud project. Once the application finishes building, the project will use the new upload provider. :::strapi Custom Provider If you want to create a custom upload provider, please refer to the [Providers](/cms/features/media-library#providers) documentation in the CMS Documentation. ::: # Command Line Interface (CLI) Source: https://docs.strapi.io/cloud/cli/cloud-cli # Command Line Interface (CLI) Strapi Cloud comes with a Command Line Interface (CLI) which allows you to log in and out, and to deploy a local project without it having to be hosted on a remote git repository. The CLI works with both the `yarn` and `npm` package managers. :::note It is recommended to install Strapi locally only, which requires prefixing all of the following `strapi` commands with the package manager used for the project setup (e.g `npm run strapi help` or `yarn strapi help`) or a dedicated node package executor (e.g. `npx strapi help`). ::: ## strapi login **Alias:** `strapi cloud:login` Log in Strapi Cloud. ```bash strapi login ``` This command automatically opens a browser window to first ask you to confirm that the codes displayed in both the browser window and the terminal are the same. Then you will be able to log into Strapi Cloud via Google, GitHub or GitLab. Once the browser window confirms successful login, it can be safely closed. If the browser window doesn't automatically open, the terminal will display a clickable link as well as the code to enter manually. ## strapi deploy **Alias:** `strapi cloud:deploy` Deploy a new local project (< 100MB) in Strapi Cloud. ```bash strapi deploy ``` This command must be used after the `login` one. It deploys a local Strapi project on Strapi Cloud, without having to host it on a remote git repository beforehand. The terminal will inform you when the project is successfully deployed on Strapi Cloud. Deploying a Strapi project through the CLI creates a project on the Free plan. Once the project is first deployed on Strapi Cloud with the CLI, the `deploy` command can be reused to trigger a new deployment of the same project. :::note Once you deployed your project, if you visit the Strapi Cloud dashboard, you may see some limitations as well as impacts due to creating a Strapi Cloud project that is not in a remote repository and which was deployed with the CLI. - Some areas in the dashboard that are usually reserved to display information about the git provider will be blank. - Some buttons, such as the **Trigger deploy** button, will be greyed out and unclickable since, unless you have [connected a git repository to your Strapi Cloud project](/cloud/getting-started/deployment-cli#automatically-deploying-subsequent-changes). ::: ## strapi link **Alias:** `strapi cloud:link` Links project in the current folder to an existing project in Strapi Cloud. ```bash strapi link ``` This command connects your local project in the current directory with an existing project on your Strapi Cloud account. You will be prompted to select the project you wish to link from a list of available projects hosted on Strapi Cloud. ## strapi projects **Alias:** `strapi cloud:projects` Lists all Strapi Cloud projects associated with your account. ```bash strapi projects ``` This command retrieves and displays a list of all projects hosted on your Strapi Cloud account. ## strapi logout **Alias:** `strapi cloud:logout` Log out of Strapi Cloud. ```bash strapi logout ``` This command logs you out of Strapi Cloud. Once the `logout` command is run, a browser page will open and the terminal will display a confirmation message that you were successfully logged out. You will not be able to use the `deploy` command anymore. # Caching & Performance Source: https://docs.strapi.io/cloud/getting-started/caching # Caching & Performance For Strapi Cloud applications with large amounts of cacheable content, such as images, videos, and other static assets, enabling CDN (Content Delivery Network) caching via the # Strapi Cloud の基礎 Source: https://docs.strapi.io/cloud/getting-started/cloud-fundamentals # Strapi Cloud の基礎 Strapi Cloud のドキュメントを読み進む前に、ここで紹介する主要な概念を押さえておくことをおすすめします。Strapi Cloud の仕組みの理解とスムーズな利用に役立ちます。 - **ホスティングプラットフォーム**
Strapi Cloud は、Strapi CMS(コンテンツ管理システム)で作成した既存の Strapi プロジェクトをデプロイするためのホスティングプラットフォームです。Strapi CMS の SaaS()版ではなく、むしろ PaaS()と捉えてください。Strapi CMS については [CMS ドキュメント](/cms/intro) を参照してください。 - **Strapi Cloud の料金プラン**
Strapi Cloud では Free、Essential、Pro、Scale の 4 プランから選べます。プランにより利用できる機能、サポート、カスタマイズの範囲が異なります(詳細は [料金ページ](https://strapi.io/pricing-cloud))。本ドキュメントでは、セクション見出しの下に 、、 バッジが付く場合、その機能は該当する有料プラン以降でのみ利用できます。バッジがない場合は Free プランでも利用できます。 - **Strapi Cloud のユーザーの種類**
Strapi Cloud プロジェクトには、オーナーとメンテナーの 2 種類のユーザーがいます。オーナーはプロジェクトを作成したユーザーで、プロジェクトに関するすべての機能・オプションにアクセスできます。メンテナーはオーナーに招待され、既存プロジェクトに参加するユーザーです。メンテナーがダッシュボードで参照・操作できない範囲については [コラボレーション](/cloud/projects/collaboration) を参照してください。 - **サポート**
Strapi サポートチームの対応範囲は、契約している Strapi Cloud のプランによります。Free プランにはサポートは含まれません。Essential と Pro は Basic サポート、Scale は Standard サポートです。レベルの詳細は [サポートに関する記事](https://support.strapi.io/support/solutions/articles/67000680833-what-is-supported-by-the-strapi-team#Not-Supported) を参照してください。 - **Strapi Cloud とセルフホストでの API**
REST API と GraphQL API の挙動は Strapi Cloud とセルフホストで同じです。違いは主に URL です。 - API のベースドメイン: Strapi Cloud では環境のドメイン(例: `https://.strapiapp.com/api/...`)を使うか、独自ドメインを設定した場合はそのドメインを使います([ドメイン](/cloud/projects/settings#domains))。セルフホストでは公開するドメインを任意に設定します。 - メディアライブラリの URL: Strapi Cloud の REST / GraphQL レスポンスでは、カスタムドメインで API にアクセスしていても、メディアフィールドの URL はプロジェクトのメディアドメイン(例: `.media.strapiapp.com`)になります。セルフホストでは設定したアップロードプロバイダーの URL が返り、自サイトや CDN と一致させられます。セルフホストから Strapi Cloud に移行する場合は、フロントエンドが API が返す絶対 URL を読むか、Strapi Cloud のメディアドメインを受け入れるようにしてください。 # Strapi Cloud - ダッシュボードからのデプロイ Source: https://docs.strapi.io/cloud/getting-started/deployment # Cloud ダッシュボードからプロジェクトをデプロイする 初めて Strapi Cloud にプロジェクトを載せるときの、Cloud ダッシュボード利用の手順です。 :::prerequisites Cloud ダッシュボードからデプロイする前に次を満たしてください。 * Strapi バージョン `4.8.2` 以上 * プロジェクトのデータベースは PostgreSQL と互換であること。外部 DB はサポート・推奨されませんが設定は可能です([高度なデータベース設定](/cloud/advanced/database))。 * ソースコードが 5. Strapi Cloud プロジェクトを設定します。 5.a. 次の情報を入力します。 | 設定名 | 説明 | |--------------|---------------------------------------------------------------------------------------------------------| | Display name | 選んだリポジトリ名が自動入力されますが、必要なら編集できます。 | | Git branch | デプロイするブランチをドロップダウンから選びます。 | | Deploy on push | 選択したブランチへの push で自動デプロイする場合はオン。オフの場合は手動で最新をデプロイします。 | | Region | Strapi をホストするサーバーの地理的リージョン。米国(東)、欧州(西)、東南アジアから選べます。 | :::note Git ブランチと「Deploy on push」は後からプロジェクト設定で変更できます。ホスティングリージョンは**プロジェクト作成時のみ**選べます([プロジェクト設定](/cloud/projects/settings))。 ::: 5.b. (任意)**Show advanced settings** で次を入力します。 | 設定名 | 説明 | |--------------|---------------------------------------------------------------------------------------------------------| | Base directory | リポジトリ内で Strapi アプリがあるディレクトリ名。モノレポや同一リポジトリに複数アプリがあるときに使用します。 | | Environment variables | **Add variable** で Strapi の環境変数を追加します([環境変数](/cms/configurations/environment/))。Strapi アプリ直下の `.env` にも定義でき、Strapi Cloud でも利用されます。 | | Node version | ドロップダウンで Node バージョンを選びます。既定はプロジェクトの Strapi に合うよう自動選択されます。手動で合わないバージョンを選ぶとビルドは失敗し、ビルドログに理由が出ます。 | :::strapi 環境変数の利用 環境変数で Strapi Cloud 既定以外の外部データベースに接続できます(詳細は [データベース設定](/cms/configurations/database#environment-variables-in-database-configurations))。Strapi 既定の DB に戻す場合は `DATABASE_` で始まる環境変数を削除します(自動マイグレーションはありません)。 カスタムのメールプロバイダーもここで設定できます。Strapi Cloud 上のアプリでは Sendgrid が既定です([プロバイダー設定](/cms/features/email#providers))。 ::: ## 請求情報の設定 :::strapi Free プランに請求ステップはありません Free を選んだ場合、クレジットカード入力は求められず、このステップはスキップされます。 下のセクションのステップ 5 に進み、プロジェクト作成を完了してください。 ::: 1. **Continue to billing** をクリックします。請求ページで支払い情報を入力し、請求内容を確認します。 2. *Payment method* でクレジットカードを追加します。このカードがアドオンや超過分などプロジェクト関連の課金に使われます。 3. *Billing information* に支払い・請求先住所を入力します。 4. *Invoice* を確認します。月額契約の場合、現在の請求サイクル残り日数に応じて日割りが入ります。*Discount code* を展開してコードを入力することもできます。 :::note 請求先に応じて税が加算されることがあります。 - EU / 英国: 有効な VAT ID があれば VAT は免除。なければ請求書に VAT が加算されます。 - 米国: 州と住所に基づき売上税が計算されます。 ::: 5. **Subscribe** をクリックして Strapi Cloud プロジェクトの作成を完了します。 ## プロジェクトのデプロイ 作成を確定すると *Project dashboard* に移り、作成と初回デプロイの進行を追跡できます。 デプロイ中でも [プロジェクト設定](/cloud/projects/settings) の一部を先に構成できます。 :::note 作成中にエラーが出ると、進行表示が止まりエラーメッセージが表示されます。失敗したステップの横に **Retry** が出るので、作成プロセスを再開できます。 ::: デプロイが成功すると、作成トラッカーがデプロイ一覧に置き換わり、クラウド上のアプリにアクセスできます。Strapi プロジェクトを共有する前に、最初の管理者ユーザーを作成してください。 ## 次のステップ Cloud ダッシュボードからデプロイできたら、次も試してください。 - 他のユーザーを [プロジェクトに招待](/cloud/projects/collaboration) する - [デプロイ管理](/cloud/projects/deploys) で新しいデプロイの手順を読む # Strapi Cloud - CLI deployment Source: https://docs.strapi.io/cloud/getting-started/deployment-cli # Project deployment with the Command Line Interface (CLI) This is a step-by-step guide for deploying your project on Strapi Cloud for the first time, using the Command Line Interface. :::prerequisites Before you can deploy your Strapi application on Strapi Cloud using the Command Line Interface, you need to have the following prerequisites: - Have a Google, GitHub or GitLab account. - Have an already created Strapi project (see [Installing from CLI in the CMS Documentation](/cms/installation/cli)), stored locally. The project must be less than 100MB. - Have available storage in your hard drive where the temporary folder of your operating system is stored. ::: ## Logging in to Strapi Cloud 1. Open your terminal. 2. Navigate to the folder of your Strapi project, stored locally on your computer. 3. Enter the following command to log into Strapi Cloud: 4. In the browser window that opens automatically, confirm that the code displayed is the same as the one written in the terminal message. 5. Still in the browser window, choose whether to login via Google, GitHub or GitLab. The window should confirm the successful login soon after. ## Deploying your project 1. From your terminal, still from the folder of your Strapi project, enter the following command to deploy the project: 2. Follow the progression bar in the terminal until confirmation that the project was successfully deployed with Strapi Cloud. Deploying the project will create a new Strapi Cloud project on the Free plan. ### Automatically deploying subsequent changes By default, when creating and deploying a project with the Cloud CLI, you need to manually deploy again all subsequent changes by running the corresponding `deploy` command everytime you make a change. Another option is to enable automatic deployment through a git repository. To do so: 1. Host your code on a git repository, such as or . 2. Connect your Strapi Cloud project to the repository (see the _Connected repository_ setting in [Projects Settings > General](/cloud/projects/settings#general)). 3. Still in _Projects Settings > General_ tab, tick the box for the "Deploy the project on every commit pushed to this branch" setting. From now on, a new deployment to Strapi Cloud will be triggered any time a commit is pushed to the connected git repository. :::note Automatic deployment is compatible with all other deployment methods, so once a git repository is connected, you can trigger a new deployment to Strapi Cloud [from the Cloud dashboard](/cloud/projects/deploys), [from the CLI](/cloud/cli/cloud-cli#strapi-deploy), or by pushing new commits to your connected repository. ::: ## ⏩ What to do next? Now that you have deployed your project via the Command Line Interface, we encourage you to explore the following ideas to have an even more complete Strapi Cloud experience: - Visit the Cloud dashboard to follow [insightful metrics and information](/cloud/projects/overview) on your Strapi project. - Check out the full [Command Line Interface documentation](/cloud/cli/cloud-cli) to learn about the other commands available. # Project deployment Source: https://docs.strapi.io/cloud/getting-started/deployment-options # Project deployment with Strapi Cloud You have 2 options to deploy your project with Strapi Cloud: - either with the user interface (UI), meaning that you will perform all the actions directly on the Strapi Cloud dashboard, - or using the Cloud Comment Line Interface (CLI), meaning that you will only interact with a terminal. The guides below will guide you through all the steps for each of the deployment options. # Strapi Cloud ドキュメントへようこそ Source: https://docs.strapi.io/cloud/getting-started/intro # Strapi Cloud ドキュメントへようこそ Strapi Cloud ドキュメントには、Strapi Cloud アカウントとアプリケーションのセットアップ、デプロイ、更新、カスタマイズに関する情報がまとまっています。 :::strapi Strapi Cloud とは? です。 ::: :::prerequisites Strapi チームが推奨する典型的な流れは次のとおりです。 1. ローカルで Strapi アプリケーションを作成する(v4.8.2 以降)。 2. 必要に応じてプラグインや独自コードで拡張する。 3. Git プロバイダー(GitHub または GitLab)でコードベースをバージョン管理する。 4. Strapi Cloud にアプリケーションをデプロイする。 ::: Strapi Cloud ドキュメントは、プロダクト利用の流れに沿ったトピック順に構成されています。次のカードをクリックすると、主要なトピックと手順へ移動します。 :::strapi Strapi コミュニティへようこそ! Strapi Cloud は、オープンソースでコミュニティ志向の Strapi の上に構築されています。Strapi チームはビジョンを共有し、コミュニティとともに Strapi の未来を形作りたいと考えています。そのため は公開されており、さまざまな知見がプロジェクトの方向づけに役立ちます。コミュニティの誰もがアイデアや意見を共有できます。 、、 に参加すれば、長年の経験と知識、コントリビューションをコミュニティ全体から得られます。 ::: # 請求と利用に関する情報 Source: https://docs.strapi.io/cloud/getting-started/usage-billing # 請求と利用に関する情報 Strapi Cloud アカウントとプロジェクトの利用・請求に関する概要です。 Strapi Cloud には Free と、有料の Essential / Pro / Scale があります([料金ページ](https://strapi.io/pricing-cloud))。下表は主な機能と利用枠の整理です。 | 機能 | Free | Essential | Pro | Scale | | -------------------------------- | ----- | --------- | --- | ----- | | **データベースエントリ数** | 500 | 無制限* | 無制限* | 無制限* | | **アセットストレージ** | 10GB | 50GB | 250GB | 1,000GB | | **アセット帯域幅(月あたり)** | 10GB | 50GB | 500GB | 1,000GB | | **API リクエスト(月あたり)** | 2,500 | 50,000 | 1,000,000 | 10,000,000 | | | | | | | | **バックアップ** | 該当なし | 該当なし | 週次 | 日次 | | **カスタムドメイン** | 該当なし | 含まれる | 含まれる | 含まれる | | **環境** | 該当なし | 該当なし | 0 含む(最大 99 まで追加) | 1 含む(最大 99 まで追加) | | **メール(月あたり)** | 100 | 無制限* | 無制限* | 無制限* | :::strapi 利用量と機能の補足 - 一般的な機能・利用量: - データベースエントリ数は DB 内のエントリー件数です。 - アセットストレージはアセットが占める容量です。 - アセット帯域幅はアセット配信に使った転送量です。 - API リクエストは API へのリクエスト数です。GraphQL と REST を含み、CDN の帯域・ストレージとしてカウントされるメディアファイル向けリクエストは除きます。レスポンスの種類に関わらず、月間利用量に含まれます。 - Cloud 固有の機能: - バックアップは Strapi Cloud プロジェクトの自動バックアップです(詳細は [バックアップ](/cloud/projects/settings#backups))。 - カスタムドメインは Strapi Cloud 用の独自ドメイン設定です([カスタムドメイン](/cloud/projects/settings#connecting-a-custom-domain))。 - 環境数は、既定の本番環境に加えてプランに含まれる追加環境の数です([環境](/cloud/projects/settings#environments))。 ::: :::caution Free プランは個人・非商用のみ 商用利用には次のようなものが含まれます。 - サイトでの決済の受け付け・処理 - サイトの作成・更新・ホストの対価としての報酬 - 商品・サービスの広告・宣伝・販売 - 第三者向け広告のホスト・配信 詳細は [Strapi Cloud-Legal](https://strapi.io/cloud-legal) を参照してください。 ::: :::info Free プランのスケールゼロとコールドスタート Free プランでは、しばらくアクセスがないとプロジェクトが自動的にスケールダウンしてゼロになります。フロントエンドや API から再度アクセスすると、応答が返るまで数秒〜1 分ほどかかることがあります。 有料プランに上げるとスケールゼロとコールドスタートが無効になり、常にすぐ応答しやすくなります。 ::: ## 環境の管理 環境は Strapi Cloud プロジェクトの隔離されたインスタンスです。すべてのプロジェクトに既定の本番環境があり、Pro または Scale ではプロジェクト設定の *Environments* タブから追加環境を構成できます([環境](/cloud/projects/settings#environments))。追加環境の数に上限はありません。 追加環境の利用上限は本番環境と同じです(例: Pro ならアセットストレージも 250GB まで。超過料金の扱いも本番と同様)。ただしアセット帯域と API 呼び出しは**プロジェクト単位**のため、環境を増やしてもこれらの枠自体は増えません。 ## 請求 請求は Strapi Cloud プロジェクトの利用に基づきます。プロジェクトのプランとアドオンは請求サイクルに応じて月払いまたは年払い、超過分は月次請求です。利用量と請求はプロジェクト設定の *Billing & Usage* で確認できます。 ### 税 米国・英国・EU の請求先住所では、地域の税が請求書に加算されることがあります。税額は請求先と VAT/Tax ID の状態に基づき、チェックアウトと請求書に表示されます。 VAT/Tax ID は [アカウントの請求](/cloud/account/account-billing) 設定で追加・更新できます。 ### 超過利用(Overages) :::caution Free プランでは超過利用はできません。 ::: API リクエスト、アセット帯域、アセットストレージの上限を超えると、超過分に対する料金が発生します。 例: Pro のアセット帯域 500GB を超えた場合、現在の請求期間の終わりかプロジェクト削除時に超過分が課金されます。超過分の日割りはなく、全額が請求されます。 超過分の料金は月次で、次のレートが適用されます。 | 機能 | レート | | --- | --- | | **API リクエスト** | $1.50 / 2.5 万リクエスト | | **アセット帯域** | $30.00 / 100GB | | **アセットストレージ** | $0.60 / GB・月 | ### プロジェクトの停止(Suspension) {#project-suspension} **Suspended** になる理由には、未払い請求、Free プラン上限の超過、Strapi Cloud の 違反などがあります。 停止中は管理パネルにアクセスできず、新しいデプロイも実行できません。ダッシュボードに理由を示すバナーが出ます。メールでも通知されます。 #### Free プランの上限超過による停止 Free で API リクエストまたはアセット帯域のいずれかを超過すると、翌月の枠がリセットされるまで停止します。 停止中は次のとおりです。 - 新しいデプロイは実行できない - アプリケーションへのアクセスはブロックされる - プロジェクト設定の変更はできない すぐ再有効化するには有料プランへのアップグレードが必要です。 #### 請求トラブルによる停止 未払い請求があるとサブスクリプションが自動解約され、プロジェクトが停止します。 再有効化するには *Settings > Billing & Usage* で **Reactivate subscription** をクリックします。 :::warning 30 日以内に解決しないと、停止中のプロジェクトは削除され、データは完全に失われます。 ::: #### その他の理由による停止 未払い以外でサブスクリプション解約に至った場合など、自分で再有効化できないことがあります。メールの手順に従ってください。通知がない場合は [Strapi Support](mailto:support@strapi.io) に連絡してください。 ### サブスクリプションの解約 Strapi Cloud のサブスクリプションをやめるには次のいずれかです。 - プロジェクトのサブスクリプションを Free プランに変更する([プランのダウングレード](/cloud/projects/settings#downgrading-to-another-plan)) - プロジェクトを完全に削除する([Strapi Cloud プロジェクトの削除](/cloud/projects/settings#deleting-a-strapi-cloud-project)) # コラボレーション Source: https://docs.strapi.io/cloud/projects/collaboration # プロジェクトでのコラボレーション プロジェクトは Strapi Cloud アカウントを持つユーザーが作成します。Strapi Cloud ユーザーはプロジェクトを他ユーザーに共有でき、オーナーが認証情報を共有しなくても、招待されたユーザーはプロジェクトダッシュボードにアクセスして共同作業できます。 プロジェクトに招待された共同編集者(メンテナー)は、オーナーと同じ権限は持ちません。メンテナーは次を実行できません。 - プロジェクトを第三者に共有する - プロジェクト設定からプロジェクトを削除する - プロジェクト設定の *Billing* セクションにアクセスする ## プロジェクトを共有する プロジェクトは Strapi Cloud アカウントを持つユーザーが作成します。Strapi Cloud ユーザーはプロジェクトを他ユーザーに共有でき、オーナーが認証情報を共有しなくても、招待されたユーザーはプロジェクトダッシュボードにアクセスして共同作業できます。 プロジェクトに招待された共同編集者(メンテナー)は、オーナーと同じ権限は持ちません。メンテナーは次を実行できません。 - プロジェクトを第三者に共有する - プロジェクト設定からプロジェクトを削除する - プロジェクト設定の *Billing* セクションにアクセスする ## プロジェクトを共有する 新しいメンテナーを招待する手順: 1. *Projects* ページで対象プロジェクトをクリックし、ダッシュボードへ移動します。 2. ダッシュボードヘッダーの **Share** ボタンをクリックします。 3. *Share [project name]* ダイアログで、招待したい相手のメールアドレスを入力します。`Invite [email address]` と表示されたドロップダウンが出ます。 4. そのドロップダウンをクリックすると、入力欄の下に紫色のボックスでメールアドレスが表示されます。 5. (任意)さらに招待する場合は手順 3 と 4 を繰り返します。メールアドレスは 1 件ずつ入力しますが、招待は複数宛先をまとめて送信できます。 6. **Send** ボタンをクリックします。 招待されたメンテナーには、プロジェクト参加用リンク付きメールが送信されます。共有後は **Share** ボタンの横にメンテナーのアバターが表示され、参加人数と参加者を確認できます。 :::tip アバターには GitHub / Google / GitLab のプロフィール画像が使われます。保留中ユーザーはアカウント有効化までイニシャル表示になります。アバターにカーソルを合わせるとフルネームを確認できます。 :::: ## メンテナーを管理する プロジェクトダッシュボードの **Share** ボタンから開く *Share [project name]* ダイアログでは、オーナーが招待済みメンテナーの一覧と各ステータスを確認し、管理できます。 フルネームが表示されているメンテナーは、招待メール経由でアカウントを有効化済みのユーザーです。一覧でメールアドレスのみが表示されている場合は、まだ有効化が完了しておらず、ダッシュボードへアクセスできません。その場合はメールアドレス横に次のステータスが表示されます。 - Pending: 招待メール送信済みで、まだアクションがない状態 - Expired: 送信から 72 時間以上経過し、招待の有効期限が切れた状態 `Expired` の場合は、**Manage** → **Resend invite** で再送できます。 ### メンテナーアクセスを取り消す メンテナーのダッシュボードアクセスを取り消す手順: 1. プロジェクトダッシュボードヘッダーの **Share** ボタンをクリックします。 2. *People with access* 一覧で対象メンテナーを探し、**Manage** をクリックします。 3. **Revoke** ボタンをクリックします。 4. 確認ダイアログで再度 **Revoke** をクリックします。 取り消されたメンテナーは、プロジェクトダッシュボードにアクセスできなくなります。 :::note アクセス取り消し時、対象メンテナーにはメールや通知は送信されません。 :::: # デプロイ管理 Source: https://docs.strapi.io/cloud/projects/deploys # デプロイ管理 新しい Strapi Cloud プロジェクトを作成すると、最初のデプロイが自動で実行されます。以降のデプロイは次の方法で行えます。 - 必要なときに手動で実行([Cloud ダッシュボード](#新しいデプロイを実行する) または [CLI](/cloud/cli/cloud-cli#strapi-deploy) から) - Strapi Cloud プロジェクトが Git リポジトリに接続され、`deploy on push` が有効な場合は、対象ブランチへのコミットプッシュ時に自動実行([プロジェクト設定](/cloud/projects/settings#modifying-git-repository--branch) を参照) 進行中のデプロイは必要に応じて [手動でキャンセル](#デプロイをキャンセルする) できます。 ## 新しいデプロイを実行する プロジェクトで新しいデプロイを手動実行するには、プロジェクトダッシュボードのヘッダー右上に常時表示される **Trigger deployment** ボタンをクリックします。 実行すると *Deployments* タブに新しいカードが追加され、ステータスの監視やログのリアルタイム確認ができます([デプロイ履歴とログ](/cloud/projects/deploys-history) を参照)。 ## デプロイをキャンセルする 何らかの理由で、進行中で未完了のデプロイをキャンセルする場合: 1. 最新のデプロイの *Deployment details* ページへ移動します([ログ詳細へのアクセス](/cloud/projects/deploys-history#accessing-deployment-details--logs) を参照)。 2. 右上の **Cancel deployment** ボタンをクリックします。デプロイのステータスは自動で *Canceled* に変わります。 :::tip デプロイ履歴が表示される *Deployments* タブからもキャンセルできます。 *Building* ステータスの進行中デプロイカードには、キャンセル用の ![Cancel button](/img/assets/icons/clear.svg) ボタンが表示されます。 ::: # デプロイ履歴とログ Source: https://docs.strapi.io/cloud/projects/deploys-history # デプロイ履歴とログ {#deploy-history-and-logs} Strapi Cloud の各プロジェクトでは、実行済みデプロイの履歴と、ビルドログ/デプロイログを含む詳細情報を確認できます。これらは *Deployments* タブで利用できます。 ## デプロイ履歴を確認する {#viewing-deploy-history} *Deployments* タブには、プロジェクトの過去デプロイ詳細が時系列カードで表示されます。 、Git プロバイダーへの直接リンク、コミットメッセージ - デプロイステータス: - *Deploying* - *Done* - *Canceled* - *Build failed* - *Deployment failed* - 最終デプロイ時刻(トリガー時刻と所要時間) - ブランチ ## デプロイ詳細とログにアクセスする {#accessing-deployment-details--logs} *Deployments* タブでデプロイカードにカーソルを合わせると、![See logs button](/img/assets/icons/Eye.svg) **Show details** ボタンが表示されます。これをクリックすると、デプロイ詳細ログを含む *Deployment details* ページへ移動します。 、Git プロバイダーへの直接リンク、このデプロイで使われたコミットメッセージ - *Status*: *Building*、*Deploying*、*Done*、*Canceled*、*Build failed*、*Deployment failed* - *Source*: このデプロイに対応するブランチとコミットメッセージ - *Duration*: デプロイ所要時間と実行時刻 # 通知 Source: https://docs.strapi.io/cloud/projects/notifications # 通知 Cloud ダッシュボード上部ナビゲーションのベルアイコン をクリックすると、Notification center を開けます。 既存の全プロジェクトに関する最新通知が一覧表示されます。通知カードをクリックすると、対応するデプロイの *Log details* ページへ移動します(詳細は [Deploy history & logs](/cloud/projects/deploys-history#accessing-deployment-details--logs) を参照)。 Notification center には次の通知が表示されます。 - *deployment completed*: デプロイが正常に完了したとき - *Build failed*: ビルド段階でデプロイが失敗したとき - *deployment failed*: デプロイ段階で失敗したとき - *deployment triggered*: 接続済みリポジトリへの新規プッシュでデプロイが開始されたとき(手動トリガー時は通知されません) :::note 30 日を超えた通知は Notification center から自動削除されます。 ::: # プロジェクトの概要 Source: https://docs.strapi.io/cloud/projects/overview # プロジェクトの概要 *Projects* ページには、Strapi Cloud のすべてのプロジェクトが一覧表示されます。ここからプロジェクトを管理し、対応するアプリケーションへアクセスできます。 各プロジェクトカードには次の情報が表示されます。 * プロジェクト名 * 本番環境の最後に成功したデプロイの日付 * プロジェクトの現在の状態: * *Disconnected*(リポジトリが Strapi Cloud に未接続) * *Suspended*(停止中。[プロジェクトの停止](/cloud/getting-started/usage-billing#project-suspension) を参照して再有効化) * *Incompatible version*(Strapi Cloud と互換性のない Strapi バージョンを使用中) 各カードには メニューがあり、次の操作ができます。 * **Visit App**: アプリケーションを開く * **Go to Deployments**: [*Deployment*](/cloud/projects/deploys) ページへ * **Go to Settings**: [*Settings*](/cloud/projects/settings) ページへ :::tip ナビゲーションバーの * Product updates* で、最新機能と修正を確認できます。 ::: ## プロジェクトのダッシュボードへアクセスする *Projects* ページで任意のプロジェクトカードをクリックするとダッシュボードが開きます。プロジェクトと環境の詳細、デプロイ履歴、各種設定へのアクセスができます。 ヘッダーから次の操作ができます。 - **Share** でプロジェクトへの共同編集ユーザーを招待する([コラボレーション](/cloud/projects/collaboration))。すでに招待済みのユーザーはアイコンで表示されます 。 - **Settings** でプロジェクトと既存環境の設定を開く 。 - 表示する環境の選択、または新しい環境の追加 。 - 新しいデプロイの実行([デプロイの管理](/cloud/projects/deploys))とアプリへの訪問 。 ダッシュボードにはほかにも次があります。 - *Deployments* と *Runtime logs* タブ(デプロイ履歴は [デプロイ履歴とログ](/cloud/projects/deploys-history)、ランタイムログは [該当ページ](/cloud/projects/runtime-logs)) - 右側のボックスにプロジェクトと環境の詳細 。内容の例: - API 呼び出し数 - アセットの帯域幅とストレージの現在の使用量 - ブランチ名と、ブランチ設定への **Manage**([Git リポジトリとブランチの変更](/cloud/projects/settings#modifying-git-repository--branch)) - ベースディレクトリ名 - Strapi のバージョン - Strapi アプリの URL # ランタイムログ Source: https://docs.strapi.io/cloud/projects/runtime-logs # ランタイムログ 対象プロジェクトのダッシュボードでは、*Runtime logs* タブにプロジェクトのライブログが表示されます。 :::note - *Runtime logs* は、プロジェクトのデプロイ成功後にのみ利用できます。 - Free プランではランタイムログはライブ表示されず、非アクティブによりアプリがスケールゼロになるたびにリセットされます。 ::: # プロジェクト設定 Source: https://docs.strapi.io/cloud/projects/settings # プロジェクト設定 対象プロジェクトのダッシュボードでは、ヘッダーにある **Settings** ボタンから、Strapi Cloud プロジェクト本体と各環境の設定を管理できます。 画面左の設定メニューは、プロジェクト全体の設定と、各環境に固有の設定の 2 つに分かれています。 ## プロジェクト全体の設定 プロジェクト設定には、次の 5 つのタブがあります。 - [*General*](#general), - [*Environments*](#environments), - [*Billing & Usage*](#billing--usage), - [Plans](#plans), - and [Invoices](#invoices). ### General {#general} *General* タブでは、次の項目を確認・更新できます。 - *Basic information*: - Strapi Cloud プロジェクト名(Cloud ダッシュボード、Strapi CLI、デプロイ URL での識別に使用)を確認・変更([プロジェクト名を変更する](#renaming-project) を参照) - ホスティングリージョン(プロジェクト・データ・リソースを保持するサーバーの地理的な配置)を確認。リージョンは作成時に決まり([プロジェクト作成](/cloud/getting-started/deployment) を参照)、後から変更できません。 - Production アプリ内部名や Subscription ID など、デバッグやサポートで役立つメタデータを確認 - *Strapi CMS license key*: Cloud プロジェクト上で CMS 機能を有効化(ライセンス購入は [Pricing page](https://strapi.io/pricing-self-hosted) を参照) - *Connected Git repository*: プロジェクトで使うリポジトリとブランチを変更([Git リポジトリとブランチを変更する](#modifying-git-repository--branch) を参照)。`deploy on push` の有効/無効も切り替え可能 - *Danger zone*: - *Transfer ownership*: 既存メンテナーへオーナー権限を移譲([プロジェクト所有権を移譲する](#transferring-project-ownership) を参照) - *Delete project*: Strapi Cloud プロジェクトを恒久的に削除([Strapi Cloud プロジェクトを削除する](#deleting-a-strapi-cloud-project) を参照) #### プロジェクト名を変更する {#renaming-project} プロジェクト名は作成時に設定されますが([プロジェクト作成](/cloud/getting-started/deployment) を参照)、後からプロジェクト設定で変更できます。 1. *General* タブの *Basic information* セクションで、編集 ボタンをクリックします。 2. ダイアログの *Project name* 入力欄に、新しいプロジェクト名を入力します。 3. **Rename** をクリックして変更を確定します。 #### Adding a CMS license key {#adding-cms-license-key} CMS ライセンスキーを Strapi Cloud プロジェクトに紐づけると、すべての環境で追加の Strapi CMS 機能を利用できます。利用可能な機能は購入したライセンス種別に依存します。詳細や購入は を参照してください。 :::note *Strapi CMS license key* セクションが表示されない場合、契約がレガシープランでカスタム CMS ライセンスをサポートしていない可能性があります。その場合は、プロジェクトにライセンスが自動付与済みです。 ::: 1. *Strapi CMS license key* セクションで **Add license** をクリックします。 2. ダイアログの入力欄にライセンスキーを貼り付けます。 3. **Save & deploy** をクリックして反映します。 Strapi Cloud プロジェクトから CMS ライセンスを外すには、**Unlink license** をクリックします。解除すると、そのライセンスで使っていた CMS 機能にもアクセスできなくなります。 :::note ライセンスキーはプロジェクト内の全環境に適用されます。 ::: #### Git リポジトリとブランチを変更する {#modifying-git-repository--branch} Strapi Cloud プロジェクトの GitHub/GitLab リポジトリ、ブランチ、ベースディレクトリは、プロジェクト作成時に設定されます([プロジェクト作成](/cloud/getting-started/deployment) を参照)。作成後も、プロジェクト設定からリポジトリ更新や Git プロバイダー切り替えが可能です。 :::caution 誤ったリポジトリを選択した場合や、新旧リポジトリでデータスキーマが一致しない場合、プロジェクトやデータが失われる可能性があります。 ::: 1. *General* タブの *Connected git repository* セクションで **Update repository** をクリックします。別画面に遷移します。 2. (任意)リポジトリ更新だけでなく Git プロバイダーも切り替える場合は、画面右上の **Switch Git provider** をクリックします。選択した Git プロバイダーの認可画面を経由後、*Update repository* 画面に戻ります。 3. *Update repository* セクションで次の 2 項目を設定します。 | 設定項目 | 手順 | | --- | --- | | Account | ドロップダウンからアカウントを選択します。 | | Repository | ドロップダウンからリポジトリを選択します。 | 4. *Select Git branches* セクションで、環境ごとの設定を入力します。ブランチは各環境の設定画面でも変更できます([Environments](#environments) を参照)。 | 設定項目 | 手順 | | --- | --- | | Branch | ドロップダウンからブランチを選択します。 | | Base directory | 入力欄にベースディレクトリのパスを入力します。 | | Auto-deploy | チェックすると、対象ブランチに新規コミットがプッシュされるたびに自動デプロイします。無効化する場合はチェックを外します。 | 5. **Save & deploy** をクリックして変更を反映します。 #### プロジェクト所有権を移譲する {#transferring-project-ownership} Strapi Cloud プロジェクトの所有権は、対象ユーザーがメンテナーであれば移譲できます。現在のオーナーが開始することも、メンテナーが申請することもできます。移譲が完了すると、新しいオーナーが再移譲するまで有効です。 :::prerequisites 所有権を移譲するには、次の条件を満たす必要があります。 - プロジェクトが有料プランで、期限切れカードや未払い請求がないこと - メンテナーが請求情報を入力済みであること - 当該プロジェクトで保留中の所有権移譲がないこと サブスクリプション更新日(毎月 1 日)当日の移譲は失敗する場合があります。その日に失敗し、かつ前提条件を満たしている場合は、数時間待ってから再試行してください。 ::: 1. *General* タブの *Danger zone* で **Transfer ownership** をクリックします。 2. ダイアログで操作します。 - オーナーの場合: 対象メンテナーの行で **...** > **Transfer ownership** をクリックします。 - メンテナーの場合: 自分の行で **...** > **Transfer ownership** をクリックします。 3. 新しいダイアログで **Transfer ownership** をクリックし、移譲/申請を確定します。 両ユーザーにメールが送信されます。移譲する側または受け取る側は、メール内の **Confirm transfer** をクリックして確定します。完了後、旧オーナーへ完了通知メールが届きます。 :::tip 移譲または申請が確定されるまでは、メンテナー選択と同じダイアログからキャンセルできます。 ::: :::note 所有権移譲後、プロジェクトは Strapi Cloud から一度切断されます。新しいオーナーは、プロジェクト設定の *General* タブから再接続してください。 ::: #### Strapi Cloud プロジェクトを削除する {#deleting-a-strapi-cloud-project} Strapi Cloud プロジェクトは削除できますが、操作は恒久的で元に戻せません。関連ドメイン、デプロイ、データは削除され、サブスクリプションは自動解約されます。 1. *General* タブの *Danger zone* で **Delete project** をクリックします。 2. ダイアログで削除理由を選択します。 3. **Delete project** をクリックして削除を確定します。 ### Environments {#environments} *Environments* タブでは、設定済み環境の一覧確認と新規環境の作成ができます。Production は既定環境で削除できません。その他の環境は契約プランの範囲内で追加でき、Strapi Cloud プロジェクトを分離環境で安全に運用できます(例: 本番前に検証する staging 環境)。 :::note 追加環境の課金サイクルは、契約プランの課金サイクルに合わせられます。 ::: 新しい環境を作成する手順: 1. **Add a new environment** をクリックします。 2. セットアップ画面で設定を入力します。 | 設定項目 | 手順 | | --- | --- | | Environment name | (必須)新しい環境名を入力します。 | | Git branch | (必須)新しい環境に紐づけるブランチを選択します。 | | Base directory | 新しい環境のベースディレクトリ名を入力します。 | | Deploy on push | チェックすると、選択ブランチへ変更がプッシュされたときに自動でデプロイします。無効時は最新変更を手動デプロイします。 | | Import variables | チェックすると既存環境から変数名のみ取り込みます。値は取り込まれず空欄のままです。 | 3. **Confirm** をクリックしてチェックアウト手順へ進みます。 4. 環境料金、適用税額、日割り調整を確認します。 5. **Add environment** をクリックして環境を作成します。*Project dashboard* に戻り、新しい環境の作成状況と初回デプロイを確認できます。 :::note 環境作成中にエラーが発生すると、進行表示が停止しエラーメッセージが表示されます。失敗したステップの横に **Retry** が表示されるため、作成処理を再開できます。 ::: ### Billing & Usage {#billing--usage} *Billing & Usage* タブでは、次回の見込み請求額、現在のサブスクリプション情報、プロジェクト利用状況の詳細サマリーを確認できます。ここから新しい環境の追加も可能です([Environments](#environments) を参照)。 このタブでは次の操作もできます。 - **Change** をクリックして *Plans* タブへ移動し、サブスクリプションプランや請求サイクルを変更([関連ドキュメント](#plans) を参照) - **Edit** をクリックして支払い方法を変更([関連ドキュメント](/cloud/account/account-billing) を参照) :::note このページで支払い方法を直接選択すると、プロジェクト専用のカードを紐づけられます。プロジェクトごとに別のカードでサブスクリプション管理が可能です。 ::: :::tip *Billing & Usage* タブの Usage セクションでは、現在の月次利用量と契約上限を比較できます。右上の矢印を使うと、任意の月の利用状況を確認できます。 利用状況から別プランの方が適していると判断された場合は、 *Billing & Usage* タブに切り替え候補プランの案内が表示されます。 ::: ### Plans {#plans} *Plans* タブでは、利用可能な Strapi Cloud プラン一覧を確認でき、現在のプランや請求サイクルを変更できます。 :::info 現在のプランが *legacy* と表示されている場合、新しいプランへサイドグレードできます([ダウングレード](#downgrading-to-another-plan) 参照)。サイドグレード後は、以前のプランには戻れません。 ::: #### 別プランへアップグレードする {#upgrading-to-another-plan} プランのアップグレードは即時反映され、プロジェクト設定から管理できます。 現在プランを上位プランにアップグレードする手順: 1. プロジェクト設定の *Plans* タブで、月額/年額を選び、アップグレード先プランの **Upgrade** をクリックします。 2. 表示された画面で支払い詳細とアップグレード条件を確認します。 a. (任意)**Edit** をクリックして別の支払い方法を選択します。 b. (任意)**I have a discount code** をクリックし、割引コードを入力して **Apply** をクリックします。 3. **Upgrade to [plan name]** をクリックして確定します。プロジェクトは自動で再デプロイされます。 #### 別プランへダウングレードする {#downgrading-to-another-plan} プランのダウングレードは、プロジェクト設定で管理できます。ただし即時反映ではなく、現在の請求期間終了まで現プランが継続します。 :::caution ダウングレード前に、必ず Strapi Cloud プロジェクトの利用状況を確認してください。現在の利用量が下位プラン上限を超える場合、超過料金が発生する可能性があります。機能制限も発生し、たとえば Essential へ下げるとプロジェクトのバックアップは利用できなくなります。詳細は [課金と利用状況](/cloud/getting-started/usage-billing) を参照してください。 追加の有料環境がある場合はダウングレードできません。まず、プラン基本料金に含まれない追加環境をすべて削除する必要があります([環境のリセットと削除](#resetting--deleting-environment) を参照)。Scale から Pro へ下げる場合、追加で含まれていた環境はダウングレード反映時に自動削除されます。 GitHub Organization のリポジトリが接続されている場合、Free プランへはダウングレードできません。先に [Connected Git repository](#modifying-git-repository--branch) 設定で個人リポジトリへ切り替えてください。 ::: 現在プランを下位プランにダウングレードする手順: 1. プロジェクト設定の *Plans* タブで月額/年額を選び、ダウングレード先プランの **Downgrade** をクリックします。 2. 表示された画面でダウングレード条件を確認します。 3. **Downgrade** をクリックして確定します。プロジェクトは自動で再デプロイされます。 :::tip ダウングレードは現在の請求期間終了時に反映されます。反映待ちの間は予約したダウングレードをキャンセルし、現プランを継続できます。 ::: #### 請求サイクルを変更する プロジェクトの請求サイクルは、月額と年額をいつでも切り替えられます。プランとアドオンは請求サイクルに応じて月額/年額課金されますが、超過料金は常に月額課金です。 請求サイクルを変更する手順: 1. プロジェクト設定の *Plans* タブで、プラン一覧上部のトグルから月額/年額を切り替えます。 2. 現在プランの **Switch to [monthly/yearly] billing** をクリックします。 3. 表示された画面で請求サイクル変更条件を確認します。 4. **Confirm switch** をクリックして確定します。 :::note 年額から月額へ切り替える場合、次回更新日までは年額サイクルが継続します。反映待ちの間は予約した変更をキャンセル可能です。月額から年額への切り替えは即時反映されます。 ::: ### Invoices {#invoices} *Invoices* タブでは、Strapi Cloud プロジェクトの請求書一覧とステータスを確認できます。Free プランでは請求書は発行されません。 :::strapi 請求書はプロフィール設定からも確認できます。 *Profile > Invoices* タブでは、全プロジェクトの請求書一覧を確認できます。詳細は [専用ドキュメント](/cloud/account/account-billing#account-invoices) を参照してください。 ::: ## 環境ごとの設定 環境設定では、まずドロップダウンで設定対象の環境を選択します。選択環境に応じて 3〜4 個のタブが表示されます。 - [*Configuration*](#configuration), - [*Backups*](#backups)(Production 環境のみ利用可能), - [*Domains*](#domains), - and [*Variables*](#variables). ### Configuration {#configuration} *Configuration* タブでは次を確認・更新できます。 - *Basic information*: - 環境名(作成時に決まり、後から変更不可) - Node バージョン([Node バージョンを変更する](#modifying-node-version) を参照) - デバッグやサポートで役立つアプリ内部名 - *Connected branch*: 環境で使う GitHub ブランチを変更([Git ブランチを編集する](#editing-git-branch) を参照)。`deploy on push` の有効/無効も切り替え可能 - *Environment data*: 同一プロジェクト内の別環境からデータ移行([環境間でデータを移行する](#transferring-data-between-environments) を参照) - *Danger zone*: 環境のリセットまたは恒久削除([環境をリセット/削除する](#resetting--deleting-environment) を参照) #### Node バージョンを変更する {#modifying-node-version} 環境の Node バージョンは、プロジェクト作成時に高度な設定で選んだ値を基準にします([プロジェクト作成](/cloud/getting-started/deployment) を参照)。作成後も各環境で別の Node バージョンへ切り替え可能です。 1. *Configuration* タブの *Basic information* セクションで、*Node version* の編集 ボタンをクリックします。 2. ダイアログの *Node version* ドロップダウンで使用バージョンを選びます。 3. **Save** をクリックします。すぐ反映する場合は **Save & deploy** をクリックします。 :::tip デプロイ前に、Strapi プロジェクトで設定した Node バージョンと、プロジェクトダッシュボードに表示される Node バージョンが一致していることを確認してください。 ::: #### Git ブランチを編集する {#editing-git-branch} 1. *Edit branch* ダイアログで設定を編集します。ブランチはプロジェクト設定側から全環境一括でも編集できます([General](#general) を参照)。 | 設定項目 | 手順 | | --- | --- | | Selected branch | (必須)ドロップダウンからブランチを選択します。 | | Base directory | 入力欄にベースディレクトリのパスを入力します。 | | Deploy the project on every commit pushed to this branch | チェックすると、対象ブランチへのコミットごとに自動デプロイします。無効化する場合はチェックを外します。 | 2. **Save & deploy** をクリックして反映します。 #### Transferring data between environments {#transferring-data-between-environments} データ移行機能を使うと、同一 Strapi Cloud プロジェクト内で、ある環境から別環境へ CMS コンテンツ全体(データベースとアセット)を移行できます。最新の本番データで検証したい場合や、本番反映前にステージング環境で準備する場合に有用です。 現在、環境間データ移行には次の制限があります。 - 移行先にできるのはセカンダリ環境のみ(Production 環境は不可) - 移行の開始と進行中移行の管理はプロジェクトオーナーのみ可能 - 一時停止中プロジェクトでは移行を開始不可 :::caution Data transfers are destructive 環境へデータ移行すると、移行先環境の既存データとアセットはすべて恒久的に上書きされます。移行元環境データは影響を受けず、移行中も CMS へアクセスできます。環境設定(変数、ドメインなど)は移行対象外です。 ::: セカンダリ環境へデータ移行する手順: 1. 移行元と移行先の [環境](#environments) を作成し、デプロイします。 2. *Configuration* タブの *Environment data* セクションで **Import data** をクリックします。 3. モーダルで移行元環境をドロップダウンから選択します。移行元に選べるのは、作成とデプロイが完了した環境のみです。 4. **Import data** をクリックして進み、表示手順に従って移行を確定します。 5. 開始後は環境ダッシュボードへ遷移し、進行状況を確認できます。移行完了後、ダッシュボードが更新され、進行中/過去のデプロイが表示されます。 :::note 移行中は移行先環境の CMS にアクセスできません。進行中移行はキャンセルできますが、移行先環境は空の状態になります。移行中にエラーが発生した場合は、再試行またはキャンセルを選べます。 ::: #### 環境をリセット/削除する {#resetting--deleting-environment} Strapi Cloud プロジェクトの追加環境はリセットまたは削除できますが、操作は恒久的で元に戻せません。既定の Production 環境はリセットも削除もできません。 ##### 環境をリセットする 環境をリセットすると、その環境のデータはすべて削除され、変数は既定値に戻ります。手順: 1. *Configuration* タブの *Danger zone* で **Reset environment** をクリックします。 2. 開いたダイアログで **Continue** をクリックし、環境リセットを確定します。 3. リセット用の項目を入力します。 | 設定項目 | 手順 | | --- | --- | | Environment name | (必須)環境名を入力します。 | | Git branch | (必須)ドロップダウンからブランチを選択します。 | | Base directory | 入力欄にベースディレクトリのパスを入力します。 | | Import variables | チェックすると既存環境から変数名のみ取り込みます。値は取り込まれず空欄のままです。 | | Auto-deploy | チェックすると、対象ブランチへのコミットごとに自動デプロイします。無効化する場合はチェックを外します。 | 4. **Reset** をクリックします。 ##### 環境を削除する 1. *Configuration* タブの *Danger zone* で **Delete environment** をクリックします。 2. 入力欄に *Environment name* を入力します。 3. **Delete environment** をクリックして削除を確定します。 ### Backups {#backups} *Backups* タブでは、最新バックアップの日時とステータスを確認できます。Strapi Cloud プロジェクトのデータベースは自動バックアップされます(Pro は週次、Scale は日次)。バックアップ保持期間は 28 日です。加えて、手動バックアップを 1 件作成できます。 :::note Notes - Free または Essential プランではバックアップ機能を利用できません。自動バックアップや手動バックアップを使うには Pro または Scale へアップグレードしてください。 - バックアップ対象は既定の Production 環境データベースのみです。アップロード済みアセットやセカンダリ環境データベースは含まれません。 - 手動バックアップ機能は、プロジェクトの初回デプロイ成功後しばらくして利用可能になります。 ::: :::tip 2023 年 10 月のバックアップ機能リリース前に作成されたプロジェクトでは、次回デプロイ時に初回バックアップが自動実行されます。 ::: #### 手動バックアップを作成する {#creating-a-manual-backup} 手動バックアップを作成するには、 *Backups* セクションで **Create backup** をクリックします。 手動バックアップはすぐ開始され、完了まで復元やほかのバックアップ作成はできません。 :::caution 新しい手動バックアップを作成すると、既存の手動バックアップは削除されます。手動バックアップは常に 1 件のみ保持できます。 ::: #### バックアップを復元する プロジェクトのバックアップを復元する手順: 1. *Backups* セクションで **Restore backup** をクリックします。 2. ダイアログの *Choose backup* ドロップダウンで、利用可能なバックアップ(自動または手動)を選択します。 3. ダイアログの **Restore** をクリックします。復元が完了すると、選択バックアップ時点の状態に戻ります。 *Backups* タブで復元時刻と復元元バックアップを確認できます。 4. 最終復元完了時刻が表示され、最終復元タイミングを追跡できます。 #### バックアップをダウンロードする プロジェクトのバックアップをダウンロードする手順: 1. *Backups* セクションで **Download backup** をクリックします。 2. ダイアログの *Choose backup* ドロップダウンで、利用可能なバックアップ(自動または手動)を選択します。 3. ダイアログの **Download** をクリックし、選択したバックアップを `.sql` 形式でダウンロードします。 :::note バックアップファイルに含まれるのは既定 Production 環境のデータベースのみです。アセットや他環境のデータベースは含まれません。 ::: ### Domains {#domains} *Domains* タブでは、ドメイン管理と新規接続ができます。 *Domains* タブには、Strapi Cloud プロジェクトで使用中のドメイン一覧が表示されます。各ドメインについて次を実行できます。 - 現在ステータスを確認 - Active: ドメイン確認済みで利用中 - Pending: ドメイン移管処理中(DNS 反映待ち) - Failed: エラーによりドメイン変更要求が失敗 - 編集ボタンでドメイン設定を開く - 削除ボタンでドメインを削除する #### カスタムドメインを接続する {#connecting-a-custom-domain} 既定ドメイン名は、ランダムな 2 語とハッシュ値で構成されます。任意のカスタムドメインに置き換え可能です。 :::note カスタムドメインは Free プランでは利用できません。Free へダウングレードすると、アプリケーションドメインは既定ドメインへ戻ります。 ::: 1. **Connect new domain** をクリックします。 2. 開いた画面で次の項目を入力します。 | 設定項目 | 手順 | | --- | --- | | Domain name | 新しいドメイン名を入力します(例: *custom-domain-name.com*)。 | | Hostname | ホスト名(エンドユーザーがブラウザ入力または API 呼び出しで利用するアドレス)を入力します。 | | Target | ターゲット(Hostname 指定時に実際に転送されるアドレス)を入力します。 | | Set as default domain | チェックすると、新しいドメインを既定ドメインに設定します。 | 3. **Save & deploy** をクリックして反映します。 :::tip カスタムドメイン設定を完了するには、ドメインレジストラまたはホスティング側設定で、Target 値(例: `proud-unicorn-123456af.strapiapp.com`)を DNS レコードに CNAME として追加してください。 ::: :::info カスタムドメインとアセット URL カスタムドメインを使っても、アップロード済みアセット URL には適用されません。アセットは Strapi Cloud のプロジェクトベース URL を維持します。 たとえばカスタムドメインが `https://my-custom-domain.com` で、Strapi Cloud プロジェクト名が `my-strapi-cloud-instance` の場合、API は `https://my-strapi-cloud-instance.media.strapiapp.com/example.png` のような URL を返します。 REST/GraphQL のメディアライブラリクエリは、常に Strapi Cloud のプロジェクトメディアドメインを返します。セルフホスト環境から移行した場合、メディア URL は独自ドメインや CDN と一致しなくなります。API が返す絶対 URL をそのまま利用するか、フロントエンド側で Strapi Cloud メディアドメインを許可してください(詳細は [Cloud Fundamentals](/cloud/cloud-fundamentals) を参照)。 ::: ### Variables Environment variables (more information in the [CMS Documentation](/cms/configurations/environment)) are used to configure the environment of your Strapi application, such as the database connection. In the *Variables* tab are listed both the default and custom environment variables for your Strapi Cloud project. Each variable is composed of a *Name* and a *Value*. #### 環境変数を管理する 既定/カスタムの各環境変数にカーソルを合わせると、次の操作が表示されます。 - **Show value**: `*` を実際の変数値表示に切り替えます。 - **Copy to clipboard**: 変数値をコピーします。 - **Actions**: Edit と Delete を表示します。 - 既定変数の編集時は *Name* を変更できず、*Value* は Generate value による自動生成のみ可能です。**Save**(または即時反映する **Save & deploy**)を押してください。 - カスタム変数の編集時は *Name* / *Value* の両方を直接入力または Generate value で変更できます。**Save**(または即時反映する **Save & deploy**)を押してください。 - 変数削除時は確認が表示されます。**Save**(または即時反映する **Save & deploy**)で確定します。 :::tip 検索バーを使うと、一覧から目的の環境変数をすばやく見つけられます。 ::: #### カスタム環境変数を作成する Strapi Cloud プロジェクトにはカスタム環境変数を作成できます。環境変数を作成・編集した後は、必ずプロジェクトを再デプロイしてください。 1. *Custom environment variables* セクションで **Add variable** をクリックします。 2. 新しい環境変数の *Name* と *Value* を入力します。 アイコンで名前と値を自動生成することもできます。 3. (任意)**Add another** をクリックすると、続けて複数のカスタム環境変数を作成できます。 4. **Save** をクリックして作成を確定します。すぐ反映する場合は **Save & deploy** をクリックします。 # Admin panel customization Source: https://docs.strapi.io/cms/admin-panel-customization # Admin panel customization The **front-end part of Strapi** is called the admin panel. The admin panel presents a graphical user interface to help you structure and manage the content that will be accessible through the Content API. To get an overview of the admin panel, please refer to the [Getting Started > Admin panel](/cms/features/admin-panel) page. From a developer point of view, Strapi's admin panel is a React-based single-page application that encapsulates all the features and installed plugins of a Strapi application. Admin panel customization is done by tweaking the code of the `src/admin/app` file or other files included in the `src/admin` folder (see [project structure](/cms/project-structure)). By doing so, you can: - Customize some parts of the admin panel to better reflect your brand identity (logos, favicon) or your language, - Replace some other parts of the admin panel, such as the Rich text editor and the bundler, - Extend the theme or the admin panel to add new features or customize the existing user interface. :::strapi Plugins and Admin Panel API In addition to supported customizations detailed in this section, you can go further and create plugins that tap into the [Admin Panel API](/cms/plugins-development/admin-panel-api). ::: ## General considerations :::prerequisites Before updating code to customize the admin panel: - Rename the default `app.example.tsx|js` file into `app.ts|js`. - Create a new `extensions` folder in `/src/admin/`. - If you want to see your changes applied live while developing, ensure the admin panel server is running (it's usually done with the `yarn develop` or `npm run develop` command if you have not changed the default [host, port, and path](/cms/configurations/admin-panel#admin-panel-server) of the admin panel). ::: Most basic admin panel customizations will be done in the `/src/admin/app` file, which includes a `config` object. Any file used by the `config` object (e.g., a custom logo) should be placed in a `/src/admin/extensions/` folder and imported inside `/src/admin/app.js`. This will replace the folder's content located at `./build`. Visit ## Basic example The following is an example of a basic customization of the admin panel: :::strapi Detailed examples in the codebase * You can see the full translation keys, for instance to change the welcome message, [on GitHub](https://github.com/strapi/strapi/blob/develop/packages/core/admin/admin/src/translations). * Light and dark colors are also found [on GitHub](https://github.com/strapi/design-system/tree/main/packages/design-system/src/themes). ::: # Admin panel bundlers Source: https://docs.strapi.io/cms/admin-panel-customization/bundlers # Admin panel bundlers Strapi's [admin panel](/cms/admin-panel-customization) is a React-based single-page application that encapsulates all the features and installed plugins of a Strapi application. 2 different bundlers can be used with your Strapi 5 application, [Vite](#vite) (the default one) and [webpack](#webpack). Both bundlers can be configured to suit your needs. :::info For simplification, the following documentation mentions the `strapi develop` command, but in practice you will probably use its alias by running either `yarn develop` or `npm run develop` depending on your package manager of choice. ::: ## Vite In Strapi 5, ## Webpack In Strapi 5, the default bundler is Vite. To use # Admin panel extension Source: https://docs.strapi.io/cms/admin-panel-customization/extension # Admin panel extension Strapi's [admin panel](/cms/admin-panel-customization) is a React-based single-page application that encapsulates all the features and installed plugins of a Strapi application. If the [customization options](/cms/admin-panel-customization#available-customizations) provided by Strapi are not enough for your use case, you will need to extend Strapi's admin panel. Extending Strapi's admin panel means leveraging its React foundation to adapt and enhance the interface and features according to the specific needs of your project, which might imply creating new components or adding new types of fields. There are 2 use cases where you might want to extend the admin panel: | Approach | Scope | Entry point | Docs | |---|---|---|---| | Local extension | One Strapi project | `/src/admin/app.(js\|ts)` and `/src/admin/extensions/` | [Admin panel customization](/cms/admin-panel-customization) | | Plugin extension | Any project that installs your plugin | `[plugin-name]/admin/src/index.(js\|ts)` | [Admin Panel API overview](/cms/plugins-development/admin-panel-api) | - As a Strapi plugin developer, you want to develop a Strapi plugin that extends the admin panel **everytime it's installed in any Strapi application**. 👉 This can be done by taking advantage of the [Admin Panel API for plugins](/cms/plugins-development/admin-panel-api), which lets you add navigation links and settings sections, inject React components into predefined areas, manage state with Redux, extend the Content Manager's Edit and List views, and more. - As a Strapi developer, you want to develop a unique solution for a Strapi user who only needs to extend a specific instance of a Strapi application. 👉 This can be done by directly updating the `/src/admin/app` file, which can import any file located in `/src/admin/extensions`. ## When to consider a plugin instead Starting with a direct customization in `/src/admin/app` is the right default for project-specific needs. Consider moving to a plugin-based approach when one or more of these signals appear: - You are duplicating the same admin customization across several Strapi projects. - You want to version and distribute the extension — either internally or through the . - You need stronger automated testing independent from a single project codebase. - Multiple teams need shared ownership and release management for the same extension. For a full introduction to plugin development, see [Developing Strapi plugins](/cms/plugins-development/developing-plugins). :::strapi Additional resources * If you're looking for ways of replacing the default Rich text editor, refer to the [corresponding page](/cms/admin-panel-customization/wysiwyg-editor). * To understand how plugins integrate with the Strapi admin panel, start with the [Admin Panel API overview](/cms/plugins-development/admin-panel-api). ::: # Favicon Source: https://docs.strapi.io/cms/admin-panel-customization/favicon # Favicon Strapi's [admin panel](/cms/admin-panel-customization) displays its branding on various places, including the [logo](/cms/admin-panel-customization/logos) and the favicon. Replacing these images allows you to match the interface and application to your identity. There are 2 approaches to replacing the favicon: * Replace the `favicon.png` file at the root of a Strapi project * Edit the [`strapi::favicon` middleware configuration](/cms/configurations/middlewares#favicon) with the following code: ```js title="/config/middlewares.js" // … { name: 'strapi::favicon', config: { path: 'my-custom-favicon.png', }, }, // … ``` Once done, rebuild, launch and revisit your Strapi app by running `yarn build && yarn develop` in the terminal. :::caution Make sure that the cached favicon is cleared. It can be cached in your web browser and also with your domain management tool like Cloudflare's CDN. ::: # Homepage customization Source: https://docs.strapi.io/cms/admin-panel-customization/homepage # Homepage customization The :::note The API requires Strapi 5.13+ The `app.widgets.register` API only works with Strapi 5.13 and above. Trying to call the API with older versions of Strapi will crash the admin panel. Plugin developers who want to register widgets should either: - set `^5.13.0` as their `@strapi/strapi` peerDependency in their plugin `package.json`. This peer dependency powers the Marketplace's compatibility check. - or check if the API exists before calling it: ```js if ('widgets' in app) { // proceed with the registration } ``` The peerDependency approach is recommended if the whole purpose of the plugin is to register widgets. The second approach makes more sense if a plugin wants to add a widget but most of its functionality is elsewhere. ::: #### Widget API reference The `app.widgets.register()` method can take either a single widget configuration object or an array of configuration objects. Each widget configuration object can accept the following properties: | Property | Type | Description | Required | |-------------|------------------------|-------------------------------------------------------|----------| | `icon` | `React.ComponentType` | Icon component to display beside the widget title | Yes | | `title` | `MessageDescriptor` | Title for the widget with translation support | Yes | | `component` | `() => Promise :::tip For simplicity, the example below uses data fetching directly inside a useEffect hook. While this works for demonstration purposes, it may not reflect best practices in production. For more robust solutions, consider alternative approaches recommended in the [React documentation](https://react.dev/learn/build-a-react-app-from-scratch#data-fetching). If you're looking to integrate a data fetching library, we recommend using [TanStackQuery](https://tanstack.com/query/v3/). ::: **Data management**: ![Rendering and Data management](/img/assets/homepage-customization/rendering-data-management.png) The green box above represents the area where the user’s React component (from `widget.component` in the [API](#widget-api-reference)) is rendered. You can render whatever you like inside of this box. Everything outside that box is, however, rendered by Strapi. This ensures overall design consistency within the admin panel. The `icon`, `title`, and `link` (optional) properties provided in the API are used to display the widget. #### Widget helper components reference Strapi provides several helper components to maintain a consistent user experience across widgets: | Component | Description | Usage | |------------------|-----------------------------------------------------|--------------------------------------| | `Widget.Loading` | Displays a loading spinner and message | When data is being fetched | | `Widget.Error` | Displays an error state | When an error occurs | | `Widget.NoData` | Displays when no data is available | When the widget has no data to show | | `Widget.NoPermissions` | Displays when user lacks required permissions | When the user cannot access the widget | These components help maintain a consistent look and feel across different widgets. You could render these components without children to get the default wording: ` ))} ); }; ``` The following file defines a custom controller that counts all content-types: ```js title="src/plugins/content-metrics/server/src/controllers/metrics.js" 'use strict'; module.exports = ({ strapi }) => ({ async getContentCounts(ctx) { try { // Get all content types const contentTypes = Object.keys(strapi.contentTypes) .filter(uid => uid.startsWith('api::')) .reduce((acc, uid) => { const contentType = strapi.contentTypes[uid]; acc[contentType.info.displayName || uid] = 0; return acc; }, {}); // Count entities for each content type for (const [name, _] of Object.entries(contentTypes)) { const uid = Object.keys(strapi.contentTypes) .find(key => strapi.contentTypes[key].info.displayName === name || key === name ); if (uid) { // Using the count() method from the Document Service API const count = await strapi.documents(uid).count(); contentTypes[name] = count; } } ctx.body = contentTypes; } catch (err) { ctx.throw(500, err); } } }); ``` The following file ensures that the metrics controller is reachable at a custom `/count` route: ```js title="src/plugins/content-metrics/server/src/routes/index.js" 'content-api': { type: 'content-api', routes: [ { method: 'GET', path: '/count', handler: 'metrics.getContentCounts', config: { policies: [], }, }, ], }, }; ``` ))} ); }; ``` The following file defines a custom controller that counts all content-types: ```js title="src/plugins/content-metrics/server/src/controllers/metrics.js" 'use strict'; module.exports = ({ strapi }) => ({ async getContentCounts(ctx) { try { // Get all content types const contentTypes = Object.keys(strapi.contentTypes) .filter(uid => uid.startsWith('api::')) .reduce((acc, uid) => { const contentType = strapi.contentTypes[uid]; acc[contentType.info.displayName || uid] = 0; return acc; }, {}); // Count entities for each content type using Document Service for (const [name, _] of Object.entries(contentTypes)) { const uid = Object.keys(strapi.contentTypes) .find(key => strapi.contentTypes[key].info.displayName === name || key === name ); if (uid) { // Using the count() method from Document Service instead of strapi.db.query const count = await strapi.documents(uid).count(); contentTypes[name] = count; } } ctx.body = contentTypes; } catch (err) { ctx.throw(500, err); } } }); ``` The following file ensures that the metrics controller is reachable at a custom `/count` route: ```js title="src/plugins/content-metrics/server/src/routes/index.js" 'content-api': { type: 'content-api', routes: [ { method: 'GET', path: '/count', handler: 'metrics.getContentCounts', config: { policies: [], }, }, ], }, }; ``` # Locales & translations Source: https://docs.strapi.io/cms/admin-panel-customization/locales-translations # Locales & translations The Strapi [admin panel](/cms/admin-panel-customization) ships with English strings and supports adding other locales so your editorial team can work in their preferred language. Locales determine which languages appear in the interface, while translations provide the text displayed for each key in a locale. This guide targets project maintainers customizing the admin experience from the application codebase. All examples modify the configuration exported from `/src/admin/app` file, which Strapi loads when the admin panel builds. You'll learn how to declare additional locales and how to extend Strapi or plugin translations when a locale is missing strings. ## Defining locales To update the list of available locales in the admin panel, set the `config.locales` array in `src/admin/app` file: :::note Notes - The `en` locale cannot be removed from the build as it is both the fallback (i.e. if a translation is not found in a locale, the `en` will be used) and the default locale (i.e. used when a user opens the administration panel for the first time). - The full list of available locales is accessible on A plugin's key/value pairs are declared independently in the plugin's files at `/admin/src/translations/[language-name].json`. These key/value pairs can similarly be extended in the `config.translations` key by prefixing the key with the plugin's name (i.e. `[plugin name].[key]: 'value'`) as in the following example: If you need to ship additional translation JSON files—for example to organize large overrides or to support a locale not bundled with Strapi—place them in the `/src/admin/extensions/translations` folder and ensure the locale code is listed in `config.locales`. :::tip Rebuild the admin Translation changes apply when the admin rebuilds. If updates don’t show, re-run your dev server or rebuild the admin to refresh bundled translations. ::: # Logos Source: https://docs.strapi.io/cms/admin-panel-customization/logos # Logos Strapi's [admin panel](/cms/admin-panel-customization) displays its branding on both the login screen and in the main navigation. Replacing these images allows you to match the interface to your identity. The present page shows how to override the two logo files via the admin panel configuration. If you prefer uploading them directly in the UI, see [Customizing the logo](/cms/features/admin-panel#customizing-the-logo). The Strapi admin panel displays a logo in 2 different locations, represented by 2 different keys in the admin panel configuration: | Location in the UI | Configuration key to update | | ---------------------- | --------------------------- | | On the login page | `config.auth.logo` | | In the main navigation | `config.menu.logo` | :::note Logos uploaded via the admin panel supersede any logo set through the configuration files. ::: ### Logos location in the admin panel The logo handled by `config.auth.logo` logo is only shown on the login screen: ![Location of the auth logo](/img/assets/development/config-auth-logo.png) The logo handled by `config.menu.logo` logo is located in the main navigation at the top left corner of the admin panel: ![Location of Menu logo](/img/assets/development/config-menu-logo.png) ### Updating logos To update the logos, put image files in the `/src/admin/extensions` folder, import these files in `src/admin/app` and update the corresponding keys as in the following example: :::note There is no size limit for image files set through the configuration files. ::: # Theme extension Source: https://docs.strapi.io/cms/admin-panel-customization/theme-extension # Theme extension Strapi's [admin panel](/cms/admin-panel-customization) can be displayed either in light or dark mode (see [profile setup](/cms/getting-started/setting-up-admin-panel#setting-up-your-administrator-profile)), and both can be extended through custom theme settings. To extend the theme, use either: - the `config.theme.light` key for the Light mode - the `config.theme.dark` key for the Dark mode :::strapi Strapi Design System The default # Customizing the rich text editor Source: https://docs.strapi.io/cms/admin-panel-customization/wysiwyg-editor # Change the default rich text editor Strapi's [admin panel](/cms/admin-panel-customization) comes with a built-in rich text editor. To change the default editor, several options are at your disposal: - You can install a third-party plugin, such as one for CKEditor, by visiting . - You can create your own plugin to create and register a fully custom WYSIWYG field (see [custom fields documentation](/cms/features/custom-fields)). :::tip Next steps When evaluating editors, start with a plugin from the Marketplace for a quick trial, then consider a custom field if you need deeper integration (schema, validation, or custom toolbar behavior). ::: # Strapi Client Source: https://docs.strapi.io/cms/api/client # Strapi Client Strapi Client ライブラリはバックエンドとのやり取りを簡素化し、コンテンツの取得・作成・更新・削除が行えます。このガイドではセットアップ、認証の設定、主な機能の使い方を説明します。 ## はじめに :::prerequisites - Strapi プロジェクトが作成済みで動いていること。まだの場合は [クイックスタート](/cms/quick-start) に従って作成してください。 - Strapi インスタンスの Content API の URL を把握していること(例: `http://localhost:1337/api`)。 ::: ### インストール Strapi Client をプロジェクトで使うには、好みのパッケージマネージャーで依存関係に追加します。 ### 基本的な設定 バックエンドと通信するには、Strapi Client を初期化し、API のベース URL を設定します。 `baseURL` にはプロトコル(`http` または `https`)を含める必要があります。無効な URL の場合は `StrapiInitializationError` がスローされます。 ### 認証 Strapi Client は複数の認証方式に対応し、バックエンドの保護されたリソースにアクセスできます。 Strapi で [API トークン](/cms/features/api-tokens) を使っている場合は、次のように設定します。 ```js const client = strapi({ baseURL: 'http://localhost:1337/api', auth: 'your-api-token-here', }); ``` リクエストに必要な認証情報が自動で付きます。 トークンが無効または欠落している場合、初期化時に `StrapiValidationError` がスローされます。 ## API リファレンス Strapi Client がバックエンドとやり取りするための主なプロパティとメソッドは次のとおりです。 | パラメータ | 説明 | | ----------| -------------------------------------------------------------------------------------------- | | `baseURL` | Strapi バックエンドの API ベース URL。 | | `fetch()` | ネイティブの fetch API に近い、汎用 API リクエスト用のメソッド。 | | `collection()` | コレクションタイプのリソースを扱います(ブログ記事や商品など)。 | | `single()` | シングルタイプのリソースを扱います(ホームページ設定や全体設定など)。 | | `files()` | Strapi メディアライブラリへのファイルのアップロード・取得・管理を行います。 | ### 汎用の fetch Strapi Client から、初期化時に指定したベース URL を基準にした直接リクエスト用に JavaScript の `fetch` に相当する手段が使えます。 ```js const result = await client.fetch('articles', { method: 'GET' }); ``` ### コレクションタイプの操作 Strapi のコレクションタイプは複数エントリを持つエンティティです(多数の投稿があるブログなど)。`collection()` で操作し、次のメソッドが使えます。 | パラメータ | 説明 | | ----------| -------------------------------------------------------------------------------------------- | | `find(queryParams?)` | フィルター・ソート・ページネーションなどの任意パラメータ付きで複数ドキュメントを取得します。 | | `findOne(documentID, queryParams?)` | 一意の ID で 1 件のドキュメントを取得します。 | | `create(data, queryParams?)` | コレクションに新しいドキュメントを作成します。 | | `update(documentID, data, queryParams?)` | 既存のドキュメントを更新します。 | | `delete(documentID, queryParams?)` | 既存のドキュメントを削除します。 | **使用例:** ### シングルタイプの操作 シングルタイプはアプリ内で 1 つだけ存在するコンテンツ(ホームページ設定やサイト全体の設定など)です。`single()` で操作し、次のメソッドが使えます。 | パラメータ | 説明 | | ----------| -------------------------------------------------------------------------------------------- | | `find(queryParams?)` | ドキュメントを取得します。 | | `update(documentID, data, queryParams?)` | ドキュメントを更新します。 | | `delete(queryParams?)` | ドキュメントを削除します。 | **使用例:** ```js const homepage = client.single('homepage'); // 既定のホームページコンテンツを取得 const defaultHomepage = await homepage.find(); // ホームページのスペイン語版を取得 const spanishHomepage = await homepage.find({ locale: 'es' }); // ホームページの下書きを更新 const updatedHomepage = await homepage.update( { title: 'Updated Homepage Title' }, { status: 'draft' } ); // ホームページのコンテンツを削除 await homepage.delete(); ``` ### ファイルの操作 Strapi Client は [メディアライブラリ](/cms/features/media-library) に `files` 経由でアクセスします。REST API を直接使わずにファイルのメタデータを取得・管理できます。 ファイル操作用のメソッドは次のとおりです。表のメソッド名をクリックすると、詳細と例のある見出しへ移動します。 | メソッド | 説明 | |--------|-------------| | [`find(params?)`](#find) | 任意のクエリパラメータに基づき、ファイルメタデータの一覧を取得します | | [`findOne(fileId)`](#findone) | ID で 1 件のファイルメタデータを取得します | | [`update(fileId, fileInfo)`](#update) | 既存ファイルのメタデータを更新します | | [`upload(file, options)`](#upload) | ファイル(Blob または Buffer)をアップロードします。メタデータ用の任意の `options` を付けられます | | [`delete(fileId)`](#delete) | ID でファイルを削除します | #### `find` {#find} `strapi.client.files.find()` は、任意のクエリパラメータに基づきファイルメタデータの一覧を返します。 次のように使います。 ```js // クライアントを初期化 const client = strapi({ baseURL: 'http://localhost:1337/api', auth: 'your-api-token', }); // すべてのファイルメタデータを取得 const allFiles = await client.files.find(); console.log(allFiles); // フィルターとソート付きでファイルメタデータを取得 const imageFiles = await client.files.find({ filters: { mime: { $contains: 'image' }, // 画像のみ name: { $contains: 'avatar' }, // 名前に avatar を含むもののみ }, sort: ['name:asc'], // 名前の昇順 }); ``` #### `findOne` {#findone} `strapi.client.files.findOne()` は、ID で 1 件のファイルメタデータを返します。 次のように使います。 ```js // クライアントを初期化 const client = strapi({ baseURL: 'http://localhost:1337/api', auth: 'your-api-token', }); // ID でファイルメタデータを取得 const file = await client.files.findOne(1); console.log(file.name); console.log(file.url); console.log(file.mime); // ファイルの MIME タイプ ``` #### `update` {#update} `strapi.client.files.update()` は既存ファイルのメタデータを更新します。引数は `fileId` と、名前・代替テキスト・キャプションなどを含むオプションオブジェクトです。 次のように使います。 ```js // クライアントを初期化 const client = strapi({ baseURL: 'http://localhost:1337/api', auth: 'your-api-token', }); // ファイルメタデータを更新 const updatedFile = await client.files.update(1, { name: 'New file name', alternativeText: 'Descriptive alt text for accessibility', caption: 'A caption for the file', }); ``` #### `upload` ##### レスポンスの形 `strapi.client.files.upload()` は、次のようなフィールドを持つファイルオブジェクトの配列を返します。 ```json { "id": 1, "name": "image.png", "alternativeText": "Uploaded from Node.js Buffer", "caption": "Example upload", "mime": "image/png", "url": "/uploads/image.png", "size": 12345, "createdAt": "2025-07-23T12:34:56.789Z", "updatedAt": "2025-07-23T12:34:56.789Z" } ``` :::note レスポンスの追加フィールド アップロードのレスポンスには、ここに示した以外のフィールドも含まれます。利用可能なすべてのフィールドはクライアントの を参照してください。 ::: #### `delete` {#delete} `strapi.client.files.delete()` は ID を指定してファイルを削除します。 次のように使います。 ```js // クライアントを初期化 const client = strapi({ baseURL: 'http://localhost:1337/api', auth: 'your-api-token', }); // ID でファイルを削除 const deletedFile = await client.files.delete(1); console.log('File deleted successfully'); console.log('Deleted file ID:', deletedFile.id); console.log('Deleted file name:', deletedFile.name); ```
## よくあるエラー Strapi Client 経由のクエリで次のエラーが発生することがあります。 | エラー | 説明 | |-------|-------------| | 権限エラー | 認証されたユーザーにファイルのアップロードや管理の権限がない場合、`FileForbiddenError` がスローされます。 | | HTTP エラー | サーバーに到達できない、認証に失敗した、ネットワークに問題がある場合、`HTTPError` がスローされます。 | | パラメータ不足 | `Buffer` をアップロードするとき、`options` に `filename` と `mimetype` の両方が必要です。どちらかが欠けるとエラーになります。 | :::strapi 追加情報 Strapi Client の詳細はパッケージの を参照してください。 ::: # Content API Source: https://docs.strapi.io/cms/api/content-api # コンテンツにアクセスする Strapi API Strapi プロジェクトを作成・設定し、[コンテンツタイプビルダー](/cms/features/content-type-builder) で構造を作り、[コンテンツマネージャー](/cms/features/content-manager) からデータを追加したら、次はそのコンテンツにアクセスする段階です。 フロントエンドアプリからは、Strapi の Content API を通じてコンテンツへアクセスできます。公開される経路は次のとおりです。 - 既定では [REST API](/cms/api/rest) - [GraphQL プラグイン](/cms/plugins/graphql) をインストールしていれば [GraphQL API](/cms/api/graphql) も利用可能 REST API とやり取りするには、[Strapi Client](/cms/api/client) ライブラリも利用できます。 REST と GraphQL は、外部アプリに公開される Content API の上位レイヤーです。Strapi には、さらに 2 つの下位 API があります。 - [Document Service API](/cms/api/document-service) は `strapi.documents` から利用でき、[バックエンドサーバー](/cms/customization) や [プラグイン](/cms/plugins-development/developing-plugins) でデータベース操作するときの推奨 API です。Document Service は **document** # Documents Source: https://docs.strapi.io/cms/api/document
# Documents Strapi 5 における **document** は API 上の概念です。document は、あるコンテンツタイプの 1 エントリーに対する複数のバリエーションをまとめたものです。 シングルタイプは 1 つの固有 document を持ち、コレクションタイプは複数の document を持てます。 管理パネル利用時は document という言葉は通常意識しません。ユーザーは [コンテンツマネージャー](/cms/features/content-manager) で **entry** を作成・編集します。例えば、特定ロケールの entry 一覧を見たり、特定ロケールの下書きを編集したりします。 ただし API レベルでは、entry のフィールド値は次のように複数状態を持ちます。 - 英語ロケールとフランス語ロケールで内容が異なる - 各ロケールで draft 版と published 版が異なる すべてのロケールにおける draft / published の内容をまとめる単位が document です。 [Document Service API](/cms/api/document-service) で document を操作すると、document 全体、またはその一部データを作成・取得・更新・削除できます。 次の図は、[国際化(i18n)](/cms/features/internationalization) や [Draft & Publish](/cms/features/draft-and-publish) の有効化状態ごとに、コンテンツがどのようなバリエーションを持つかを示します。 - コンテンツタイプで i18n が有効な場合、document は複数の **document locale** を持てます。 - コンテンツタイプで Draft & Publish が有効な場合、document は **published** と **draft** の 2 バージョンを持てます。 :::strapi document データを扱う API document またはその中のデータを扱うには次を使います。 - バックエンドサーバー側(コントローラー、サービス、プラグインのバックエンド側など)では [Document Service API](/cms/api/document-service) を使う。 - アプリのフロント側では [REST API](/cms/api/rest) または [GraphQL API](/cms/api/graphql) でデータを取得する。 API 全体の説明は [Content API の導入](/cms/api/content-api) を参照してください。 ::: :::info 既定で返るバージョン バックエンド API とフロント API では、パラメーター未指定時の既定バージョンが異なります。 - Document Service API は既定で draft を返す - REST / GraphQL API は既定で published を返す :::
# Document Service API Source: https://docs.strapi.io/cms/api/document-service # Document Service API Document Service API は **Query Engine API** の上に構築されています。 **ドキュメント** :::strapi Strapi 5 では Entity Service API は非推奨です Document Service API は Strapi v4 で使われていた Entity Service API に代わります( `findOne()` は一致するドキュメントがあればそれを返し、なければ `null` を返します。 ### `findFirst()` {#findfirst} パラメータに一致する最初のドキュメントを取得します。 構文: `findFirst(parameters: Params) => Document` #### パラメータ | パラメータ | 説明 | 既定値 | 型 | |-----------|-------------|---------|------| | [`locale`](/cms/api/document-service/locale#find-first) | 検索対象ドキュメントのロケール。 | 既定ロケール | 文字列または `undefined` | | [`status`](/cms/api/document-service/status#find-first) | _コンテンツタイプで [下書きと公開](/cms/features/draft-and-publish) が有効な場合_: 公開状態。次のいずれか。 | `'draft'` | `'published'` または `'draft'` | | [`filters`](/cms/api/document-service/filters) | 使う [フィルター](/cms/api/document-service/filters) | `null` | Object | | [`fields`](/cms/api/document-service/fields#findfirst) | [返すフィールドを選択](/cms/api/document-service/fields#findfirst) | すべてのフィールド
(既定でポピュレートされないものを除く) | Object | | [`populate`](/cms/api/document-service/populate) | 追加フィールドを [ポピュレート](/cms/api/document-service/populate) する。 | `null` | Object | #### 例
##### 基本的な例 既定では、`findFirst()` は渡した一意識別子(コレクション型の id またはシングル型の id)に対応する最初のドキュメントの、既定ロケールの下書き版を返します。 ##### パラメータで最初の 1 件を取得 `findFirst()` にパラメータを渡すと、条件に一致する最初のドキュメントを返します。 `locale` や `status` を省略すると、既定ロケールの下書き版が返ります。 ### `findMany()` {#findmany} パラメータに一致するドキュメントを取得します。 構文: `findMany(parameters: Params) => Document[]` #### パラメータ | パラメータ | 説明 | 既定値 | 型 | |-----------|-------------|---------|------| | [`locale`](/cms/api/document-service/locale#find-many) | 検索対象ドキュメントのロケール。 | 既定ロケール | 文字列または `undefined` | | [`status`](/cms/api/document-service/status#find-many) | _コンテンツタイプで [下書きと公開](/cms/features/draft-and-publish) が有効な場合_: 公開状態。次のいずれか。 | `'draft'` | `'published'` または `'draft'` | | [`filters`](/cms/api/document-service/filters) | 使う [フィルター](/cms/api/document-service/filters) | `null` | Object | | [`fields`](/cms/api/document-service/fields#findmany) | [返すフィールドを選択](/cms/api/document-service/fields#findmany) | すべてのフィールド
(既定でポピュレートされないものを除く) | Object | | [`populate`](/cms/api/document-service/populate) | 追加フィールドを [ポピュレート](/cms/api/document-service/populate) する。 | `null` | Object | | [`pagination`](/cms/api/document-service/sort-pagination#pagination) | 結果を [ページネーション](/cms/api/document-service/sort-pagination#pagination) する | | [`sort`](/cms/api/document-service/sort-pagination#sort) | 結果を [ソート](/cms/api/document-service/sort-pagination#sort) する | | | #### 例
##### 基本的な例 パラメータを省略すると、`findMany()` は各ドキュメントについて既定ロケールの下書き版を返します。 ##### パラメータで一覧を取得 利用できるフィルターは Document Service API リファレンスの [filters](/cms/api/document-service/filters) を参照してください。 `locale` や `status` を省略すると、既定ロケールの下書き版が返ります。 ### `create()` {#create} 下書きのドキュメントを作成して返します。 作成するコンテンツのフィールドは `data` オブジェクトで渡します。 構文: `create(parameters: Params) => Document` #### パラメータ | パラメータ | 説明 | 既定値 | 型 | |-----------|-------------|---------|------| | [`locale`](/cms/api/document-service/locale#create) | 作成するドキュメントのロケール。 | 既定ロケール | 文字列または `undefined` | | [`fields`](/cms/api/document-service/fields#create) | [返すフィールドを選択](/cms/api/document-service/fields#create) | すべてのフィールド
(既定でポピュレートされないものを除く) | Object | | [`status`](/cms/api/document-service/status#create) | _コンテンツタイプで [下書きと公開](/cms/features/draft-and-publish) が有効な場合_: `'published'` にすると、作成と同時に下書きを自動公開できる | -| `'published'` | | [`populate`](/cms/api/document-service/populate) | 追加フィールドを [ポピュレート](/cms/api/document-service/populate) する。 | `null` | Object | #### 例 `locale` を省略すると、`create()` は既定ロケール向けの下書き版を作成します。 :::tip コンテンツタイプで [下書きと公開](/cms/features/draft-and-publish) が有効なら、作成と同時にドキュメントを公開できます([`status` の説明](/cms/api/document-service/status#create) を参照)。 ::: ### `update()` {#update} ドキュメントのバージョンを更新して返します。 構文: `update(parameters: Params) => Promise ### `delete()` {#delete} 1 件のドキュメント、またはその特定ロケール版を削除します。 構文: `delete(parameters: Params): Promise<{ documentId: ID, entries: Number }>` #### パラメータ | パラメータ | 説明 | 既定値 | 型 | |-----------|-------------|---------|------| | `documentId`| ドキュメント ID | | `ID`| | [`locale`](/cms/api/document-service/locale#delete) | 削除するドキュメントのロケール版。 | `null`
(既定ロケールのみ削除) | 文字列、`'*'`、または `null` | | [`filters`](/cms/api/document-service/filters) | 使う [フィルター](/cms/api/document-service/filters) | `null` | Object | | [`fields`](/cms/api/document-service/fields#delete) | [返すフィールドを選択](/cms/api/document-service/fields#delete) | すべてのフィールド
(既定でポピュレートされないものを除く) | Object | | [`populate`](/cms/api/document-service/populate) | 追加フィールドを [ポピュレート](/cms/api/document-service/populate) する。 | `null` | Object | #### 例 `locale` を省略すると、`delete()` はドキュメントの既定ロケール版だけを削除します。下書きと公開版の両方が削除されます。 ### `publish()` {#publish} ドキュメントの 1 つまたは複数のロケールを公開します。 コンテンツタイプで [下書きと公開](/cms/features/draft-and-publish) が有効なときだけ使えます。 構文: `publish(parameters: Params): Promise<{ documentId: ID, entries: Number }>` #### パラメータ | パラメータ | 説明 | 既定値 | 型 | |-----------|-------------|---------|------| | `documentId`| ドキュメント ID | | `ID`| | [`locale`](/cms/api/document-service/locale#publish) | 公開するドキュメントのロケール。 | 既定ロケールのみ | 文字列、`'*'`, または `null` | | [`filters`](/cms/api/document-service/filters) | 使う [フィルター](/cms/api/document-service/filters) | `null` | Object | | [`fields`](/cms/api/document-service/fields#publish) | [返すフィールドを選択](/cms/api/document-service/fields#publish) | すべてのフィールド
(既定でポピュレートされないものを除く) | Object | | [`populate`](/cms/api/document-service/populate) | 追加フィールドを [ポピュレート](/cms/api/document-service/populate) する。 | `null` | Object | #### 例 `locale` を省略すると、`publish()` はドキュメントの既定ロケール版だけを公開します。 ### `unpublish()` {#unpublish} ドキュメントの 1 つまたはすべてのロケール版の公開を取り下げ、取り下げたロケール版の件数を返します。 コンテンツタイプで [下書きと公開](/cms/features/draft-and-publish) が有効なときだけ使えます。 構文: `unpublish(parameters: Params): Promise<{ documentId: ID, entries: Number }>` #### パラメータ | パラメータ | 説明 | 既定値 | 型 | |-----------|-------------|---------|------| | `documentId`| ドキュメント ID | | `ID`| | [`locale`](/cms/api/document-service/locale#unpublish) | 公開を取り下げるロケール。 | 既定ロケールのみ | 文字列、`'*'`, または `null` | | [`filters`](/cms/api/document-service/filters) | 使う [フィルター](/cms/api/document-service/filters) | `null` | Object | | [`fields`](/cms/api/document-service/fields#unpublish) | [返すフィールドを選択](/cms/api/document-service/fields#unpublish) | すべてのフィールド
(既定でポピュレートされないものを除く) | Object | | [`populate`](/cms/api/document-service/populate) | 追加フィールドを [ポピュレート](/cms/api/document-service/populate) する。 | `null` | Object | #### 例 `locale` を省略すると、`unpublish()` はドキュメントの既定ロケール版の公開だけを取り下げます。 ### `discardDraft()` {#discarddraft} 下書きデータを破棄し、公開版の内容で上書きします。 コンテンツタイプで [下書きと公開](/cms/features/draft-and-publish) が有効なときだけ使えます。 構文: `discardDraft(parameters: Params): Promise<{ documentId: ID, entries: Number }>` #### パラメータ | パラメータ | 説明 | 既定値 | 型 | |-----------|-------------|---------|------| | `documentId`| ドキュメント ID | | `ID`| | [`locale`](/cms/api/document-service/locale#discard-draft) | 下書きを破棄するロケール。 | 既定ロケールのみ。 | 文字列、`'*'`, または `null` | | [`filters`](/cms/api/document-service/filters) | 使う [フィルター](/cms/api/document-service/filters) | `null` | Object | | [`fields`](/cms/api/document-service/fields#discarddraft) | [返すフィールドを選択](/cms/api/document-service/fields#discarddraft) | すべてのフィールド
(既定でポピュレートされないものを除く) | Object | | [`populate`](/cms/api/document-service/populate) | 追加フィールドを [ポピュレート](/cms/api/document-service/populate) する。 | `null` | Object | #### 例 `locale` を省略すると、`discardDraft()` は既定ロケールについてだけ下書きを破棄し、公開版で上書きします。 ### `count()` {#count} 渡したパラメータに一致するドキュメント数を数えます。 構文: `count(parameters: Params) => number` #### パラメータ | パラメータ | 説明 | 既定値 | 型 | |-----------|-------------|---------|------| | [`locale`](/cms/api/document-service/locale#count) | 数える対象のロケール | 既定ロケール | 文字列または `null` | | [`status`](/cms/api/document-service/status#count) | _コンテンツタイプで [下書きと公開](/cms/features/draft-and-publish) が有効な場合_: 公開状態。次のいずれか。 | `'draft'` | `'published'` または `'draft'` | | [`filters`](/cms/api/document-service/filters) | 使う [フィルター](/cms/api/document-service/filters) | `null` | Object | :::note 公開済みドキュメントには必ず下書き側の対応もあるため、公開済みでも下書き版があるものとして数えられます。 そのため `status: 'draft'` で数えても、他の条件に一致するドキュメントの総数が返ります。一部はすでに公開済みで、Content Manager 上では「下書き」や「変更あり」と表示されない場合でも同様です。公開済みをこのカウントから除外する方法は現状ありません。 ::: #### 例
##### 基本的な例 パラメータを省略すると、`count()` は既定ロケールのドキュメント総数を返します。 ##### 公開済みだけを数える 公開済みドキュメントだけを数えるには、`count()` に `status: 'published'` を他のパラメータと一緒に渡します。 `locale` を省略すると、既定ロケールのドキュメントが数えられます。 ##### フィルター付きで数える [フィルター](/cms/api/document-service/filters) は `count()` にも渡せます。 `locale` と `status` の両方を省略すると、下書き(`status` 省略時の既定。公開済みも下書き版があるものとして数えられるため、ロケール内の利用可能ドキュメント総数に相当)が、既定ロケールについてだけ数えられます。 ```js /** * 下書きドキュメント数を数える(status 省略時の既定) * 英語(既定ロケール) * 名前が 'Pizzeria' で始まるもの */ await strapi.documents('api::restaurant.restaurant').count({ filters: { name: { $startsWith: "Pizzeria" } } }) ``` # Document Service API での fields Source: https://docs.strapi.io/cms/api/document-service/fields # Document Service API: フィールドの選択 既定では、[Document Service API](/cms/api/document-service) はドキュメントのすべてのフィールドを返しますが、どのフィールドもポピュレートしません。このページでは、`fields` パラメータでクエリ結果に含めるフィールドだけを指定する方法を説明します。 :::tip リレーション、メディア、コンポーネント、ダイナミックゾーンをポピュレートするには `populate` パラメータも使えます([`populate` パラメータ](/cms/api/document-service/populate) のドキュメントを参照)。 ::: ## `findFirst()` でフィールドを選ぶ {#findfirst} Document Service API で [最初に一致するドキュメントを取得](/cms/api/document-service#findfirst) するときに、返すフィールドを絞る例です。 ## `findMany()` でフィールドを選ぶ {#findmany} Document Service API で [ドキュメント一覧を取得](/cms/api/document-service#findmany) するときに、返すフィールドを絞る例です。 ## `create()` でフィールドを選ぶ {#create} Document Service API で [ドキュメントを作成](/cms/api/document-service#create) するときに、レスポンスに含めるフィールドを絞る例です。 ## `update()` でフィールドを選ぶ {#update} Document Service API で [ドキュメントを更新](/cms/api/document-service#update) するときに、レスポンスに含めるフィールドを絞る例です。 ## `delete()` でフィールドを選ぶ {#delete} Document Service API で [ドキュメントを削除](/cms/api/document-service#delete) するときに、返却に含めるフィールドを絞る例です。 ## `publish()` でフィールドを選ぶ {#publish} Document Service API で [ドキュメントを公開](/cms/api/document-service#publish) するときに、返却に含めるフィールドを絞る例です。 ## `unpublish()` でフィールドを選ぶ {#unpublish} Document Service API で [公開を取り下げる](/cms/api/document-service#unpublish) ときに、返却に含めるフィールドを絞る例です。 ## `discardDraft()` でフィールドを選ぶ {#discarddraft} Document Service API で [下書きを破棄](/cms/api/document-service#discarddraft) するときに、返却に含めるフィールドを絞る例です。 # Document Service API のフィルター Source: https://docs.strapi.io/cms/api/document-service/filters # Document Service API: フィルター [Document Service API](/cms/api/document-service) では、クエリ結果をフィルターで絞り込めます。 次の演算子が使えます。 | 演算子 | 説明 | | -------------------------------- | ---------------------------------------- | | [`$eq`](#eq) | 等しい | | [`$eqi`](#eqi) | 等しい(大文字・小文字を区別しない) | | [`$ne`](#ne) | 等しくない | | [`$nei`](#nei) | 等しくない(大文字・小文字を区別しない) | | [`$lt`](#lt) | より小さい | | [`$lte`](#lte) | 以下 | | [`$gt`](#gt) | より大きい | | [`$gte`](#gte) | 以上 | | [`$in`](#in) | 配列に含まれる | | [`$notIn`](#notin) | 配列に含まれない | | [`$contains`](#contains) | 含む | | [`$notContains`](#notcontains) | 含まない | | [`$containsi`](#containsi) | 含む(大文字・小文字を区別しない) | | [`$notContainsi`](#notcontainsi) | 含まない(大文字・小文字を区別しない) | | [`$null`](#null) | null である | | [`$notNull`](#notnull) | null でない | | [`$between`](#between) | 範囲内(両端を含む) | | [`$startsWith`](#startswith) | 前方一致 | | [`$startsWithi`](#startswithi) | 前方一致(大文字・小文字を区別しない) | | [`$endsWith`](#endswith) | 後方一致 | | [`$endsWithi`](#endswithi) | 後方一致(大文字・小文字を区別しない) | | [`$or`](#or) | フィルターを OR で結合 | | [`$and`](#and) | フィルターを AND で結合 | | [`$not`](#not) | フィルターを NOT で結合 | ## 属性オペレーター
### `$not` {#not} 内側の条件を否定します。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $not: { $contains: 'Hello World', }, }, }, }); ``` ### `$eq` {#eq} 属性が入力値と等しい。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $eq: 'Hello World', }, }, }); ``` `$eq` は省略できます。 ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: 'Hello World', }, }); ``` ### `$eqi` {#eqi} 属性が入力値と等しい(大文字・小文字を区別しない)。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $eqi: 'HELLO World', }, }, }); ``` ### `$ne` {#ne} 属性が入力値と等しくない。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $ne: 'ABCD', }, }, }); ``` ### `$nei` {#nei} 属性が入力値と等しくない(大文字・小文字を区別しない)。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $nei: 'abcd', }, }, }); ``` ### `$in` {#in} 属性の値が入力リストに含まれる。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $in: ['Hello', 'Hola', 'Bonjour'], }, }, }); ``` 値の配列を直接渡すと `$in` と同じ意味になります。 ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: ['Hello', 'Hola', 'Bonjour'], }, }); ``` ### `$notIn` {#notin} 属性の値が入力リストに含まれない。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $notIn: ['Hello', 'Hola', 'Bonjour'], }, }, }); ``` ### `$lt` {#lt} 属性が入力値より小さい。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { rating: { $lt: 10, }, }, }); ``` ### `$lte` {#lte} 属性が入力値以下。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { rating: { $lte: 10, }, }, }); ``` ### `$gt` {#gt} 属性が入力値より大きい。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { rating: { $gt: 5, }, }, }); ``` ### `$gte` {#gte} 属性が入力値以上。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { rating: { $gte: 5, }, }, }); ``` ### `$between` {#between} 属性が 2 つの入力値のあいだ(両端を含む)。例: `$between: [1, 3]` なら `1` と `3` も一致。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { rating: { $between: [1, 20], }, }, }); ``` ### `$contains` {#contains} 属性が入力値を含む(大文字・小文字を区別)。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $contains: 'Hello', }, }, }); ``` ### `$notContains` {#notcontains} 属性が入力値を含まない(大文字・小文字を区別)。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $notContains: 'Hello', }, }, }); ``` ### `$containsi` {#containsi} 属性が入力値を含む。`$containsi` は大文字・小文字を区別せず、[$contains](#contains) は区別します。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $containsi: 'hello', }, }, }); ``` ### `$notContainsi` {#notcontainsi} 属性が入力値を含まない。`$notContainsi` は大文字・小文字を区別せず、[$notContains](#notcontains) は区別します。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $notContainsi: 'hello', }, }, }); ``` ### `$startsWith` {#startswith} 属性が入力値で始まる(大文字・小文字を区別)。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $startsWith: 'ABCD', }, }, }); ``` ### `$startsWithi` {#startswithi} 属性が入力値で始まる(大文字・小文字を区別しない)。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $startsWithi: 'ABCD', // 'abcd' で絞った場合と同様 }, }, }); ``` ### `$endsWith` {#endswith} 属性が入力値で終わる(大文字・小文字を区別)。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $endsWith: 'ABCD', }, }, }); ``` ### `$endsWithi` {#endswithi} 属性が入力値で終わる(大文字・小文字を区別しない)。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $endsWithi: 'ABCD', // 'abcd' で絞った場合と同様 }, }, }); ``` ### `$null` {#null} 属性が `null` である。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $null: true, }, }, }); ``` ### `$notNull` {#notnull} 属性が `null` でない。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $notNull: true, }, }, }); ``` ## 論理オペレーター ### `$and` {#and} ネストした条件がすべて `true` であること。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { $and: [ { title: 'Hello World', }, { createdAt: { $gt: '2021-11-17T14:28:25.843Z' }, }, ], }, }); ``` オブジェクトで複数条件を並べると、暗黙の `$and` になります。 ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: 'Hello World', createdAt: { $gt: '2021-11-17T14:28:25.843Z' }, }, }); ``` ### `$or` {#or} ネストした条件の少なくとも 1 つが `true` であること。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { $or: [ { title: 'Hello World', }, { createdAt: { $gt: '2021-11-17T14:28:25.843Z' }, }, ], }, }); ``` ### `$not` ネストした条件を否定します。 **例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { $not: { title: 'Hello World', }, }, }); ``` :::note `$not` は次のように使えます。 - 論理オペレーター(例: `filters: { $not: { // 条件… }}`) - [属性オペレーター](#not)(例: `filters: { 属性名: { $not: { … } } }`) ::: :::tip `$and`、`$or`、`$not` は、別の `$and` / `$or` / `$not` の内側にネストできます。 ::: # Document Service API の locale パラメータ Source: https://docs.strapi.io/cms/api/document-service/locale # Document Service API: `locale` パラメータ 既定では、[Document Service API](/cms/api/document-service) はドキュメントの**既定ロケール**版を返します(アプリで別の既定ロケールを設定していなければ `'en'`、つまり英語版です。[Internationalization (i18n)](/cms/features/internationalization) を参照)。このページでは、特定のロケールだけを対象にデータを取得・更新するために `locale` をどう使うかを説明します。 ## `findOne()` でロケール版を取得する {#find-one} `locale` を渡すと、Document Service API の [`findOne()` メソッド](/cms/api/document-service#findone) は、そのロケールのドキュメント版を返します。 `status` を省略すると、既定で `draft` 版が返ります。 ## `findFirst()` でロケール版を取得する {#find-first} Document Service API で [最初に一致するドキュメントを取得](/cms/api/document-service#findfirst) するとき、特定のロケール版を返す例です。 `status` を省略すると、既定で `draft` 版が返ります。 ## `findMany()` でロケール版を取得する {#find-many} [`findMany()` メソッド](/cms/api/document-service#findmany) に `locale` を渡すと、そのロケールが存在するドキュメントがすべて返ります。 `status` を省略すると、既定で各ドキュメントの `draft` 版が返ります。
補足説明: 次の 4 ドキュメントがあり、ロケールの組み合わせがそれぞれ異なるとします。 - ドキュメント A: - en - `fr` - it - ドキュメント B: - en - it - ドキュメント C: - `fr` - ドキュメント D: - `fr` - it `findMany({ locale: 'fr' })` は、`fr` 版を持つドキュメント A、C、D について、それぞれの下書き版だけを返します。
## ロケール向けに `create()` する {#create} 特定ロケール用のドキュメントを作成するには、Document Service API の [`create` メソッド](/cms/api/document-service#create) に `locale` を渡します。 ## ロケール版を `update()` する {#update} ドキュメントの特定ロケール版だけを更新するには、Document Service API の [`update()` メソッド](/cms/api/document-service#update) に `locale` を渡します。 ## ロケール版を `delete()` する {#delete} Document Service API の [`delete()` メソッド](/cms/api/document-service#delete) で `locale` を使うと、一部のロケールだけを削除できます。`status` を明示しない限り、下書きと公開版の両方が削除されます。 ### 1 つのロケール版を削除 ```js await strapi.documents('api::restaurant.restaurant').delete({ documentId: 'a1b2c3d4e5f6g7h8i9j0klm', locale: 'es', }); ``` ### すべてのロケール版を削除 `locale` にはワイルドカード `*` が使え、ドキュメントのすべてのロケール版を削除できます。 ## ロケール版を `publish()` する {#publish} Document Service API の [`publish()` メソッド](/cms/api/document-service#publish) で、特定のロケール版だけを公開するには `locale` を渡します。 ### 1 つのロケール版を公開 ### すべてのロケール版を公開 `locale` に `*` を渡すと、ドキュメントのすべてのロケール版を公開できます。 ## ロケール版を `unpublish()` する {#unpublish} Document Service API の [`unpublish()` メソッド](/cms/api/document-service#unpublish) で、特定のロケール版だけの公開を取り下げるには `locale` を渡します。 ### 1 つのロケール版の公開を取り下げ ### すべてのロケール版の公開を取り下げ `locale` に `*` を渡すと、ドキュメントのすべてのロケール版の公開を取り下げられます。 ## ロケール版で `discardDraft()` する {#discard-draft} Document Service API の [`discardDraft()` メソッド](/cms/api/document-service#discarddraft) で、一部のロケールについてだけ下書きを破棄するには `locale` を渡します。 ### 1 つのロケール版の下書きを破棄 そのロケールの公開版の内容で下書きを上書きするには、`discardDraft()` に `locale` を渡します。 ### すべてのロケール版の下書きを破棄 `locale` に `*` を渡すと、各ロケールについて下書きを破棄し、公開版のデータで置き換えられます。 ## ロケールごとに `count()` する {#count} 特定ロケールのドキュメント数を数えるには、Document Service API の [`count()` メソッド](/cms/api/document-service#count) に `locale` と他のパラメータを渡します。 `status` を省略すると、下書きが数えられます(公開済みも下書き版があるものとして数えるため、ロケール内の利用可能ドキュメント総数に相当します)。 ```js // フランス語ロケールのドキュメント数(status 省略時は下書きベースの総数) await strapi.documents('api::restaurant.restaurant').count({ locale: 'fr' }); ``` # Document Service の振る舞いを拡張する Source: https://docs.strapi.io/cms/api/document-service/middlewares # Document Service API: ミドルウェア [Document Service API](/cms/api/document-service) は、ミドルウェアで振る舞いを拡張できます。 Document Service のミドルウェアでは、各メソッドの実行前や実行後に処理を挟めます。
コントローラーが強調された Strapi バックエンドの簡略図
リクエストが Strapi バックエンドをどう通るかの簡略図で、Document Service を強調しています。完全なインタラクティブな図はバックエンドのカスタマイズの概要ページにあります。
## ミドルウェアの登録 構文: `strapi.documents.use(middleware)` ### パラメータ ミドルウェアは、`context` と `next` を受け取る関数です。 構文: `(context, next) => ReturnType` | パラメータ | 説明 | 型 | |-----------|---------------------------------------|------------| | `context` | ミドルウェア用のコンテキスト | `Context` | | `next` | スタック内の次のミドルウェアを呼び出す | `function` | #### `context` | パラメータ | 説明 | 型 | |---------------|--------------------------------------------------------------------------------------|---------------| | `action` | 実行中のメソッド([利用可能なメソッド](/cms/api/document-service)を参照) | `string` | | `params` | メソッドのパラメータ([利用可能なメソッド](/cms/api/document-service)を参照) | `Object` | | `uid` | コンテンツタイプの一意識別子 | `string` | | `contentType` | コンテンツタイプ | `ContentType` |
例: 呼び出すメソッドに応じて `context` に含まれる内容の例です。
#### `next` `next` は引数のない関数で、スタックの次のミドルウェアを呼び出し、その戻り値を返します。 **例** ```js strapi.documents.use((context, next) => { return next(); }); ``` ### 登録する場所 一般的に、ミドルウェアは Strapi の `register` フェーズで登録します。 #### アプリ利用者 アプリ直下の `register()` ライフサイクルで登録します。 ```js title="/src/index.js|ts" module.exports = { register({ strapi }) { strapi.documents.use((context, next) => { // ここにロジック return next(); }); }, // bootstrap({ strapi }) {}, // destroy({ strapi }) {}, }; ``` #### プラグイン開発者 プラグインの `register()` ライフサイクルで登録します。 ```js title="/(plugin-root-folder)/strapi-server.js|ts" module.exports = { register({ strapi }) { strapi.documents.use((context, next) => { // ここにロジック return next(); }); }, // bootstrap({ strapi }) {}, // destroy({ strapi }) {}, }; ``` ## ミドルウェアの実装 実装するときは、必ず `next()` の戻り値を返してください。 そうしないと Strapi アプリが壊れる可能性があります。 ### 例 ```js const applyTo = ['api::article.article']; strapi.documents.use(async (context, next) => { // 特定のコンテンツタイプだけ対象 if (!applyTo.includes(context.uid)) { return next(); } // 特定のアクションだけ対象 if (['create', 'update'].includes(context.action)) { context.params.data.fullName = `${context.params.data.firstName} ${context.params.data.lastName}`; } const result = await next(); // 返す前に result を加工する return result; }); ```
:::strapi ライフサイクルフック Document Service API は、呼び出すメソッドに応じてさまざまなデータベースのライフサイクルフックを発火します。一覧は [Document Service API: ライフサイクルフック](/cms/migration/v4-to-v5/breaking-changes/lifecycle-hooks-document-service#table) を参照してください。 ::: # Document Service API の populate Source: https://docs.strapi.io/cms/api/document-service/populate # Document Service API: フィールドのポピュレート 既定では、[Document Service API](/cms/api/document-service) はリレーション、メディア、コンポーネント、ダイナミックゾーンをいずれもポピュレートしません。このページでは、`populate` で特定のフィールドをポピュレートする方法を説明します。 :::tip 返すフィールドだけを絞るには `fields` も使えます([`fields` パラメータ](/cms/api/document-service/fields) のドキュメントを参照)。 ::: :::caution Users & Permissions プラグインが有効な場合、ポピュレート先のコンテンツタイプに対して `find` 権限が必要です。ロールがそのコンテンツタイプにアクセスできない場合、ポピュレートされません。 ::: ## リレーションとメディア クエリでは `populate` で、ポピュレートするフィールドを次のような形で指定します。 ### すべてのリレーションを 1 階層だけ すべてのリレーションを 1 階層だけポピュレートするには、`populate` にワイルドカード `*` を使います。 ### 特定のリレーションだけ 1 階層 特定のリレーションだけを 1 階層ポピュレートするには、リレーション名を `populate` の配列で渡します。 ### 特定のリレーションを複数階層 特定のリレーションを複数階層ポピュレートするには、オブジェクト形式の `populate` を使います。 ## コンポーネントとダイナミックゾーン コンポーネントはリレーションと同じ要領でポピュレートします。 ダイナミックゾーンは構造が可変です。ポピュレートするには `on` でコンポーネントごとにクエリを定義します。 ## `create()` 時のポピュレート 作成レスポンスにポピュレート結果を含める例です。 ## `update()` 時のポピュレート 更新レスポンスにポピュレート結果を含める例です。 ## `publish()` 時のポピュレート 公開時のレスポンスにポピュレート結果を含めます(`unpublish()` や `discardDraft()` も同様の動きです)。 # Document Service API でのソートとページネーション Source: https://docs.strapi.io/cms/api/document-service/sort-pagination # Document Service API: 結果のソートとページネーション [Document Service API](/cms/api/document-service) では、クエリ結果のソートとページネーションができます。 ## ソート {#sort} Document Service API の結果をソートするには、クエリに `sort` パラメータを含めます。 ### 単一フィールドでソート 1 つのフィールドでソートする例です。 ### 複数フィールドでソート 複数フィールドでソートするには、配列で渡します。 ## ページネーション {#pagination} ページネーションするには、`limit` と `start` を渡します。 # Document Service API と下書き・公開 Source: https://docs.strapi.io/cms/api/document-service/status # Document Service API: 下書きと公開の扱い [下書きと公開](/cms/features/draft-and-publish) が有効なとき、[Document Service API](/cms/api/document-service) は既定でドキュメントの下書き版を返します。このページでは `status` パラメータで次を行う方法を説明します。 - ドキュメントの公開版を返す - ステータスに応じてドキュメントを数える - 作成または更新と同時に公開する :::note Document Service API のクエリに `{ status: 'draft' }` を渡した結果は、`status` を省略した場合と同じです。 ::: ## `findOne()` で公開版を取得する {#find-one} `findOne()` は既定でドキュメントの下書き版を返します。 Document Service API で [特定のドキュメントを取得](/cms/api/document-service#findone) するときに公開版が欲しい場合は、`status: 'published'` を渡します。 ## `findFirst()` で公開版を取得する {#find-first} `findFirst()` は既定でドキュメントの下書き版を返します。 Document Service API で [最初のドキュメントを取得](/cms/api/document-service#findfirst) するときに公開版が欲しい場合は、`status: 'published'` を渡します。 ## `findMany()` で公開版を取得する {#find-many} `findMany()` は既定で各ドキュメントの下書き版を返します。 Document Service API で [ドキュメント一覧を取得](/cms/api/document-service#findmany) するときに公開版が欲しい場合は、`status: 'published'` を渡します。 ## `count()` で下書きまたは公開のみを数える {#count} Document Service API で [ドキュメント数を数える](/cms/api/document-service#count) とき、下書き版または公開版だけを考慮するには、対応する `status` を渡します。 ```js // 下書きを数える(実際には公開済みも含まれる) const draftsCount = await strapi.documents("api::restaurant.restaurant").count({ status: 'draft' }); ``` ```js // 公開済みのみを数える const publishedCount = await strapi.documents("api::restaurant.restaurant").count({ status: 'published' }); ``` :::note 公開済みドキュメントには必ず下書き側の対応もあるため、公開済みでも下書き版があるものとして数えられます。 そのため `status: 'draft'` で数えても、他の条件に一致するドキュメントの総数が返ります。一部はすでに公開済みで、Content Manager 上では「下書き」や「変更あり」と表示されない場合でも同様です。公開済みをこのカウントから除外する方法は現状ありません。 ::: ## 下書きを作成して公開する {#create} `create()` に渡すパラメータに `status: 'published'` を付けると、作成と同時にドキュメントを公開できます。 ## 下書きを更新して公開する {#update} `update()` に渡すパラメータに `status: 'published'` を付けると、更新と同時にドキュメントを公開できます。 # GraphQL API Source: https://docs.strapi.io/cms/api/graphql # GraphQL API GraphQL API では、Strapi の [GraphQL プラグイン](/cms/plugins/graphql) 経由で [コンテンツタイプ](/cms/backend-customization/models#content-types) をクエリ・ミューテーションできます。結果は [フィルター](#filters)、[ソート](#sorting)、[ページネーション](#pagination) で絞り込み・並べ替え・分割取得できます。 :::prerequisites GraphQL API を使うには、[GraphQL](/cms/plugins/graphql) プラグインをインストールします。 ::: インストール後、GraphQL Playground は `/graphql` で開けます。クエリやミューテーションを対話的に組み立て、コンテンツタイプに合わせたスキーマドキュメントを参照できます。 #### リレーションの取得 {#fetch-relations} フラットクエリでも ::: ### メディアフィールドの取得 {#fetch-media-fields} メディアフィールドも、他の属性と同様に取得します。 次の例では、「Restaurants」コンテンツタイプの各ドキュメントに付いた `cover` メディアの `url` を取得します。 ```graphql { restaurants { images { documentId url } } } ``` 複数メディア用フィールドは、フラットクエリまたは ### コンポーネントの取得 {#fetch-components} コンポーネントの内容も、他の属性と同様に取得します。 次の例では、「Restaurants」の各ドキュメントに含まれる `closingPeriod` コンポーネントについて、`label`、`start_date`、`end_date` を取得します。 ```graphql { restaurants { closingPeriod { label start_date end_date } } } ``` ### ダイナミックゾーンの取得 {#fetch-dynamic-zone-data} ダイナミックゾーンは GraphQL ではユニオン型になるため、 ```graphql title="所属演算子の例(in, notIn)" # in - returns restaurants with category either "pizza" or "burger" { restaurants(filters: { category: { in: ["pizza", "burger"] } }) { name } } # notIn - returns restaurants whose category is neither "pizza" nor "burger" { restaurants(filters: { category: { notIn: ["pizza", "burger"] } }) { name } } ``` ```graphql title="null 判定演算子の例(null, notNull)" # null - returns restaurants where description is null { restaurants(filters: { description: { null: true } }) { name } } # notNull - returns restaurants where description is not null { restaurants(filters: { description: { notNull: true } }) { name } } ``` ```graphql title="論理演算子の例(and, or, not)" # and - both category must be "pizza" AND averagePrice must be < 20 { restaurants(filters: { and: [ { category: { eq: "pizza" } }, { averagePrice: { lt: 20 } } ] }) { name } } # or - category is "pizza" OR category is "burger" { restaurants(filters: { or: [ { category: { eq: "pizza" } }, { category: { eq: "burger" } } ] }) { name } } # not - category must NOT be "pizza" { restaurants(filters: { not: { category: { eq: "pizza" } } }) { name } } ``` ```graphql title="ネストした論理演算子の例(20 ユーロ未満のピッツェリアなど)" { restaurants( filters: { and: [ { not: { averagePrice: { gte: 20 } } }, { or: [ { name: { eq: "Pizzeria" } }, { name: { startsWith: "Pizzeria" } } ] } ] } ) { documentId name averagePrice } } ``` ### 特定ロケールの 1 件を取得 {#locale-fetch} 特定ロケールの ### ローカライズしたドキュメントを新規作成 {#locale-create} `locale` を渡すと、特定ロケール用の # OpenAPI specification Source: https://docs.strapi.io/cms/api/openapi # OpenAPI 仕様の生成 Strapi はコマンドラインから 任意の `--output` で出力パスとファイル名を指定できます。 ### 仕様の構造と内容 生成される OpenAPI 仕様は
生成された OpenAPI 仕様には、Strapi アプリで利用可能な API エンドポイントと、次のような各エンドポイントに関する情報が含まれます。 - すべてのコンテンツタイプに対する CRUD 操作 - アプリで定義したカスタム API ルート - ユーザー管理向けの認証エンドポイント - メディア用のファイルアップロードエンドポイント - インストール済みプラグインのエンドポイント ## Swagger UI との連携 次の手順で [Swagger UI](https://swagger.io/) 互換のページをすばやく用意できます。 1. 仕様を生成します。 2. [`/config/middlewares.js` の設定](/cms/configurations/middlewares) を次のコードに更新します。 こうすると から読み込む Swagger UI が、[セキュリティミドルウェア](/cms/configurations/middlewares#security) の CSP でブロックされにくくなります。 3. Strapi プロジェクトに `public/openapi.html` を作成し、Swagger UI を表示する次のコードを入れます。 ```html API Documentation
``` 4. Strapi サーバーを `yarn develop` または `npm run develop` で再起動し、`/openapi.html` を開きます。Swagger UI が表示されます。 ![Strapi の OpenAPI 仕様を使った Swagger UI の例](/img/assets/apis/swagger-open-api.png) # REST API reference Source: https://docs.strapi.io/cms/api/rest # REST API リファレンス REST API では、[コンテンツタイプ](/cms/backend-customization/models) を API エンドポイント経由で操作できます。Strapi はコンテンツタイプを作成するときに [API エンドポイント](#endpoints) を自動生成します。クエリ時には [API パラメータ](/cms/api/rest/parameters) で結果を絞り込めます。 このドキュメントはコンテンツタイプ向けの REST API リファレンスです。用途別の手順は [ガイド](/cms/api/rest/guides/intro) も参照してください。 :::prerequisites コンテンツタイプは既定では非公開です。公開するか、適切な権限で認証したクエリが必要です。詳しくは [クイックスタート](/cms/quick-start#step-4-set-roles--permissions)、[Users & Permissions](/cms/features/users-permissions#roles)、[API トークン](/cms/features/api-tokens) を参照してください。 ::: :::note 既定では REST API のレスポンスにはトップレベルのフィールドのみが含まれ、リレーション、メディア、コンポーネント、ダイナミックゾーンはポピュレートされません。特定のフィールドをポピュレートするには [`populate` パラメータ](/cms/api/rest/populate-select) を使います。ポピュレートするリレーションのフィールドには find 権限が付与されている必要があります。 ::: :::strapi Strapi Client [Strapi Client](/cms/api/client) ライブラリはバックエンドとのやり取りを簡素化し、コンテンツの取得・作成・更新・削除が行えます。 ::: ## エンドポイント {#endpoints} 各コンテンツタイプに対して、次のエンドポイントが自動生成されます。
複数形 API ID と単数形 API ID: 次の表では次のとおりです。 - `:singularApiId` はコンテンツタイプの「API ID(単数形)」の値、 - `:pluralApiId` は「API ID(複数形)」の値を指します。 これらは Content-Type Builder でコンテンツタイプを作成するときに定義され、管理画面で編集するときにも確認できます([ユーザーガイド](/cms/features/content-type-builder#creating-content-types) 参照)。例として、既定の「Article」コンテンツタイプでは次のとおりです。 - `:singularApiId` は `article` - `:pluralApiId` は `articles`
エンドポイントの具体例: 次の例は
:::strapi Upload API [メディアライブラリ](/cms/features/media-library) を支える Upload パッケージは、専用の [`/api/upload` エンドポイント](/cms/api/rest/upload) があります。 ::: :::note [コンポーネント](/cms/backend-customization/models#components-json) には API エンドポイントはありません。 ::: ## リクエストとレスポンス {#requests} :::strapi Strapi 5 と Strapi v4 Strapi 5 の Content API は Strapi v4 と比べて主に次の 2 点が異なります。 - レスポンス形式がフラット化され、属性は `data.attributes` にネストされず、`data` の直下にあります(例: 「title」は `data.title`)。 - Strapi 5 では **ドキュメント** ### ドキュメントを 1 件取得 {#get} `documentId` でドキュメントを返します。 :::strapi Strapi 5 と Strapi v4 Strapi 5 では特定のドキュメントは `documentId` で参照します。 ::: ### ドキュメントを作成 {#create} ドキュメントを作成し、その内容を返します。 [Internationalization (i18n) プラグイン](/cms/features/internationalization) が有効な場合、REST API の POST で [ローカライズされたドキュメントを作成](/cms/api/rest/locale#rest-create) できます。 :::note 作成時にリレーションとその順序を指定できます(詳しくは [REST API でのリレーション管理](/cms/api/rest/relations.md) を参照)。 ::: ### ドキュメントを更新 {#update} ドキュメントを部分更新し、結果を返します。 フィールドをクリアするには `null` を送ります。 :::note メモ * [Internationalization (i18n) プラグイン](/cms/features/internationalization) が有効でも、現時点ではドキュメントの [ロケールの更新](/cms/api/rest/locale#rest-update) はできません。 * 更新時にもリレーションとその順序を指定できます(詳しくは [REST API でのリレーション管理](/cms/api/rest/relations) を参照)。 ::: ### ドキュメントを削除 {#delete} ドキュメントを削除します。 成功時、`DELETE` は HTTP ステータス 204 のみを返し、レスポンスボディは空です。 # Filters Source: https://docs.strapi.io/cms/api/rest/filters # REST API: フィルター [REST API](/cms/api/rest) では、[「ドキュメント一覧を取得」](/cms/api/rest#get-all) の結果にフィルターをかけられます。
オプション機能を使うと、次のようなフィルターも利用できます。 - [Internationalization (i18n) プラグイン](/cms/features/internationalization) がコンテンツタイプで有効な場合、ロケールで絞り込めます。 - [下書きと公開](/cms/features/draft-and-publish) が有効な場合、既定の `published` または `draft` の状態で絞り込めます。 :::tip
JavaScript のクエリ(qs ライブラリで組み立て): ## 例: id が 3、6、8 のレストランを複数取得 配列の値と `$in` で、複数の完全一致を検索できます。
JavaScript のクエリ(qs ライブラリで組み立て): ## 複合フィルター 複合フィルターでは、`$and` と `$or` などを組み合わせて、必要なデータだけを柔軟に取得します。
JavaScript のクエリ(qs ライブラリで組み立て): ## ディープフィルター ディープフィルターは、リレーション先のフィールドで絞り込む方法です。 :::note - リレーション、メディア、コンポーネント、ダイナミックゾーンは既定ではポピュレートされません。`populate` で構造を含めます([`populate` のドキュメント](/cms/api/rest/populate-select#population) 参照)。 - ポピュレートした内容にフィルターをかけたり、ネストしたリレーションにフィルターをかけたりはできますが、メディアやダイナミックゾーンなど多態的な構造にフィルターは使えません。 ::: :::caution ディープフィルター付きの API クエリはパフォーマンスに影響することがあります。遅いクエリがある場合は、最適化したクエリを使うカスタムルートの実装を検討してください。 :::
JavaScript のクエリ(qs ライブラリで組み立て): # REST API Guides Source: https://docs.strapi.io/cms/api/rest/guides/intro # REST API ガイド [REST API リファレンス](/cms/api/rest) は、利用できるエンドポイントとパラメータを素早く確認するためのものです。 ## ガイド Strapi ドキュメントチームがメンテナンスする次のガイドでは、専門的なトピックを扱い、一部は詳しい解説(🧠)、一部は手順中心(🛠️)になっています。 ## その他の資料 :::strapi 他のユーザー向けに貢献したい方へ この節の一部の外部資料は Strapi v4 向けに作られており、Strapi 5 ではそのままでは動かない場合があります。Strapi 5 向けに更新したい場合は、Write for the Community プログラムで してください。 ::: チュートリアルやガイドは次のブログ記事でも公開されています。 # Interactive Query Builder Source: https://docs.strapi.io/cms/api/rest/interactive-query-builder # Strapi のインタラクティブツールでクエリ URL を組み立てる [REST API](/cms/api/rest) では多くのパラメータを組み合わせられるため、クエリ URL が長く複雑になりがちです。 Strapi のコードベースでは でネストした JavaScript オブジェクトをパース・文字列化しています。複雑なクエリ URL は手入力より `qs` で生成することを推奨します。 次のインタラクティブなクエリビルダーで URL を自動生成できます。 1. 用途に合わせて _Endpoint_ と _Endpoint Query Parameters_ の値を書き換えます。 2. **Copy to clipboard** をクリックし、入力に応じて更新される _Query String URL_ をコピーします。 :::info パラメータの使い方 [REST API のパラメータ一覧](/cms/api/rest/parameters) と、各パラメータのドキュメントを参照すると理解しやすくなります。 :::


:::note 既定のエンドポイントパスは `/api/` で始まり、[API 設定の `rest.prefix`](/cms/configurations/api) で変更していない限りそのままにしてください。
例: 既定の API プレフィックスで `books` コレクションタイプをクエリする場合、_Endpoint_ に `/api/books` と入力します。 ::: :::caution 免責 このページの `qs` とインタラクティブクエリビルダーは次の限界があります。 - 構文エラーをすべて検出できるわけではない - プロジェクトで使えるパラメータや値を知らない - オートコンプリートはない 現状は、JavaScript オブジェクトをインラインのクエリ文字列 URL に変換するための補助です。生成した URL が必ずしも API で期待どおりの結果を返すとは限りません。 ::: # Locale Source: https://docs.strapi.io/cms/api/rest/locale # REST API: `locale` [Internationalization (i18n)](/cms/features/internationalization) により、[REST API](/cms/api/rest) でロケール単位の操作が追加されます。 :::prerequisites API でロケールのコンテンツを扱う前に、管理画面でロケールが [Strapi に追加済み](/cms/features/internationalization#settings) であることを確認してください。 ::: `locale` [API パラメータ](/cms/api/rest/parameters) で、指定したロケールのドキュメントだけを扱えます。値はロケールコードです( ### `GET` 特定ロケールのドキュメント一覧を取得 {#rest-get-all} ### `GET` 特定ロケールのドキュメントを 1 件取得 {#rest-get} 指定ロケールのドキュメントを取得するには、クエリに `locale` を付けます。 | 用途 | 構文と詳細へのリンク | | -------------------- | ---------------------------------------------------------------------------------------------- | | コレクションタイプ | [`GET /api/content-type-plural-name/document-id?locale=locale-code`](#get-one-collection-type) | | シングルタイプ | [`GET /api/content-type-singular-name?locale=locale-code`](#get-one-single-type) | #### コレクションタイプ {#get-one-collection-type} コレクションタイプで、指定ロケールの特定ドキュメントを取得するには、`documentId` のあとに `locale` を付けます。 #### シングルタイプ {#get-one-single-type} シングルタイプで、指定ロケールのドキュメントを取得するには、シングルタイプ名のあとに `locale` を付けます。 ### `POST` コレクションタイプ向けにローカライズされたドキュメントを新規作成 {#rest-create} ゼロからローカライズされたドキュメントを作るには Content API に POST します。既定ロケール用か別ロケール用かで、クエリに `locale` が必要かどうかが変わります。 | 用途 | 構文と詳細へのリンク | | ----------------------------- | --------------------------------------------------------------------------------------- | | 既定ロケール向けに作成 | [`POST /api/content-type-plural-name`](#rest-create-default-locale) | | 特定ロケール向けに作成 | [`POST /api/content-type-plural-name?locale=fr`](#rest-create-specific-locale) | #### 既定ロケール向け {#rest-create-default-locale} リクエストボディにロケールを渡さない場合、ドキュメントはアプリの既定ロケールで作成されます。 #### 特定ロケール向け {#rest-create-specific-locale} 既定以外のロケール用エントリを作るには、POST のクエリ URL に `locale` を付けます。 ### `PUT` 既存ドキュメントのロケール版を新規作成または更新 {#rest-update} 既存ドキュメントへの `PUT` では次ができます。 - 別ロケール版のドキュメントを新規に作る - 既存のロケール版を更新する 適切な URL に `PUT` し、クエリに `locale=ロケールコード` を付け、ボディの `data` に属性を渡します。 | 用途 | 構文と詳細へのリンク | | -------------------- | --------------------------------------------------------------------------------------- | | コレクションタイプ | [`PUT /api/content-type-plural-name/document-id?locale=locale-code`](#rest-put-collection-type) | | シングルタイプ | [`PUT /api/content-type-singular-name?locale=locale-code`](#rest-put-single-type) | :::caution 既存のローカライズ済みエントリに別ロケールを追加するとき、リクエストボディではローカライズ対象のフィールドのみ受け付けます。 ::: :::tip コンテンツタイプで [`createLocalization` 権限](/cms/features/rbac#collection-and-single-types) が有効である必要があります。無効だと `403: Forbidden` になります。 ::: :::note 既存のローカライズ済みエントリのロケール自体は変更できません。更新時にボディで `locale` 属性を送っても無視されます。 ::: #### コレクションタイプ {#rest-put-collection-type} コレクションタイプの既存ドキュメントに新しいロケールを追加するには、`documentId` のあとに `locale` を付け、ボディにデータを渡します。 #### シングルタイプ {#rest-put-single-type} シングルタイプの既存ドキュメントに新しいロケールを追加するには、シングルタイプ名のあとに `locale` を付け、ボディにデータを渡します。
### `DELETE` ドキュメントの特定ロケール版を削除 {#rest-delete} ドキュメントの特定ロケール版だけを削除するには、適切な `locale` 付きで `DELETE` を送ります。 成功時、`DELETE` は HTTP ステータス 204 のみを返し、レスポンスボディは空です。 #### コレクションタイプ {#rest-delete-collection-type} コレクションタイプで特定ロケール版だけを削除するには、`documentId` のあとに `locale` を付けます。 #### シングルタイプ {#rest-delete-single-type} シングルタイプで特定ロケール版だけを削除するには、シングルタイプ名のあとに `locale` を付けます。 # Parameters Source: https://docs.strapi.io/cms/api/rest/parameters # REST API のパラメータ [REST API](/cms/api/rest) では API パラメータで結果のフィルター、ソート、ページネーション、表示フィールドやポピュレートするリレーションの指定ができます。さらに、下書きと公開の状態やロケールなど、オプション機能に関するパラメータも使えます。 利用できる API パラメータは次のとおりです。 | パラメータ | 型 | 説明 | | ------------------ | ------------- | ----------------------------------------------------- | | `filters` | Object | [レスポンスをフィルター](/cms/api/rest/filters) | | `locale` | String | [ロケールを指定](/cms/api/rest/locale) | | `status` | String | [下書きと公開の状態を指定](/cms/api/rest/status) | | `populate` | String or Object | [リレーション、コンポーネント、ダイナミックゾーンをポピュレート](/cms/api/rest/populate-select#population) | | `fields` | Array | [表示するフィールドのみを選択](/cms/api/rest/populate-select#field-selection) | | `sort` | String or Array | [レスポンスをソート](/cms/api/rest/sort-pagination.md#sorting) | | `pagination` | Object | [エントリをページング](/cms/api/rest/sort-pagination.md#pagination) | :::note パラメータ内の長い角括弧エンコードのリスト(例: `populate` や `fields`)は、[`strapi::query` の `arrayLimit`](/cms/configurations/middlewares#query) により制限されます。[ポピュレート](/cms/api/rest/populate-select#population) も参照してください。 ::: クエリパラメータは (角括弧 `[]` でエンコード)を使います。 :::tip 多くの REST API パラメータを組み合わせるとクエリ URL が長く複雑になりがちです。
👉 Strapi の [インタラクティブなクエリビルダー](/cms/api/rest/interactive-query-builder) で URL を組み立てると便利です。 🤗 ::: # Populate and Select Source: https://docs.strapi.io/cms/api/rest/populate-select # REST API: ポピュレートとフィールド選択 [REST API](/cms/api/rest) は既定ではリレーション、メディア、コンポーネント、ダイナミックゾーンをポピュレートしません。含めたいフィールドには [`populate` パラメータ](#population) を使います。クエリ結果に特定のフィールドだけを返すには [`fields` パラメータ](#field-selection) を使います。 :::tip ## ポピュレート {#population} REST API は既定ではこれらの型をポピュレートしないため、`populate` を渡さない限りリレーション、メディア、コンポーネント、ダイナミックゾーンは含まれません。ポピュレートしたリレーションは常にオブジェクト全体が返り、REST API では ID の配列だけを返すことはできません。 :::prerequisites ポピュレートするコンテンツタイプには `find` 権限が必要です。ロールにアクセスがないコンテンツタイプはポピュレートされません(`find` の付与方法は [Users & Permissions](/cms/features/users-permissions#editing-a-role) を参照)。 ::: `populate` は単独で使うほか、[複数のオペレータと組み合わせて](#combining-population-with-other-operators)細かく制御できます。 :::caution `populate=deep` 系のプラグインは [Strapi では推奨されません](https://support.strapi.io/articles/8544110758-why-populate-deep-plugins-are-not-recommended-in-strapi)。 ::: :::note クエリ文字列に並ぶ長い `populate` リスト(`populate[0]`、`populate[1]`、…)は、クエリパーサの `arrayLimit`(既定: `100`)で上限があります。より長くするには [`strapi::query` ミドルウェア](/cms/configurations/middlewares#query) の `arrayLimit` を上げます。値を大きくするとリクエストあたりのパース負荷が増えます。 ::: 次の表は代表的な `populate` の書式です。各行の詳細は Understanding populate ガイドへリンクしています。 | 用途 | パラメータの例 | 詳しい説明 | |-----------| ---------------|-----------------------| | メディア・リレーション・コンポーネント・ダイナミックゾーンを含め、すべて 1 階層だけ | `populate=*`| [すべてのリレーションとフィールドを 1 階層だけポピュレート](/cms/api/rest/guides/understanding-populate#populate-all-relations-and-fields-1-level-deep) | | 1 つのリレーションを
1 階層だけ | `populate=a-relation-name`| [特定のリレーションを 1 階層だけ](/cms/api/rest/guides/understanding-populate#populate-1-level-deep-for-specific-relations) | | 複数のリレーションを
1 階層だけ | `populate[0]=relation-name&populate[1]=another-relation-name&populate[2]=yet-another-relation-name`| [特定のリレーションを 1 階層だけ](/cms/api/rest/guides/understanding-populate#populate-1-level-deep-for-specific-relations) | | 一部のリレーションを複数階層 | `populate[root-relation-name][populate][0]=nested-relation-name`| [特定のリレーションを複数階層](/cms/api/rest/guides/understanding-populate#populate-several-levels-deep-for-specific-relations) | | コンポーネントをポピュレート | `populate[0]=component-name`| [コンポーネントのポピュレート](/cms/api/rest/guides/understanding-populate#populate-components) | | コンポーネントと、そのネストしたコンポーネント | `populate[0]=component-name&populate[1]=component-name.nested-component-name`| [コンポーネントのポピュレート](/cms/api/rest/guides/understanding-populate#populate-components) | | ダイナミックゾーン(第 1 階層の要素のみ) | `populate[0]=dynamic-zone-name`| [ダイナミックゾーンのポピュレート](/cms/api/rest/guides/understanding-populate#populate-dynamic-zones) | | ダイナミックゾーンとネスト・リレーションを、`on` で明示した戦略でポピュレート | `populate[dynamic-zone-name][on][component-category.component-name][populate][relation-name][populate][0]=field-name`| [ダイナミックゾーンのポピュレート](/cms/api/rest/guides/understanding-populate#populate-dynamic-zones) | :::tip 階層の深い `populate` は [インタラクティブなクエリビルダー](/cms/api/rest/interactive-query-builder) で組み立てるとよいです。例と説明は [REST API ガイド](/cms/api/rest/guides/intro) も参照してください。 ::: ### ポピュレートと他オペレータの併用 {#combining-population-with-other-operators} `populate` は、[フィールド選択](/cms/api/rest/populate-select#field-selection)、[フィルター](/cms/api/rest/filters)、[ソート](/cms/api/rest/sort-pagination) などと組み合わせられます。 :::note ポピュレートとページネーションのオペレータは同時に使えません。 ::: #### フィールド選択と併用 `fields` と `populate` は一緒に使えます。 #### フィルターと併用 `filters` と `populate` は一緒に使えます。 # Relations Source: https://docs.strapi.io/cms/api/rest/relations # API リクエストでのリレーション管理 コンテンツタイプ間のリレーション(データベース層ではエンティティ同士の接続)は、エンティティを相互に結びつけることです。 リレーションは [管理画面](/cms/features/content-manager#relational-fields)、[REST API](/cms/api/rest)、[Document Service API](/cms/api/document-service) のリクエストで管理できます。 Content API では、リクエストボディにパラメータを渡してリレーションを接続・切断・設定できます。このペイロードは単一エントリのリレーションとマルチリレーション(one-to-many、many-to-one、many-to-many、many-way)の両方で使えます。複数リンクを許すリレーションフィールドでは、API はリレーション ID の配列を想定し、レスポンスでも配列を返します。 | パラメータ名 | 説明 | 更新の種類 | |-------------------------|-------------|----------------| | [`connect`](#connect) | 新しいエンティティを接続します。

`disconnect` と併用できます。

[位置指定引数](#relations-reordering)と組み合わせて、リレーションの順序を定義できます。 | 部分 | | [`disconnect`](#disconnect) | エンティティの接続を切ります。

`connect` と併用できます。 | 部分 | | [`set`](#set) | 指定した集合に置き換えます。`set` を使うと、他エンティティへの既存の接続はすべて上書きされます。

`connect` や `disconnect` とは併用できません。 | 全体 | :::note マルチリレーションは REST API と [GraphQL API](/cms/api/graphql#fetch-relations) の両方で管理できます。`connect`、`disconnect`、`set` はどちらの API でも利用できます。一方、[Document Service API](/cms/api/document-service) はリレーション操作を扱いません。 ::: :::note コンテンツタイプで [Internationalization (i18n)](/cms/features/internationalization) が有効な場合、特定ロケール向けにリレーションを設定するためにロケールを渡せます。次は Document Service API の例です。 ```js await strapi.documents('api::restaurant.restaurant').update({ documentId: 'a1b2c3d4e5f6g7h8i9j0klm', locale: 'fr', data: { category: { connect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv'] } } }) ``` ロケールを省略すると既定ロケールが使われます。 ::: ## `connect` {#connect} リクエストボディで `connect` を使うと部分更新として、指定したリレーションを接続します。 `connect` には省略形と詳細形があります。 | 構文の種類 | 構文の例 | | ------------|----------------| | 省略形 | `connect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv']` | | 詳細形 | ```connect: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }]``` | 詳細形では [リレーションの並べ替え](#relations-reordering) も指定できます。 `connect` は [`disconnect`](#disconnect) と併用できます。 :::caution メディア属性への `connect` は公式にはサポートされていません。上級者向けにアップロードファイルの ID を指定して接続する方法はありますが、Strapi が推奨・保証するものではなく、下書きと公開で ID が食い違うなど簡単に壊れます。利用は自己責任で慎重に行ってください。 ::: ### リレーションの並べ替え {#relations-reordering} `position` を省略した要素(例: `{ id: 'srkvrr77k96o44d9v6ef1vu' }`)は、既定で `position: { end: true }` と同じ扱いです。他のリレーションは、既存の `id` を基準にした `after` / `before`、または一覧に対する `start` / `end` で相対的に配置されます。`connect` 配列の順に処理されるため、結果のデータベース上のレコードは次のようになります。 ```js categories: [ { id: 'nyk7047azdgbtjqhl7btuxw' }, { id: 'j9k8l7m6n5o4p3q2r1s0tuv' }, { id: '6u86wkc6x3parjd4emikhmx6' }, { id: '3r1wkvyjwv0b9b36s7hzpxl7' }, { id: 'a1b2c3d4e5f6g7h8i9j0klm' }, { id: 'rkyqa499i84197l29sbmwzl' }, { id: 'srkvrr77k96o44d9v6ef1vu9' } ] ``` ### エッジケース: 下書きと公開または i18n が無効な場合 コンテンツタイプで [下書きと公開](/cms/features/draft-and-publish) や [Internationalization (i18n)](/cms/features/internationalization) がオフになっていると、`connect` の使い方が次のように変わることがあります。 **i18n がオフの `Category` から、i18n がオンの `Article` へのリレーション:** 接続先のロケールを次のように指定できます。 ```js data: { categories: { connect: [ { documentId: 'z0y2x4w6v8u1t3s5r7q9onm', locale: 'en' }, // 同じ documentId で別ロケールに接続 👇 { documentId: 'z0y2x4w6v8u1t3s5r7q9onm', locale: 'fr' }, ] } } ``` **下書きと公開がオフの `Category` から、オンのアーティクルへのリレーション:** ```js data: { categories: { connect: [ { documentId: 'z0y2x4w6v8u1t3s5r7q9onm', status: 'draft' }, // 同じ documentId で別の公開状態に接続 👇 { documentId: 'z0y2x4w6v8u1t3s5r7q9onm', status: 'published' }, ] } } ``` ## `disconnect` {#disconnect} リクエストボディで `disconnect` を使うと部分更新として、指定したリレーションの接続を切ります。 `disconnect` にも省略形と詳細形があります。 | 構文の種類 | 構文の例 | | ------------|----------------| | 省略形 | `disconnect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv']` | 詳細形 | ```disconnect: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }]``` | `disconnect` は [`connect`](#connect) と併用できます。
## `set` {#set} `set` は全体更新で、既存のリレーションをすべて、指定した順序の集合に置き換えます。 `set` には省略形と詳細形があります。 | 構文の種類 | 構文の例 | | ----------- | ------------------------------- | | 省略形 | `set: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv']` | | 詳細形 | ```set: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }]``` | `set` は既存をすべて置き換えるため、他パラメータと併用しないでください。部分更新には [`connect`](#connect) と [`disconnect`](#disconnect) を使います。 :::note `set` を省略する場合 パラメータを省略するのは `set` を使うのと同じです。
例えば次の 3 つはいずれも同じ意味です。 - `data: { categories: set: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }] }}` - `data: { categories: set: ['z0y2x4w6v8u1t3s5r7q9onm2', 'j9k8l7m6n5o4p3q2r1s0tuv'] }}` - `data: { categories: ['z0y2x4w6v8u1t3s5r7q9onm2', 'j9k8l7m6n5o4p3q2r1s0tuv'] }` ::: # Sort and Pagination Source: https://docs.strapi.io/cms/api/rest/sort-pagination # REST API: ソートとページネーション [REST API](/cms/api/rest) のクエリ結果は、ソートとページネーションができます。 :::tip
JavaScript のクエリ(qs ライブラリで組み立て): ### 例: 2 フィールドでソートし、昇順・降順を指定 各フィールドに `:asc` または `:desc` を付けて、希望の順序にします。
JavaScript のクエリ(qs ライブラリで組み立て): ## ページネーション {#pagination} クエリでは `pagination` パラメータを使えます。次のいずれかの方法です。 - [ページ番号](#pagination-by-page)(ページ番号と 1 ページあたりの件数) - [オフセット](#pagination-by-offset)(スキップ件数と取得件数) :::note ページネーションの方式は混在させられません。`page` と `pageSize`、**または** `start` と `limit` のどちらか一方だけを使ってください。 ::: ### ページ番号によるページネーション {#pagination-by-page} ページ番号で区切るには次のパラメータを使います。 | パラメータ | 型 | 説明 | 既定値 | | ----------------------- | ------- | ------------------------------------------------------------------------- | ------- | | `pagination[page]` | Integer | ページ番号 | 1 | | `pagination[pageSize]` | Integer | 1 ページあたりの件数 | 25 | | `pagination[withCount]` | Boolean | レスポンスにエントリ総数とページ数を含めるか | True |
JavaScript のクエリ(qs ライブラリで組み立て): ### オフセットによるページネーション {#pagination-by-offset} オフセットで区切るには次のパラメータを使います。 | パラメータ | 型 | 説明 | 既定値 | | ----------------------- | ------- | -------------------------------------------------------------- | ------- | | `pagination[start]` | Integer | 開始位置(返す最初のエントリのオフセット) | 0 | | `pagination[limit]` | Integer | 返すエントリ数 | 25 | | `pagination[withCount]` | Boolean | レスポンスにエントリ総数を含めるか | `true` | :::tip `pagination[limit]` の既定値と最大値は、[`./config/api.js`](/cms/configurations/api) の `api.rest.defaultLimit` と `api.rest.maxLimit` で設定できます。 :::
JavaScript のクエリ(qs ライブラリで組み立て): # Status Source: https://docs.strapi.io/cms/api/rest/status # REST API: `status` [REST API](/cms/api/rest) では、ドキュメントの状態(下書きまたは公開)に応じて結果を絞り込めます。 :::prerequisites [下書きと公開](/cms/features/draft-and-publish) 機能が有効になっている必要があります。 ::: クエリでは `status` パラメータで次のように取得できます。 - `published`: 公開版のドキュメントのみ(既定) - `draft`: 下書き版のドキュメントのみ :::tip レスポンスの `data` では、下書きの `publishedAt` は `null` です。 ::: :::note 公開版が既定で返るため、`status` を省略するのは `status=published` と同じ扱いです。 :::

JavaScript のクエリ(qs ライブラリで組み立て): # Upload files Source: https://docs.strapi.io/cms/api/rest/upload # REST API: ファイルのアップロード [メディアライブラリ](/cms/features/media-library) は、Strapi のバックエンドで `upload` パッケージによって動作します。ファイルをアップロードするには、管理画面のメディアライブラリを使うか、[REST API](/cms/api/rest) の次のエンドポイントを使います。 | メソッド | パス | 説明 | | :----- | :---------------------- | :------------------ | | GET | `/api/upload/files` | ファイル一覧を取得 | | GET | `/api/upload/files/:id` | 特定のファイルを取得 | | POST | `/api/upload` | ファイルをアップロード | | POST | `/api/upload?id=x` | fileInfo を更新 | | DELETE | `/api/upload/files/:id` | ファイルを削除 | :::note メモ - [フォルダ](/cms/features/media-library#organizing-assets-with-folders) は管理画面専用で、Content API(REST / GraphQL)には含まれません。REST でアップロードしたファイルは、自動で作成される「API Uploads」フォルダに置かれます。 - GraphQL API ではメディアのアップロードに対応していません。アップロードは REST API を使うか、管理画面の [メディアライブラリ](/cms/features/media-library) から行ってください。アップロード済みメディアの更新・削除用の GraphQL ミューテーションは利用できます(詳しくは [GraphQL API のドキュメント](/cms/api/graphql#mutations-on-media-files) を参照)。 ::: ## ファイルをアップロード {#upload-files} 1 件または複数のファイルをアプリケーションにアップロードします。 受け付けるパラメータは `files` のみで、アップロードするファイルを表します。値は Buffer または Stream にできます。 :::tip 画像をアップロードするときは、`fileInfo` オブジェクトでファイル名、代替テキスト、キャプションを指定できます。 ::: :::caution リクエストボディには FormData を送る必要があります。 ::: ## エントリに紐づくファイルをアップロード 特定のエントリにリンクされる 1 件または複数のファイルをアップロードします。 利用できるパラメータは次のとおりです。 | パラメータ | 説明 | | --------- | ----------- | |`files` | アップロードするファイル。値は Buffer または Stream にできます。 | |`path`(任意) | ファイルを置くフォルダ(strapi-provider-upload-aws-s3 のみサポート)。 | | `refId` | ファイルを紐づけるエントリの ID。 | | `ref` | ファイルを紐づけるモデルの一意 ID(uid)。詳しくは下記。 | | `source`(任意) | モデルが属するプラグイン名。 | | `field` | ファイルを紐づけるエントリ上のフィールド名。 | 例として、`Restaurant` モデルの属性が次のとき: ```json title="/src/api/restaurant/content-types/restaurant/schema.json" { // ... "attributes": { "name": { "type": "string" }, "cover": { "type": "media", "multiple": false, } } // ... } ``` 対応するフロントエンドの例: ```html
``` :::caution リクエストボディには FormData を送る必要があります。 ::: ## fileInfo を更新 アプリケーション内のファイル情報を更新します。 受け付けるパラメータは `fileInfo` のみで、更新する内容を表します。 ```js const fileId = 50; const newFileData = { alternativeText: 'My new alternative text for this image!', }; const form = new FormData(); form.append('fileInfo', JSON.stringify(newFileData)); const response = await fetch(`http://localhost:1337/api/upload?id=${fileId}`, { method: 'post', body: form, }); ``` ## モデル定義 [モデル](/cms/backend-customization/models)(または別プラグインのモデル)にファイル属性を追加するのは、新しい関連付けを追加するのと同様です。 次の例では、`avatar` に 1 ファイルをアップロードして紐づけます。 ```json title="/src/api/restaurant/content-types/restaurant/schema.json" { // ... { "attributes": { "pseudo": { "type": "string", "required": true }, "email": { "type": "email", "required": true, "unique": true }, "avatar": { "type": "media", "multiple": false, } } } // ... } ``` 次の例では、`restaurant` コンテンツタイプに複数画像をアップロードして紐づけます。 ```json title="/src/api/restaurant/content-types/restaurant/schema.json" { // ... { "attributes": { "name": { "type": "string", "required": true }, "covers": { "type": "media", "multiple": true, } } } // ... } ``` # Back-end customization Source: https://docs.strapi.io/cms/backend-customization
# Backend customization :::strapi Disambiguation: Strapi back end As a headless CMS, the Strapi software as a whole can be considered as the "back end" of your website or application. But the Strapi software itself includes 2 different parts: - The **back-end** part of Strapi is an HTTP server that Strapi runs. Like any HTTP server, the Strapi back end receives requests and send responses. Your content is stored in a database, and the Strapi back end interacts with the database to create, retrieve, update, and delete content. - The **front-end** part of Strapi is called the admin panel. The admin panel presents a graphical user interface to help you structure and manage the content. Throughout this developer documentation, 'back end' refers _exclusively_ to the back-end part of Strapi. The [Getting Started > Admin panel page](/cms/features/admin-panel) gives an admin panel overview and the [admin panel customization section](/cms/admin-panel-customization) details the various customization options available for the admin panel. ::: The Strapi back end runs an HTTP server based on , a back-end JavaScript framework. Like any HTTP server, the Strapi back end receives requests and send responses. You can send requests to the Strapi back end to create, retrieve, update, or delete data through the [REST](/cms/api/rest) or [GraphQL](/cms/api/graphql) APIs. A request can travel through the Strapi back end as follows: 1. The Strapi server receives a [request](/cms/backend-customization/requests-responses). 2. The request hits [global middlewares](/cms/backend-customization/middlewares) that are run in a sequential order. 3. The request hits a [route](/cms/backend-customization/routes).
By default, Strapi generates route files for all the content-types that you create (see [REST API documentation](/cms/api/rest)), and more routes can be added and configured. 4. [Route policies](/cms/backend-customization/policies) act as a read-only validation step that can block access to a route. [Route middlewares](/cms/backend-customization/routes#middlewares) can control the request flow and mutate the request itself before moving forward. 5. [Controllers](/cms/backend-customization/controllers) execute code once a route has been reached. [Services](/cms/backend-customization/services) are optional, additional code that can be used to build custom logic reusable by controllers. 6. The code executed by the controllers and services interacts with the [models](/cms/backend-customization/models) that are a representation of the content content structure stored in the database.
Interacting with the data represented by the models is handled by the [Document Service](/cms/api/document-service) and [Query Engine](/cms/api/query-engine). 7. You can implement [Document Service middlewares](/cms/api/document-service/middlewares) to control the data before it's sent to the Query Engine. The Query Engine can also use lifecycle hooks though we recommend you use Document Service middlewares unless you absolutely need to directly interact with the database. 7. The server returns a [response](/cms/backend-customization/requests-responses). The response can travel back through route middlewares and global middlewares before being sent. Both global and route middlewares include an asynchronous callback function, `await next()`. Depending on what is returned by the middleware, the request will either go through a shorter or longer path through the back end: * If a middleware returns nothing, the request will continue travelling through the various core elements of the back end (i.e., controllers, services, and the other layers that interact with the database). * If a middleware returns before calling `await next()`, a response will be immediately sent, skipping the rest of the core elements. Then it will go back down the same chain it came up. :::info Please note that all customizations described in the pages of this section are only for the REST API. [GraphQL customizations](/cms/plugins/graphql#customization) are described in the GraphQL plugin documentation. ::: ## Interactive diagram The following diagram represents how requests travel through the Strapi back end. You can click on any shape to jump to the relevant page in the documentation.
# Controllers Source: https://docs.strapi.io/cms/backend-customization/controllers # Controllers Controllers are JavaScript files that contain a set of methods, called actions, reached by the client according to the requested [route](/cms/backend-customization/routes). Whenever a client requests the route, the action performs the business logic code and sends back the [response](/cms/backend-customization/requests-responses). Controllers represent the C in the model-view-controller (MVC) pattern. In most cases, the controllers will contain the bulk of a project's business logic. But as a controller's logic becomes more and more complicated, it's a good practice to use [services](/cms/backend-customization/services) to organize the code into re-usable parts.
Simplified Strapi backend diagram with controllers highlighted
The diagram represents a simplified version of how a request travels through the Strapi back end, with controllers highlighted. The backend customization introduction page includes a complete, interactive diagram.
:::caution Sanitize inputs and outputs When overriding core actions, always validate and sanitize queries and responses to avoid leaking private fields or bypassing access rules. Use `validateQuery` (optional), `sanitizeQuery` (recommended), and `sanitizeOutput` before returning data from custom actions. See the example below for a safe `find` override. ::: ## Implementation Controllers can be [generated or added manually](#adding-a-new-controller). Strapi provides a `createCoreController` factory function that automatically generates core controllers and allows building custom ones or [extend or replace the generated controllers](#extending-core-controllers). ### Adding a new controller A new controller can be implemented: - with the [interactive CLI command `strapi generate`](/cms/cli) - or manually by creating a JavaScript file: - in `./src/api/[api-name]/controllers/` for API controllers (this location matters as controllers are auto-loaded by Strapi from there) - or in a folder like `./src/plugins/[plugin-name]/server/controllers/` for plugin controllers, though they can be created elsewhere as long as the plugin interface is properly exported in the `strapi-server.js` file (see [Server API for Plugins documentation](/cms/plugins-development/server-api)) Each controller action can be an `async` or `sync` function. Every action receives a context object (`ctx`) as a parameter. `ctx` contains the [request context](/cms/backend-customization/requests-responses#ctxrequest) and the [response context](/cms/backend-customization/requests-responses#ctxresponse).
Example: GET /hello route calling a basic controller A specific `GET /hello` [route](/cms/backend-customization/routes) is defined, the name of the router file (i.e. `index`) is used to call the controller handler (i.e. `index`). Every time a `GET /hello` request is sent to the server, Strapi calls the `index` action in the `hello.js` controller, which returns `Hello World!`:
:::note When a new [content-type](/cms/backend-customization/models#content-types) is created, Strapi builds a generic controller with placeholder code, ready to be customized. ::: :::tip To see a possible advanced usage for custom controllers, read the [services and controllers](/cms/backend-customization/examples/services-and-controllers) page of the backend customization examples cookbook. ::: ### Controllers & Routes: How routes reach controller actions - Core mapping is automatic: when you generate a content-type, Strapi creates the matching controller and a router file that already targets the standard actions (`find`, `findOne`, `create`, `update`, and `delete`). Overriding any of these actions inside the generated controller does not require touching the router — the route keeps the same handler string and executes your updated logic. - Adding a route should only be done for new actions or paths. If you introduce a brand-new method such as `exampleAction`, create or update a route entry whose `handler` points to the action so HTTP requests can reach it. Use the fully-qualified handler syntax `::..` (e.g. `api::restaurant.restaurant.exampleAction` for an API controller or `plugin::menus.menu.exampleAction` for a plugin controller). - Regarding controller and route filenames: the default controller name comes from the filename inside `./src/api/[api-name]/controllers/`. Core routers created with `createCoreRouter` adopt the same name, so the generated handler string matches automatically. Custom routers can follow any file naming scheme, as long as the `handler` string references an exported controller action. The example below adds a new controller action and exposes it through a custom route without duplicating the existing CRUD route definitions: ```js title="./src/api/restaurant/controllers/restaurant.js" const { createCoreController } = require('@strapi/strapi').factories; module.exports = createCoreController('api::restaurant.restaurant', ({ strapi }) => ({ async exampleAction(ctx) { const specials = await strapi.service('api::restaurant.restaurant').find({ filters: { isSpecial: true } }); return this.transformResponse(specials.results); }, })); ``` ```js title="./src/api/restaurant/routes/01-custom-restaurant.js" module.exports = { routes: [ { method: 'GET', path: '/restaurants/specials', handler: 'api::restaurant.restaurant.exampleAction', }, ], }; ``` ### Sanitization and Validation in controllers {#sanitization-and-validation-in-controllers} :::warning It's strongly recommended you sanitize (v4.8.0+) and/or validate (v4.13.0+) your incoming request query utilizing the new `sanitizeQuery` and `validateQuery` functions to prevent the leaking of private data. ::: Sanitization means that the object is “cleaned” and returned. Validation means an assertion is made that the data is already clean and throws an error if something is found that shouldn't be there. In Strapi 5, both query parameters and input data (i.e., create and update body data) are validated. Any create and update data requests with the following invalid input will throw a `400 Bad Request` error: - relations the user do not have permission to create - unrecognized values that are not present on a schema - non-writable fields and internal timestamps like `createdAt` and `createdBy` fields - setting or updating an `id` field (except for connecting relations) #### Sanitization when utilizing controller factories Within the Strapi factories the following functions are exposed that can be used for sanitization and validation: | Function Name | Parameters | Description | |------------------|----------------------------|--------------------------------------------------------------------------------------| | `sanitizeQuery` | `ctx` | Sanitizes the request query | | `sanitizeOutput` | `entity`/`entities`, `ctx` | Sanitizes the output data where entity/entities should be an object or array of data | | `sanitizeInput` | `data`, `ctx` | Sanitizes the input data | | `validateQuery` | `ctx` | Validates the request query (throws an error on invalid params) | | `validateInput` | `data`, `ctx` | (EXPERIMENTAL) Validates the input data (throws an error on invalid data) | These functions automatically inherit the sanitization settings from the model and sanitize the data accordingly based on the content-type schema and any of the content API authentication strategies, such as the Users & Permissions plugin or API tokens. :::warning Because these methods use the model associated with the current controller, if you query data that is from another model (i.e., doing a find for "menus" within a "restaurant" controller method), you must instead use the `strapi.contentAPI` methods, such as `strapi.contentAPI.sanitize.query` described in [Sanitizing Custom Controllers](#sanitize-validate-custom-controllers), or else the result of your query will be sanitized against the wrong model. ::: #### Sanitization and validation when building custom controllers {#sanitize-validate-custom-controllers} Within custom controllers, Strapi exposes the following functions via `strapi.contentAPI` for sanitization and validation. To add custom query or body parameters to Content API routes (e.g. in `register`), see [Custom Content API parameters](/cms/backend-customization/routes#custom-content-api-parameters). | Function Name | Parameters | Description | |------------------------------|--------------------|---------------------------------------------------------| | `strapi.contentAPI.sanitize.input` | `data`, `schema`, `auth` | Sanitizes the request input including non-writable fields, removing restricted relations, and other nested "visitors" added by plugins | | `strapi.contentAPI.sanitize.output` | `data`, `schema`, `auth` | Sanitizes the response output including restricted relations, private fields, passwords, and other nested "visitors" added by plugins | | `strapi.contentAPI.sanitize.query` | `ctx.query`, `schema`, `auth` | Sanitizes the request query including filters, sort, fields, and populate | | `strapi.contentAPI.validate.query` | `ctx.query`, `schema`, `auth` | Validates the request query including filters, sort, fields (currently not populate) | | `strapi.contentAPI.validate.input` | `data`, `schema`, `auth` | (EXPERIMENTAL) Validates the request input including non-writable fields, removing restricted relations, and other nested "visitors" added by plugins | :::note Depending on the complexity of your custom controllers, you may need additional sanitization that Strapi cannot currently account for, especially when combining the data from multiple sources. ::: ### Extending core controllers {#extending-core-controllers} Default controllers and actions are created for each content-type. These default controllers are used to return responses to API requests (e.g. when `GET /api/articles/3` is accessed, the `findOne` action of the default controller for the "Article" content-type is called). Default controllers can be customized to implement your own logic. The following code examples should help you get started. :::tip An action from a core controller can be replaced entirely by [creating a custom action](#adding-a-new-controller) and naming the action the same as the original action (e.g. `find`, `findOne`, `create`, `update`, or `delete`). ::: :::tip When extending a core controller, you do not need to re-implement any sanitization as it will already be handled by the core controller you are extending. Where possible it's strongly recommended to extend the core controller instead of creating a custom controller. :::
Collection type examples :::tip The [backend customization examples cookbook](/cms/backend-customization/examples) shows how you can overwrite a default controller action, for instance for the [`create` action](/cms/backend-customization/examples/services-and-controllers#custom-controller). :::
Single type examples
## Usage Controllers are declared and attached to a route. Controllers are automatically called when the route is called, so controllers usually do not need to be called explicitly. However, [services](/cms/backend-customization/services) can call controllers, and in this case the following syntax should be used: ```js // access an API controller strapi.controller('api::api-name.controller-name'); // access a plugin controller strapi.controller('plugin::plugin-name.controller-name'); ``` :::tip To list all the available controllers, run `yarn strapi controllers:list`. ::: # Middlewares Source: https://docs.strapi.io/cms/backend-customization/middlewares # Middlewares customization Globally scoped custom middlewares should be added to the [middlewares configuration file](/cms/configurations/middlewares#loading-order) or Strapi won't load them. API level and plugin middlewares can be added into the specific router that they are relevant to like the following: ```js title="./src/api/[api-name]/routes/[collection-name].js or ./src/plugins/[plugin-name]/server/routes/index.js" module.exports = { routes: [ { method: "GET", path: "/[collection-name]", handler: "[controller].find", config: { middlewares: ["[middleware-name]"], // See the usage section below for middleware naming conventions }, }, ], }; ```
Example of a custom timer middleware
The GraphQL plugin also allows [implementing custom middlewares](/cms/plugins/graphql#middlewares), with a different syntax. :::tip Discover loaded middlewares Run `yarn strapi middlewares:list` to list all registered middlewares and double‑check naming when wiring them in routers. ::: ## Usage Middlewares are called different ways depending on their scope: - use `global::middleware-name` for application-level middlewares - use `api::api-name.middleware-name` for API-level middlewares - use `plugin::plugin-name.middleware-name` for plugin middlewares :::tip To list all the registered middlewares, run `yarn strapi middlewares:list`. ::: ### Restricting content access with an "is-owner policy" It is often required that the author of an entry is the only user allowed to edit or delete the entry. In previous versions of Strapi, this was known as an "is-owner policy". With Strapi v4, the recommended way to achieve this behavior is to use a middleware. Proper implementation largely depends on your project's needs and custom code, but the most basic implementation could be achieved with the following procedure: 1. From your project's folder, create a middleware with the Strapi CLI generator, by running the `yarn strapi generate` (or `npm run strapi generate`) command in the terminal. 2. Select `middleware` from the list, using keyboard arrows, and press Enter. 3. Give the middleware a name, for instance `isOwner`. 4. Choose `Add middleware to an existing API` from the list. 5. Select which API you want the middleware to apply. 6. Replace the code in the `/src/api/[your-api-name]/middlewares/isOwner.js` file with the following, replacing `api::restaurant.restaurant` in line 22 with the identifier corresponding to the API you choose at step 5 (e.g., `api::blog-post.blog-post` if your API name is `blog-post`): ```js showLineNumbers title="src/api/blog-post/middlewares/isOwner.js" "use strict"; /** * `isOwner` middleware */ module.exports = (config, { strapi }) => { // Add your own logic here. return async (ctx, next) => { const user = ctx.state.user; const entryId = ctx.params.id ? ctx.params.id : undefined; let entry = {}; /** * Gets all information about a given entry, * populating every relations to ensure * the response includes author-related information */ if (entryId) { entry = await strapi.documents('api::restaurant.restaurant').findOne( entryId, { populate: "*" } ); } /** * Compares user id and entry author id * to decide whether the request can be fulfilled * by going forward in the Strapi backend server */ if (user.id !== entry.author.id) { return ctx.unauthorized("This action is unauthorized."); } else { return next(); } }; }; ``` 7. Ensure the middleware is configured to apply on some routes. In the `config` object found in the `src/api/[your-api–name]/routes/[your-content-type-name].js` file, define the action keys (`find`, `findOne`, `create`, `update`, `delete`, etc.) for which you would like the middleware to apply, and declare the `isOwner` middleware for these routes.

For instance, if you wish to allow GET requests (mapping to the `find` and `findOne` actions) and POST requests (i.e., the `create` action) to any user for the `restaurant` content-type in the `restaurant` API, but would like to restrict PUT (i.e., `update` action) and DELETE requests only to the user who created the entry, you could use the following code in the `src/api/restaurant/routes/restaurant.js` file: ```js title="src/api/restaurant/routes/restaurant.js" /** * restaurant router */ const { createCoreRouter } = require("@strapi/strapi").factories; module.exports = createCoreRouter("api::restaurant.restaurant", { config: { update: { middlewares: ["api::restaurant.is-owner"], }, delete: { middlewares: ["api::restaurant.is-owner"], }, }, }); ``` :::info You can find more information about route middlewares in the [routes documentation](/cms/backend-customization/routes). ::: # Models Source: https://docs.strapi.io/cms/backend-customization/models # Models As Strapi is a headless Content Management System (CMS), creating a content structure for the content is one of the most important aspects of using the software. Models define a representation of the content structure. There are 2 different types of models in Strapi: - content-types, which can be collection types or single types, depending on how many entries they manage, - and components that are content structures re-usable in multiple content-types. If you are just starting out, it is convenient to generate some models with the [Content-type Builder](/cms/features/content-type-builder) directly in the admin panel. The user interface takes over a lot of validation tasks and showcases all the options available to create the content's content structure. The generated model mappings can then be reviewed at the code level using this documentation. ## Model creation Content-types and components models are created and stored differently. ### Content-types Content-types in Strapi can be created: - with the [Content-type Builder in the admin panel](/cms/features/content-type-builder), - or with [Strapi's interactive CLI `strapi generate`](/cms/cli#strapi-generate) command. The content-types use the following files: - `schema.json` for the model's [schema](#model-schema) definition. (generated automatically, when creating content-type with either method) - `lifecycles.js` for [lifecycle hooks](#lifecycle-hooks). This file must be created manually. These models files are stored in `./src/api/[api-name]/content-types/[content-type-name]/`, and any JavaScript or JSON file found in these folders will be loaded as a content-type's model (see [project structure](/cms/project-structure)). :::note In [TypeScript](/cms/typescript.md)-enabled projects, schema typings can be generated using the `ts:generate-types` command. ::: ### Components {#components-creation} Component models can't be created with CLI tools. Use the [Content-type Builder](/cms/features/content-type-builder) or create them manually. Components models are stored in the `./src/components` folder. Every component has to be inside a subfolder, named after the category the component belongs to (see [project structure](/cms/project-structure)). ## Model schema The `schema.json` file of a model consists of: - [settings](#model-settings), such as the kind of content-type the model represents or the table name in which the data should be stored, - [information](#model-information), mostly used to display the model in the admin panel and access it through the REST and GraphQL APIs, - [attributes](#model-attributes), which describe the content structure of the model, - and [options](#model-options) used to defined specific behaviors on the model. ### Model settings General settings for the model can be configured with the following parameters: | Parameter | Type | Description | | -------------------------------------------- | ------ | ---------------------------------------------------------------------------------------------------------------------- | | `collectionName` | String | Database table name in which the data should be stored | | `kind`

_Optional,
only for content-types_ | String | Defines if the content-type is:
  • a collection type (`collectionType`)
  • or a single type (`singleType`)
| ```json // ./src/api/[api-name]/content-types/restaurant/schema.json { "kind": "collectionType", "collectionName": "Restaurants_v1", } ``` ### Model information The `info` key in the model's schema describes information used to display the model in the admin panel and access it through the Content API. It includes the following parameters: | Parameter | Type | Description | | -------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------- | | `displayName` | String | Default name to use in the admin panel | | `singularName` | String | Singular form of the content-type name.
Used to generate the API routes and databases/tables collection.

Should be kebab-case. | | `pluralName` | String | Plural form of the content-type name.
Used to generate the API routes and databases/tables collection.

Should be kebab-case. | | `description` | String | Description of the model | ```json title="./src/api/[api-name]/content-types/restaurant/schema.json" "info": { "displayName": "Restaurant", "singularName": "restaurant", "pluralName": "restaurants", "description": "" }, ``` ### Model attributes The content structure of a model consists of a list of attributes. Each attribute has a `type` parameter, which describes its nature and defines the attribute as a simple piece of data or a more complex structure used by Strapi. Many types of attributes are available: - scalar types (e.g. strings, dates, numbers, booleans, etc.), - Strapi-specific types, such as: - `media` for files uploaded through the [Media library](/cms/features/content-type-builder#media) - `relation` to describe a [relation](#relations) between content-types - `customField` to describe [custom fields](#custom-fields) and their specific keys - `component` to define a [component](#components-json) (i.e. a content structure usable in multiple content-types) - `dynamiczone` to define a [dynamic zone](#dynamic-zones) (i.e. a flexible space based on a list of components) - and the `locale` and `localizations` types, only used by the [Internationalization (i18n) plugin](/cms/features/internationalization) The `type` parameter of an attribute should be one of the following values: | Type categories | Available types | |------|-------| | String types |
  • `string`
  • `text`
  • `richtext`
  • `enumeration`
  • `email`
  • `password`
  • [`uid`](#uid-type)
| | Date types |
  • `date`
  • `time`
  • `datetime`
  • `timestamp`
| | Number types |
  • `integer`
  • `biginteger`
  • `float`
  • `decimal`
| | Other generic types |
  • `boolean`
  • `json`
| | Special types unique to Strapi |
  • `media`
  • [`relation`](#relations)
  • [`customField`](#custom-fields)
  • [`component`](#components-json)
  • [`dynamiczone`](#dynamic-zones)
| | Internationalization (i18n)-related types

_Can only be used if the [i18n](/cms/features/internationalization) is enabled on the content-type_|
  • `locale`
  • `localizations`
| #### Validations Basic validations can be applied to attributes using the following parameters: | Parameter | Type | Description | Default | | -------------- | ------- | --------------------------------------------------------------------------------------------------------- | ------- | | `required` | Boolean | If `true`, adds a required validator for this property | `false` | | `max` | Integer | Checks if the value is greater than or equal to the given maximum | - | | `min` | Integer | Checks if the value is less than or equal to the given minimum | - | | `minLength` | Integer | Minimum number of characters for a field input value | - | | `maxLength` | Integer | Maximum number of characters for a field input value | - | | `private` | Boolean | If `true`, the attribute will be removed from the server response.

💡 This is useful to hide sensitive data. | `false` | | `configurable` | Boolean | If `false`, the attribute isn't configurable from the Content-type Builder plugin. | `true` | ```json title="./src/api/[api-name]/content-types/restaurant/schema.json" { // ... "attributes": { "title": { "type": "string", "minLength": 3, "maxLength": 99, "unique": true }, "description": { "default": "My description", "type": "text", "required": true }, "slug": { "type": "uid", "targetField": "title" } // ... } } ``` #### Database validations and settings :::caution 🚧 This API is considered experimental. These settings should be reserved to an advanced usage, as they might break some features. There are no plans to make these settings stable. ::: Database validations and settings are custom options passed directly onto the `tableBuilder` Knex.js function during schema migrations. Database validations allow for an advanced degree of control for setting custom column settings. The following options are set in a `column: {}` object per attribute: | Parameter | Type | Description | Default | | ------------- | ------- | --------------------------------------------------------------------------------------------- | ------- | | `name` | string | Changes the name of the column in the database | - | | `defaultTo` | string | Sets the database `defaultTo`, typically used with `notNullable` | - | | `notNullable` | boolean | Sets the database `notNullable`, ensures that columns cannot be null | `false` | | `unsigned` | boolean | Only applies to number columns, removes the ability to go negative but doubles maximum length | `false` | | `unique` | boolean | Enforces database-level uniqueness on published entries. Draft saves skip the check when Draft & Publish is enabled, so duplicates fail only at publish time. | `false` | | `type` | string | Changes the database type, if `type` has arguments, you should pass them in `args` | - | | `args` | array | Arguments passed into the Knex.js function that changes things like `type` | `[]` | :::caution Draft & Publish and `unique` When [Draft & Publish](/cms/features/draft-and-publish) is enabled, Strapi intentionally skips `unique` validations while an entry is saved as a draft. Duplicates therefore remain undetected until publication, at which point the database constraint triggers an error even though the UI previously displayed “Saved document” for the drafts. To avoid unexpected publication failures: - disable Draft & Publish on content-types that must stay globally unique, - or add custom validation (e.g. lifecycle hooks or middleware) that checks for draft duplicates before saving, - or rely on automatically generated unique identifiers such as a `uid` field and document editorial conventions. ::: ```json title="./src/api/[api-name]/content-types/restaurant/schema.json" { // ... "attributes": { "title": { "type": "string", "minLength": 3, "maxLength": 99, "unique": true, "column": { "unique": true // enforce database unique also } }, "description": { "default": "My description", "type": "text", "required": true, "column": { "defaultTo": "My description", // set database level default "notNullable": true // enforce required at database level, even for drafts } }, "rating": { "type": "decimal", "default": 0, "column": { "defaultTo": 0, "type": "decimal", // using the native decimal type but allowing for custom precision "args": [ 6,1 // using custom precision and scale ] } } // ... } } ``` #### `uid` type The `uid` type is used to automatically prefill the field value in the admin panel with a unique identifier (UID) (e.g. slugs for articles) based on 2 optional parameters: - `targetField` (string): If used, the value of the field defined as a target is used to auto-generate the UID. - `options` (string): If used, the UID is generated based on a set of options passed to #### Custom fields [Custom fields](/cms/features/custom-fields) extend Strapi’s capabilities by adding new types of fields to content-types. Custom fields are explicitly defined in the [attributes](#model-attributes) of a model with `type: customField`. Custom fields' attributes also show the following specificities: - a `customField` attribute whose value acts as a unique identifier to indicate which registered custom field should be used. Its value follows: - either the `plugin::plugin-name.field-name` format if a plugin created the custom field - or the `global::field-name` format for a custom field specific to the current Strapi application - and additional parameters depending on what has been defined when registering the custom field (see [custom fields documentation](/cms/features/custom-fields)). ```json title="./src/api/[apiName]/[content-type-name]/content-types/schema.json" { // … "attributes": { "attributeName": { // attributeName would be replaced by the actual attribute name "type": "customField", "customField": "plugin::color-picker.color", "options": { "format": "hex" } } } // … } ``` #### Components {#components-json} Component fields create a relation between a content-type and a component structure. Components are explicitly defined in the [attributes](#model-attributes) of a model with `type: 'component'` and accept the following additional parameters: | Parameter | Type | Description | | ------------ | ------- | ---------------------------------------------------------------------------------------- | | `repeatable` | Boolean | Could be `true` or `false` depending on whether the component is repeatable or not | | `component` | String | Define the corresponding component, following this format:
`.` | ```json title="./src/api/[apiName]/restaurant/content-types/schema.json" { "attributes": { "openinghours": { "type": "component", "repeatable": true, "component": "restaurant.openinghours" } } } ``` #### Dynamic zones Dynamic zones create a flexible space in which to compose content, based on a mixed list of [components](#components-json). Dynamic zones are explicitly defined in the [attributes](#model-attributes) of a model with `type: 'dynamiczone'`. They also accept a `components` array, where each component should be named following this format: `.`. ```json title="./src/api/[api-name]/content-types/article/schema.json" { "attributes": { "body": { "type": "dynamiczone", "components": ["article.slider", "article.content"] } } } ``` ### Model options The `options` key is used to define specific behaviors and accepts the following parameter: | Parameter | Type | Description | |---------------------|------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `privateAttributes` | Array of strings | Allows treating a set of attributes as private, even if they're not actually defined as attributes in the model. It could be used to remove them from API responses timestamps.

The `privateAttributes` defined in the model are merged with the `privateAttributes` defined in the global Strapi configuration. | | `draftAndPublish` | Boolean | Enables the draft and publish feature.

Default value: `true` (`false` if the content-type is created from the interactive CLI). | | `populateCreatorFields` | Boolean | Populates `createdBy` and `updatedBy` fields in responses returned by the REST API (see [guide](/cms/api/rest/guides/populate-creator-fields) for more details).

Default value: `false`. | ```json title="./src/api/[api-name]/content-types/restaurant/schema.json" { "options": { "privateAttributes": ["id", "createdAt"], "draftAndPublish": true } } ``` ### Plugin options `pluginOptions` is an optional object allowing plugins to store configuration for a model or a specific attribute. | Key | Value | Description | |---------------------------|-------------------------------|--------------------------------------------------------| | `i18n` | `localized: true` | Enables localization. | | `content-manager` | `visible: false` | Hides from Content Manager in the admin panel. | | `content-type-builder` | `visible: false` | Hides from Content-type Builder in the admin panel. | ```json title="./src/api/[api-name]/content-types/[content-type-name]/schema.json" { "attributes": { "name": { "pluginOptions": { "i18n": { "localized": true } }, "type": "string", "required": true }, "slug": { "pluginOptions": { "i18n": { "localized": true } }, "type": "uid", "targetField": "name", "required": true } // …additional attributes } } ``` ## Lifecycle hooks Lifecycle hooks are functions that get triggered when Strapi queries are called. They are triggered automatically when managing content through the administration panel or when developing custom code using `queries`· Lifecycle hooks can be customized declaratively or programmatically. :::caution Lifecycles hooks are not triggered when using directly the Using the database layer API, it's also possible to register a subscriber and listen to events programmatically: ```js title="./src/index.js" module.exports = { async bootstrap({ strapi }) { // registering a subscriber strapi.db.lifecycles.subscribe({ models: [], // optional; beforeCreate(event) { const { data, where, select, populate } = event.params; event.state = 'doStuffAfterWards'; }, afterCreate(event) { if (event.state === 'doStuffAfterWards') { } const { result, params } = event; // do something to the result }, }); // generic subscribe for generic handling strapi.db.lifecycles.subscribe((event) => { if (event.action === 'beforeCreate') { // do something } }); } } ``` # Policies Source: https://docs.strapi.io/cms/backend-customization/policies # Policies Policies are functions that execute specific logic on each request before it reaches the [controller](/cms/backend-customization/controllers). They are mostly used for securing business logic. Each [route](/cms/backend-customization/routes) of a Strapi project can be associated to an array of policies. For example, a policy named `is-admin` could check that the request is sent by an admin user, and restrict access to critical routes. Policies can be global or scoped. [Global policies](#global-policies) can be associated to any route in the project. Scoped policies only apply to a specific [API](#api-policies) or [plugin](#plugin-policies) and should live under the corresponding `./src/api//policies/` or `./src/plugins//policies/` folder.
Simplified Strapi backend diagram with routes and policies highlighted
The diagram represents a simplified version of how a request travels through the Strapi back end, with policies and routes highlighted. The backend customization introduction page includes a complete, interactive diagram.
## Implementation A new policy can be implemented: - with the [interactive CLI command `strapi generate`](/cms/cli#strapi-generate) - or manually by creating a JavaScript file in the appropriate folder (see [project structure](/cms/project-structure)): - `./src/policies/` for global policies - `./src/api/[api-name]/policies/` for API policies - `./src/plugins/[plugin-name]/policies/` for plugin policies
Global policy implementation example: `policyContext` is a wrapper around the [controller](/cms/backend-customization/controllers) context. It adds some logic that can be useful to implement a policy for both REST and GraphQL.
Policies can be configured using a `config` object: ## Usage To apply policies to a route, add them to its configuration object (see [routes documentation](/cms/backend-customization/routes#policies)). Policies are called different ways depending on their scope: - use `global::policy-name` for [global policies](#global-policies) - use `api::api-name.policy-name` for [API policies](#api-policies) - use `plugin::plugin-name.policy-name` for [plugin policies](#plugin-policies) :::tip To list all the available policies, run `yarn strapi policies:list`. ::: ### Global policies Global policies can be associated to any route in a project. ### Plugin policies Plugins can add and expose policies to an application. For example, the [Users & Permissions feature](/cms/features/users-permissions) comes with policies to ensure that the user is authenticated or has the rights to perform an action: ### API policies API policies are associated to the routes defined in the API where they have been declared. To use a policy in another API, reference it with the following syntax: `api::[apiName].[policyName]`: # Requests and Responses Source: https://docs.strapi.io/cms/backend-customization/requests-responses # Requests and Responses The Strapi back end server is based on . When you send requests through the [REST API](/cms/api/rest), a context object (`ctx`) is passed to every element of the Strapi back end (e.g., [policies](/cms/backend-customization/policies), [controllers](/cms/backend-customization/controllers), [services](/cms/backend-customization/services)). `ctx` includes 3 main objects: - [`ctx.request`](#ctxrequest) for information about the request sent by the client making an API request, - [`ctx.state`](#ctxstate) for information about the state of the request within the Strapi back end, - and [`ctx.response`](#ctxresponse) for information about the response that the server will return. :::tip The request's context can also be accessed from anywhere in the code with the [`strapi.requestContext` function](#accessing-the-request-context-anywhere). ::: :::info In addition to the concepts and parameters described in the following documentation, you might find additional information in the , and . :::
Simplified Strapi backend diagram with requests and responses highlighted
The diagram represents a simplified version of how a request travels through the Strapi back end, with requests and responses highlighted. The backend customization introduction page includes a complete, interactive diagram.
## `ctx.request` The `ctx.request` object contains the following parameters: | Parameter | Description | Type | | --------------------- | -------------------------------------------------------------------------------------------- | -------- | | `ctx.request.body` | Parsed version of the body. | `Object` | | `ctx.request.files` | Files sent with the request. | `Array` | | `ctx.request.headers` | Headers sent with the request. | `Object` | | `ctx.request.host` | Host part of the URL, including the port. | `String` | | `ctx.request.hostname`| Host part of the URL, excluding the port. | `String` | | `ctx.request.href` | Complete URL of the requested resource, including the protocol, domain, port (if specified), path, and query parameters. | `String` | | `ctx.request.ip` | IP of the person sending the request.| `String` | | `ctx.request.ips` | When `X-Forwarded-For` is present and `app.proxy` is enabled, an array of IPs is returned, ordered from upstream to downstream.

For example if the value were "client, proxy1, proxy2", you would receive the `["client", "proxy1", "proxy2"]` array. | `Array` | | `ctx.request.method` | Request method (e.g., `GET`, `POST`). | `String` | | `ctx.request.origin` | URL part before the first `/`. | `String` | | `ctx.request.params` | Parameters sent in the URL.

For example, if the internal URL is `/restaurants/:id`, whatever you replace `:id` in the real request becomes accessible through `ctx.request.params.id`. | `Object` | | `ctx.request.path` | Path of the requested resource, excluding the query parameters. | `String` | | `ctx.request.protocol`| Protocol being used (e.g., `https` or `http`). | `String` | | `ctx.request.query` | Strapi-specific [query parameters](#ctxrequestquery). | `Object` | | `ctx.request.subdomains`| Subdomains included in the URL.

For example, if the domain is `tobi.ferrets.example.com`, the value is the following array: `["ferrets", "tobi"]`. | `Array` | | `ctx.request.url` | Path and query parameters of the requested resource, excluding the protocol, domain, and port. | `String` |
Differences between protocol, origin, url, href, path, host, and hostname : Given an API request sent to the `https://example.com:1337/api/restaurants?id=123` URL, here is what different parameters of the `ctx.request` object return: | Parameter | Returned value | | ---------- | ------------------------------------------------- | | `ctx.request.href` | `https://example.com:1337/api/restaurants?id=123` | | `ctx.request.protocol` | `https` | | `ctx.request.host` | `localhost:1337` | | `ctx.request.hostname` | `localhost` | | `ctx.request.origin` | `https://example.com:1337` | | `ctx.request.url` | `/api/restaurants?id=123` | | `ctx.request.path` | `/api/restaurants` |
### `ctx.request.query` `ctx.request` provides a `query` object that gives access to Strapi query parameters. The following table lists available parameters with a short description and a link to the relevant REST API documentation section (see [REST API parameters](/cms/api/rest/parameters) for more information): | Parameter | Description | Type | | -------------------------------------| --------------------------------------------------------------------------------------------------------------------------- | -------------------- | | `ctx.request.query`
`ctx.query` | The whole query object. | `Object` | | `ctx.request.query.sort` | Parameters to [sort the response](/cms/api/rest/sort-pagination.md#sorting) | `String` or `Array` | | `ctx.request.query.filters` | Parameters to [filter the response](/cms/api/rest/filters) | `Object` | | `ctx.request.query.populate` | Parameters to [populate relations, components, or dynamic zones](/cms/api/rest/populate-select#population) | `String` or `Object` | | `ctx.request.query.fields` | Parameters to [select only specific fields to return with the response](/cms/api/rest/populate-select#field-selection) | `Array` | | `ctx.request.query.pagination` | Parameter to [page through entries](/cms/api/rest/sort-pagination.md#pagination) | `Object` | | `ctx.request.query.publicationState` | Parameter to [select the Draft & Publish state](/cms/api/rest/status) | `String` | | `ctx.request.query.locale` | Parameter to [select one or multiple locales](/cms/api/rest/locale) | `String` or `Array` | ## `ctx.state` The `ctx.state` object gives access to the state of the request within the Strapi back end, including specific values about the [user](#ctxstateuser), [authentication](#ctxstateauth), [route](#ctxstateroute): | Parameter | Description | Type | | ---------------------------|---------------------------------------------------------------------------- | -------- | | `ctx.state.isAuthenticated`| Returns whether the current user is authenticated in any way. | `Boolean` | ### `ctx.state.user` The `ctx.state.user` object gives access to information about the user performing the request and includes the following parameters: | Parameter | Description | Type | | ----------| -------------------------------------------------------------------------------------------- | -------- | | `ctx.state.user`| User's information. Only one relation is populated. | `Object` | | `ctx.state.user.role`| The user's role | `Object` | ### `ctx.state.auth` The `ctx.state.auth` object gives access to information related to the authentication and includes the following parameters: | Parameter | Description | Type | | ------------------------------| -------------------------------------------------------------------------------------------- | -------- | | `ctx.state.auth.strategy` | Information about the currently used authentication strategy ([Users & Permissions plugin](/cms/features/users-permissions) or [API tokens](/cms/features/api-tokens)) | `Object` | | `ctx.state.auth.strategy.name`| Name of the currently used strategy | `String` | | `ctx.state.auth.credentials` | The user's credentials | `String` | ### `ctx.state.route` The `ctx.state.route` object gives access to information related to the current route and includes the following parameters: | Parameter | Description | Type | | ----------| -------------------------------------------------------------------------------------------- | -------- | | `ctx.state.route.method`| Method used to access the current route. | `String` | | `ctx.state.route.path`| Path of the current route. | `String` | | `ctx.state.route.config`| Configuration information about the current route. | `Object` | | `ctx.state.route.handler`| Handler (controller) of the current route. | `Object` | | `ctx.state.route.info`| Additional information about the current route, such as the apiName and the API request type. | `Object` | | `ctx.state.route.info.apiName`| Name of the used API. | `String` | | `ctx.state.route.info.type`| Type of the used API. | `String` | ## `ctx.response` The `ctx.response` object gives access to information related to the response that the server will return and includes the following parameters: | Parameter | Description | Type | | ----------| -------------------------------------------------------------------------------------------- | -------- | | `ctx.response.body`| Body of the response. | `Any` | | `ctx.response.status` | Status code of the response. | `Integer` | | `ctx.response.message`| Status message of the response.

By default, `response.message` is associated with `response.status`. | `String` | | `ctx.response.header`
`ctx.response.headers`| Header(s) sent with the response. | `Object` | | `ctx.response.length`| header value as a number when present, or deduces it from `ctx.body` when possible; otherwise, returns `undefined`. | `Integer` | | `ctx.response.redirect`
`ctx.response.redirect(url, [alt])` | Performs a `302` redirect to the URL. The string "back" is special-cased to provide Referrer support; when Referrer is not present, alt or "/" is used.

Example: `ctx.response.redirect('back', '/index.html');` | `Function` | | `ctx.response.attachment`

`ctx.response.attachment([filename], [options])` | Sets header to "attachment" to signal the client to prompt for download. Optionally specify the filename of the download and some . | `Function` | | `ctx.response.type`| header, void of parameters such as "charset". | `String` | | `ctx.response.lastModified`| header as a Date, if it exists. | `DateTime` | | `ctx.response.etag`| Sets the of a response including the wrapped "s.
There is no corresponding `response.etag` getter. | `String` | ## Accessing the request context anywhere Strapi exposes a way to access the current request context from anywhere in the code (e.g. lifecycle functions). You can access the request as follows: ```js const ctx = strapi.requestContext.get(); ``` You should only use this inside of functions that will be called in the context of an HTTP request. ```js // correct const service = { myFunction() { const ctx = strapi.requestContext.get(); console.log(ctx.state.user); }, }; // incorrect const ctx = strapi.requestContext.get(); const service = { myFunction() { console.log(ctx.state.user); }, }; ``` **Example:** ```js title="./api/test/content-types/article/lifecycles.js" module.exports = { beforeUpdate() { const ctx = strapi.requestContext.get(); console.log('User info in service: ', ctx.state.user); }, }; ``` :::note Strapi uses a Node.js feature called to make the context available anywhere. ::: # Routes Source: https://docs.strapi.io/cms/backend-customization/routes # Routes Requests sent to Strapi on any URL are handled by routes. By default, Strapi generates routes for all the content-types (see [REST API documentation](/cms/api/rest)). Routes can be [added](#implementation) and configured: - with [policies](#policies), which are a way to block access to a route, - and with [middlewares](#middlewares), which are a way to control and change the request flow and the request itself. Once a route exists, reaching it executes some code handled by a controller (see [controllers documentation](/cms/backend-customization/controllers)). To view all existing routes and their hierarchal order, you can run `yarn strapi routes:list` (see [CLI reference](/cms/cli)). :::tip If you only customize the default controller actions (`find`, `findOne`, `create`, `update`, or `delete`) that Strapi generates for a content-type, you can leave the router as-is. Those core routes already target the same handler names and will run your new controller logic. Add or edit a route only when you need a brand-new HTTP path/method or want to expose a custom controller action. :::
Simplified Strapi backend diagram with routes highlighted
The diagram represents a simplified version of how a request travels through the Strapi back end, with routes highlighted. The backend customization introduction page includes a complete, interactive diagram.
## Implementation Implementing a new route consists in defining it in a router file within the `./src/api/[apiName]/routes` folder (see [project structure](/cms/project-structure)). There are 2 different router file structures, depending on the use case: - configuring [core routers](#configuring-core-routers) - or creating [custom routers](#creating-custom-routers). ### Configuring core routers Core routers (i.e. `find`, `findOne`, `create`, `update`, and `delete`) correspond to [default routes](/cms/api/rest#endpoints) automatically created by Strapi when a new [content-type](/cms/backend-customization/models#model-creation) is created. Strapi provides a `createCoreRouter` factory function that automatically generates the core routers and allows: - passing in configuration options to each router - and disabling some core routers to [create custom ones](#creating-custom-routers). A core router file is a JavaScript file exporting the result of a call to `createCoreRouter` with the following parameters: | Parameter | Description | Type | | ----------| -------------------------------------------------------------------------------------------- | -------- | | `prefix` | Allows passing in a custom prefix to add to all routers for this model (e.g. `/test`) | `String` | | `only` | Core routes that will only be loaded

Anything not in this array is ignored. | `Array` | --> | `except` | Core routes that should not be loaded

This is functionally the opposite of the `only` parameter. | `Array` | | `config` | Configuration to handle [policies](#policies), [middlewares](#middlewares) and [public availability](#public-routes) for the route | `Object` |

Generic implementation example: This only allows a `GET` request on the `/restaurants` path from the core `find` [controller](/cms/backend-customization/controllers) without authentication. When you reference custom controller actions in custom routers, prefer the fully‑qualified `api::..` form for clarity (e.g., `api::restaurant.restaurant.review`). ### Creating custom routers Creating custom routers consists in creating a file that exports an array of objects, each object being a route with the following parameters: | Parameter | Description | Type | | -------------------------- | -------------------------------------------------------------------------------- | -------- | | `method` | Method associated to the route (i.e. `GET`, `POST`, `PUT`, `DELETE` or `PATCH`) | `String` | | `path` | Path to reach, starting with a forward-leading slash (e.g. `/articles`)| `String` | | `handler` | Function to execute when the route is reached.
Use the fully-qualified syntax `api::api-name.controllerName.actionName` (or `plugin::plugin-name.controllerName.actionName`). The short `.` form for legacy projects also works. | `String` | | `config`

_Optional_ | Configuration to handle [policies](#policies), [middlewares](#middlewares) and [public availability](#public-routes) for the route

| `Object` |
Dynamic routes can be created using parameters and regular expressions. These parameters will be exposed in the `ctx.params` object. For more details, please refer to the
## Configuration Both [core routers](#configuring-core-routers) and [custom routers](#creating-custom-routers) have the same configuration options. The routes configuration is defined in a `config` object that can be used to handle [policies](#policies) and [middlewares](#middlewares) or to [make the route public](#public-routes). ### Policies [Policies](/cms/backend-customization/policies) can be added to a route configuration: - by pointing to a policy registered in `./src/policies`, with or without passing a custom configuration - or by declaring the policy implementation directly, as a function that takes `policyContext` to extend ### Middlewares [Middlewares](/cms/backend-customization/middlewares) can be added to a route configuration: - by pointing to a middleware registered in `./src/middlewares`, with or without passing a custom configuration - or by declaring the middleware implementation directly, as a function that takes ### Public routes By default, routes are protected by Strapi's authentication system, which is based on [API tokens](/cms/features/api-tokens) or on the use of the [Users & Permissions plugin](/cms/features/users-permissions). In some scenarios, it can be useful to have a route publicly available and control the access outside of the normal Strapi authentication system. This can be achieved by setting the `auth` configuration parameter of a route to `false`: ## Custom Content API parameters {#custom-content-api-parameters} You can extend the `query` and body parameters allowed on Content API routes by registering them in the [register](/cms/configurations/functions#register) lifecycle. Registered parameters are then validated and sanitized like core parameters. Clients can send extra query keys (e.g. `?search=...`) or root-level body keys (e.g. `clientMutationId`) without requiring custom routes or controllers. | What | Where | |------|--------| | Enable strict parameters (reject unknown query/body keys) | [API configuration](/cms/configurations/api): set `rest.strictParams: true` in `./config/api.js` (or `./config/api.ts`). | | Add allowed parameters (app) | Call `addQueryParams` / `addInputParams` in [register](/cms/configurations/functions#register) in `./src/index.js` or `./src/index.ts`. | | Add allowed parameters (plugin) | Call `addQueryParams` / `addInputParams` in the plugin's [register](/cms/plugins-development/server-lifecycle#register) lifecycle. | When `rest.strictParams` is enabled, only core parameters and parameters on each route's request schema are accepted; the parameters you register are merged into that schema. Use the `z` instance from `@strapi/utils` (or `zod/v4`) for schemas. ### `addQueryParams` `strapi.contentAPI.addQueryParams(options)` registers extra `query` parameters. Schemas must be scalar or array-of-scalars (string, number, boolean, enum). For nested structures, use `addInputParams` instead. Each entry can have an optional `matchRoute: (route) => boolean` callback to add the parameter only to routes for which the callback returns true. You cannot register core query param names (e.g. `filters`, `sort`, `fields`) as extra params; they are reserved. ### `addInputParams` `strapi.contentAPI.addInputParams(options)` registers extra input parameters: root-level keys in the request body (e.g. alongside `data`), with any Zod type. The optional `matchRoute` callback works the same way as for `addQueryParams`. You cannot register reserved names such as `id` or `documentId` as input params. ### `matchRoute` The `matchRoute` callback receives a `route` object with the following properties: - `route.method`: the HTTP method (`'GET'`, `'POST'`, etc.) - `route.path`: the route path - `route.handler`: the controller action string - `route.info`: metadata about the route For example, to target only GET routes, use `matchRoute: (route) => route.method === 'GET'`. To target only routes whose path includes `articles`, use `matchRoute: (route) => route.path.includes('articles')`. # Services Source: https://docs.strapi.io/cms/backend-customization/services # Services Services are a set of reusable functions. They are particularly useful to respect the "don’t repeat yourself" (DRY) programming concept and to simplify [controllers](/cms/backend-customization/controllers.md) logic.
Simplified Strapi backend diagram with services highlighted
The diagram represents a simplified version of how a request travels through the Strapi back end, with services highlighted. The backend customization introduction page includes a complete, interactive diagram.
## Implementation Services can be [generated or added manually](#adding-a-new-service). Strapi provides a `createCoreService` factory function that automatically generates core services and allows building custom ones or [extend or replace the generated services](#extending-core-services). ### Adding a new service A new service can be implemented: - with the [interactive CLI command `strapi generate`](/cms/cli#strapi-generate) - or manually by creating a JavaScript file in the appropriate folder (see [project structure](/cms/project-structure.md)): - `./src/api/[api-name]/services/` for API services - or `./src/plugins/[plugin-name]/services/` for [plugin services](/cms/plugins-development/server-controllers-services). To manually create a service, export a factory function that returns the service implementation (i.e. an object with methods). This factory function receives the `strapi` instance: :::strapi Document Service API To get started creating your own services, see Strapi's built-in functions in the [Document Service API](/cms/api/document-service) documentation. :::
Example of a custom email service (using Nodemailer) The goal of a service is to store reusable functions. A `sendNewsletter` service could be useful to send emails from different functions in our codebase that have a specific purpose: The service is now available through the `strapi.service('api::restaurant.restaurant').sendNewsletter(...args)` global variable. It can be used in another part of the codebase, like in the following controller:
:::note When a new [content-type](/cms/backend-customization/models.md#content-types) is created, Strapi builds a generic service with placeholder code, ready to be customized. ::: ### Extending core services Core services are created for each content-type and could be used by [controllers](/cms/backend-customization/controllers.md) to execute reusable logic through a Strapi project. Core services can be customized to implement your own logic. The following code examples should help you get started. :::tip A core service can be replaced entirely by [creating a custom service](#adding-a-new-service) and naming it the same as the core service (e.g. `find`, `findOne`, `create`, `update`, or `delete`). :::
Collection type examples
Single type examples
## Usage Once a service is created, it's accessible from [controllers](/cms/backend-customization/controllers.md) or from other services: ```js // access an API service strapi.service('api::apiName.serviceName').FunctionName(); // access a plugin service strapi.service('plugin::pluginName.serviceName').FunctionName(); ``` In the syntax examples above, `serviceName` is the name of the service file for API services or the name used to export the service file to `services/index.js` for plugin services. :::tip To list all the available services, run `yarn strapi services:list`. ::: ### Core service methods Services generated with `createCoreService` inherit methods that wrap the [Document Service API](/cms/api/document-service). The available methods depend on the content-type: #### Collection types | Method | Description | | --- | --- | | `find(params)` | Wrapper for [`findMany`](/cms/api/document-service#findmany); returns a paginated list of documents. | | `findOne(documentId, params)` | Wrapper for [`findOne`](/cms/api/document-service#findone); returns a single document by its `documentId`. | | `create(params)` | Wrapper for [`create`](/cms/api/document-service#create); creates a new document. | | `update(documentId, params)` | Wrapper for [`update`](/cms/api/document-service#update); updates an existing document. | | `delete(documentId, params)` | Wrapper for [`delete`](/cms/api/document-service#delete); removes a document. | | `count(params)` | Wrapper for [`count`](/cms/api/document-service#count); returns the number of matching documents. | | `publish(documentId, params)` | Wrapper for [`publish`](/cms/api/document-service#publish); publishes a draft document. | | `unpublish(documentId, params)` | Wrapper for [`unpublish`](/cms/api/document-service#unpublish); unpublishes a document. | | `discardDraft(documentId, params)` | Wrapper for [`discardDraft`](/cms/api/document-service#discarddraft); deletes the draft copy. | #### Single types | Method | Description | | --- | --- | | `find(params)` | Returns the single document (uses [`findFirst`](/cms/api/document-service#findfirst) internally). | | `createOrUpdate({ data, ...params })` | Creates the document if it doesn't exist or updates it (uses [`update`](/cms/api/document-service#update)). | | `delete(params)` | Deletes the document (uses [`delete`](/cms/api/document-service#delete)). | | `count(params)` | Counts documents matching the filters (uses [`count`](/cms/api/document-service#count)). | | `publish(params)` | Publishes a draft document (uses [`publish`](/cms/api/document-service#publish)). | | `unpublish(params)` | Unpublishes the document (uses [`unpublish`](/cms/api/document-service#unpublish)). | | `discardDraft(params)` | Deletes the draft copy (uses [`discardDraft`](/cms/api/document-service#discarddraft)). | #### Parameters and default behavior Core service methods accept the same parameters as their underlying [Document Service API](/cms/api/document-service) calls, such as `fields`, `filters`, `sort`, `pagination`, `populate`, `locale`, and `status`. When no `status` is provided, Strapi automatically sets `status: 'published'` so only published content is returned. To query draft documents, explicitly pass `status: 'draft'` or another value supported by the Document Service. The `createCoreService` factory also exposes a `getFetchParams(params)` helper that converts a controller's query object into the parameter format expected by these methods. This helper can be reused when overriding core methods to forward sanitized parameters to `strapi.documents()`. # Webhooks Source: https://docs.strapi.io/cms/backend-customization/webhooks # Webhooks Webhook is a construct used by an application to notify other applications that an event occurred. More precisely, webhook is a user-defined HTTP callback. Using a webhook is a good way to tell third-party providers to start some processing (CI, build, deployment ...). The way a webhook works is by delivering information to a receiving application through HTTP requests (typically POST requests). ## User content-type webhooks To prevent from unintentionally sending any user's information to other applications, Webhooks will not work for the User content-type. If you need to notify other applications about changes in the Users collection, you can do so by creating [Lifecycle hooks](/cms/backend-customization/models#lifecycle-hooks) using the `./src/index.js` example. ## Available configurations You can set webhook configurations inside the file `./config/server`. - `webhooks` - `defaultHeaders`: You can set default headers to use for your webhook requests. This option is overwritten by the headers set in the webhook itself. **Example configuration** ## Webhooks security Most of the time, webhooks make requests to public URLs, therefore it is possible that someone may find that URL and send it wrong information. To prevent this from happening you can send a header with an authentication token. Using the Admin panel you would have to do it for every webhook. Another way is to define `defaultHeaders` to add to every webhook request. You can configure these global headers by updating the file at `./config/server`: If you are developing the webhook handler yourself you can now verify the token by reading the headers. ### Verifying signatures In addition to auth headers, it's recommended to sign webhook payloads and verify signatures server‑side to prevent tampering and replay attacks. To do so, you can use the following guidelines: - Generate a shared secret and store it in environment variables - Have the sender compute an HMAC (e.g., SHA‑256) over the raw request body plus a timestamp - Send the signature (and timestamp) in headers (e.g., `X‑Webhook‑Signature`, `X‑Webhook‑Timestamp`) - On receipt, recompute the HMAC and compare using a constant‑time check - Reject if the signature is invalid or the timestamp is too old to mitigate replay
Example: Verify HMAC signatures (Node.js) Here is a minimal Node.js middleware example (pseudo‑code) showing Here are a few additional external examples: - -
## Available events By default Strapi webhooks can be triggered by the following events: | Name | Description | | ----------------- | ----------------------------------------------------- | | [`entry.create`](#entrycreate) | Triggered when a Content Type entry is created. | | [`entry.update`](#entryupdate) | Triggered when a Content Type entry is updated. | | [`entry.delete`](#entrydelete) | Triggered when a Content Type entry is deleted. | | [`entry.publish`](#entrypublish) | Triggered when a Content Type entry is published.\* | | [`entry.unpublish`](#entryunpublish) | Triggered when a Content Type entry is unpublished.\* | | [`media.create`](#mediacreate) | Triggered when a media is created. | | [`media.update`](#mediaupdate) | Triggered when a media is updated. | | [`media.delete`](#mediadelete) | Triggered when a media is deleted. | | [`review-workflows.updateEntryStage`](#review-workflowsupdateentrystage) | Triggered when content is moved between review stages (see [review workflows](/cms/features/review-workflows#configuration)).
This event is only available with the edition of Strapi. | | [`releases.publish`](#releases-publish) | Triggered when a Release is published (see [Releases](/cms/features/releases)).
This event is only available with the or plan of Strapi CMS. | \*only when `draftAndPublish` is enabled on this Content Type. ## Payloads :::info Private fields are not sent in the payload. ::: ### Headers When a payload is delivered to your webhook's URL, it will contain specific headers: | Header | Description | | ---------------- | ------------------------------------------ | | `X-Strapi-Event` | Name of the event type that was triggered. | ### `entry.create` This event is triggered when a new entry is created. **Example payload** ```json { "event": "entry.create", "createdAt": "2020-01-10T08:47:36.649Z", "model": "address", "entry": { "id": 1, "geolocation": {}, "city": "Paris", "postal_code": null, "category": null, "full_name": "Paris", "createdAt": "2020-01-10T08:47:36.264Z", "updatedAt": "2020-01-10T08:47:36.264Z", "cover": null, "images": [] } } ``` ### `entry.update` This event is triggered when an entry is updated. **Example payload** ```json { "event": "entry.update", "createdAt": "2020-01-10T08:58:26.563Z", "model": "address", "entry": { "id": 1, "geolocation": {}, "city": "Paris", "postal_code": null, "category": null, "full_name": "Paris", "createdAt": "2020-01-10T08:47:36.264Z", "updatedAt": "2020-01-10T08:58:26.210Z", "cover": null, "images": [] } } ``` ### `entry.delete` This event is triggered when an entry is deleted. **Example payload** ```json { "event": "entry.delete", "createdAt": "2020-01-10T08:59:35.796Z", "model": "address", "entry": { "id": 1, "geolocation": {}, "city": "Paris", "postal_code": null, "category": null, "full_name": "Paris", "createdAt": "2020-01-10T08:47:36.264Z", "updatedAt": "2020-01-10T08:58:26.210Z", "cover": null, "images": [] } } ``` ### `entry.publish` This event is triggered when an entry is published. **Example payload** ```json { "event": "entry.publish", "createdAt": "2020-01-10T08:59:35.796Z", "model": "address", "entry": { "id": 1, "geolocation": {}, "city": "Paris", "postal_code": null, "category": null, "full_name": "Paris", "createdAt": "2020-01-10T08:47:36.264Z", "updatedAt": "2020-01-10T08:58:26.210Z", "publishedAt": "2020-08-29T14:20:12.134Z", "cover": null, "images": [] } } ``` ### `entry.unpublish` This event is triggered when an entry is unpublished. **Example payload** ```json { "event": "entry.unpublish", "createdAt": "2020-01-10T08:59:35.796Z", "model": "address", "entry": { "id": 1, "geolocation": {}, "city": "Paris", "postal_code": null, "category": null, "full_name": "Paris", "createdAt": "2020-01-10T08:47:36.264Z", "updatedAt": "2020-01-10T08:58:26.210Z", "publishedAt": null, "cover": null, "images": [] } } ``` ### `media.create` This event is triggered when you upload a file on entry creation or through the media interface. **Example payload** ```json { "event": "media.create", "createdAt": "2020-01-10T10:58:41.115Z", "media": { "id": 1, "name": "image.png", "hash": "353fc98a19e44da9acf61d71b11895f9", "sha256": "huGUaFJhmcZRHLcxeQNKblh53vtSUXYaB16WSOe0Bdc", "ext": ".png", "mime": "image/png", "size": 228.19, "url": "/uploads/353fc98a19e44da9acf61d71b11895f9.png", "provider": "local", "provider_metadata": null, "createdAt": "2020-01-10T10:58:41.095Z", "updatedAt": "2020-01-10T10:58:41.095Z", "related": [] } } ``` ### `media.update` This event is triggered when you replace a media or update the metadata of a media through the media interface. **Example payload** ```json { "event": "media.update", "createdAt": "2020-01-10T10:58:41.115Z", "media": { "id": 1, "name": "image.png", "hash": "353fc98a19e44da9acf61d71b11895f9", "sha256": "huGUaFJhmcZRHLcxeQNKblh53vtSUXYaB16WSOe0Bdc", "ext": ".png", "mime": "image/png", "size": 228.19, "url": "/uploads/353fc98a19e44da9acf61d71b11895f9.png", "provider": "local", "provider_metadata": null, "createdAt": "2020-01-10T10:58:41.095Z", "updatedAt": "2020-01-10T10:58:41.095Z", "related": [] } } ``` ### `media.delete` This event is triggered only when you delete a media through the media interface. **Example payload** ```json { "event": "media.delete", "createdAt": "2020-01-10T11:02:46.232Z", "media": { "id": 11, "name": "photo.png", "hash": "43761478513a4c47a5fd4a03178cfccb", "sha256": "HrpDOKLFoSocilA6B0_icA9XXTSPR9heekt2SsHTZZE", "ext": ".png", "mime": "image/png", "size": 4947.76, "url": "/uploads/43761478513a4c47a5fd4a03178cfccb.png", "provider": "local", "provider_metadata": null, "createdAt": "2020-01-07T19:34:32.168Z", "updatedAt": "2020-01-07T19:34:32.168Z", "related": [] } } ``` ### `review-workflows.updateEntryStage` This event is only available with the plan of Strapi.
The event is triggered when content is moved to a new review stage (see [Review Workflows](/cms/features/review-workflows#configuration)). **Example payload** ```json { "event": "review-workflows.updateEntryStage", "createdAt": "2023-06-26T15:46:35.664Z", "model": "model", "uid": "uid", "entity": { "id": 2 }, "workflow": { "id": 1, "stages": { "from": { "id": 1, "name": "Stage 1" }, "to": { "id": 2, "name": "Stage 2" } } } } ``` ### `releases.publish` {#releases-publish} The event is triggered when a [release](/cms/features/releases) is published. **Example payload** ```json { "event": "releases.publish", "createdAt": "2024-02-21T16:45:36.877Z", "isPublished": true, "release": { "id": 2, "name": "Fall Winter highlights", "releasedAt": "2024-02-21T16:45:36.873Z", "scheduledAt": null, "timezone": null, "createdAt": "2024-02-21T15:16:22.555Z", "updatedAt": "2024-02-21T16:45:36.875Z", "actions": { "count": 1 } } } ``` ## Best practices for webhook handling - Validate incoming requests by checking headers and payload signatures. - Implement retries for failed webhook requests to handle transient errors. - Log webhook events for debugging and monitoring. - Use secure, HTTPS endpoints for receiving webhooks. - Set up rate limiting to avoid being overwhelmed by multiple webhook requests. :::tip If you want to learn more about how to use webhooks with Next.js, please have a look at the [dedicated blog article](https://strapi.io/blog/how-to-create-an-ssg-static-site-generation-application-with-strapi-webhooks-and-nextjs). ::: # Command Line Interface Source: https://docs.strapi.io/cms/cli # Command Line Interface (CLI) Strapi comes with a full featured Command Line Interface (CLI) which lets you scaffold and manage your project in seconds. The CLI works with both the `yarn` and `npm` package managers. :::caution Interactive commands such as `strapi admin:create-user` don't display prompts with `npm`. Please consider using the `yarn` package manager. ::: :::note It is recommended to install Strapi locally only, which requires prefixing all of the following `strapi` commands with the package manager used for the project setup (e.g `npm run strapi help` or `yarn strapi help`) or a dedicated node package executor (e.g. `npx strapi help`). To pass options with `npm` use the syntax: `npm run strapi -- --
### `compression` The `compression` middleware is based on
### `cors` This security middleware is about cross-origin resource sharing (CORS) and is based on
Example: Custom configuration for the cors middleware within a function as parameter `origin` can take a Function as parameter following this signature ```ts title="./config/middlewares.ts" // ... { name: 'strapi::cors', config: { origin: (ctx): string | string[] => { const origin = ctx.request.header.origin; if (origin === 'http://localhost:3000') { return origin; // The returns will be part of the Access-Control-Allow-Origin header } return ''; // Fail cors check } }, }, // ... ] ```
### `errors` The errors middleware handles [errors](/cms/error-handling.md) thrown by the code. Based on the type of error it sets the appropriate HTTP status to the response. By default, any error not supposed to be exposed to the end user will result in a 500 HTTP response. The middleware doesn't have any configuration options. ### `favicon` The `favicon` middleware serves the favicon and is based on
### `ip` The `ip` middleware is an IP filter middleware based on
### `logger` The `logger` middleware is used to log requests. To define a custom configuration for the `logger` middleware, create a dedicated configuration file (`./config/logger.js`). It should export an object that must be a complete or partial
### `poweredBy` The `poweredBy` middleware adds a `X-Powered-By` parameter to the response header. It accepts the following options: | Option | Description | Type | Default value | |-------------|------------------------------------|----------|------------------------| | `poweredBy` | Value of the `X-Powered-By` header | `String` | `'Strapi '` |
details Example: Custom configuration for the poweredBy middleware
### `query` The `query` middleware is a query parser based on
Example: Raise arrayLimit for long REST query lists Use a value that fits your longest bracket-encoded lists (for example many `populate[n]` entries). Adjust the number based on your needs and acceptable parsing cost.
### `response-time` The `response-time` middleware enables the `X-Response-Time` (in milliseconds) for the response header. The middleware doesn't have any configuration options. ### `public` The `public` middleware is a static file serving middleware, based on
### `security` The security middleware is based on
### `session` The `session` middleware allows the use of cookie-based sessions, based on # Plugins configuration Source: https://docs.strapi.io/cms/configurations/plugins # Plugins configuration Plugin configurations are stored in `/config/plugins.js|ts` (see [project structure](/cms/project-structure)). Each plugin can be configured with the following available parameters: | Parameter | Description | Type | | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | `enabled` | Enable (`true`) or disable (`false`) an installed plugin | Boolean | | `config`

_Optional_ | Used to override default plugin configuration ([defined in strapi-server.js](/cms/plugins-development/server-configuration)) | Object | | `resolve`
_Optional, only required for local plugins_ | Path to the plugin's folder | String | :::note Configurations for core features and providers * Some core features of Strapi have historically been implemented as core plugins. This explains that their configuration is still defined in the `/config/plugins` file despite not technically being plugins in Strapi 5 anymore. This includes: - the [Upload configuration](/cms/features/media-library#available-options) for the package which powers the Media Library, - and the [Users & Permissions configuration](/cms/features/users-permissions#code-based-configuration). The detailed [GraphQL plugin configuration](/cms/plugins/graphql#code-based-configuration) is also documented in its dedicated plugin page. * Additionally, providers configuration for the Media Library and the Email features are also defined in `/config/plugins`. Their configurations are detailed in the [Upload providers configuration](/cms/features/media-library#code-based-configuration) and the [Email providers configuration](/cms/features/email#providers). ::: **Basic example custom configuration for plugins:** :::tip If no specific configuration is required, a plugin can also be declared with the shorthand syntax `'plugin-name': true`. ::: # Server configuration Source: https://docs.strapi.io/cms/configurations/server # Server configuration The `/config/server.js` file is used to define the server configuration for a Strapi application. :::caution Changes to the `server.js` file require rebuilding the admin panel. After saving the modified file run either `yarn build` or `npm run build` in the terminal to implement the changes. ::: ## Available options The `./config/server.js` file can include the following parameters: | Parameter | Description | Type | Default | | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------- | | `host`

❗️ _Mandatory_ | Host name | string | `localhost` | | `port`

❗️ _Mandatory_ | Port on which the server should be running. | integer | `1337` | | `app.keys`

❗️ _Mandatory_ | Declare session keys (based on # TypeScript configuration Source: https://docs.strapi.io/cms/configurations/typescript # TypeScript configuration [TypeScript](/cms/typescript)-enabled Strapi projects have a specific project structure and handle TypeScript project configuration through [`tsconfig.json` files](#project-structure-and-typescript-specific-configuration-files). Strapi also has dedicated TypeScript features that are configured [in the `config/typescript.js|ts` file](#strapi-specific-configuration-for-typescript). ## Project structure and TypeScript-specific configuration files TypeScript-enabled Strapi applications have a specific [project structure](/cms/project-structure) with the following dedicated folders and configuration files: | TypeScript-specific directories and files | Location | Purpose | | ----------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `./dist` directory | application root | Adds the location for compiling the project JavaScript source code. | | `build` directory | `./dist` | Contains the compiled administration panel JavaScript source code. The directory is created on the first `yarn build` or `npm run build` command | | `tsconfig.json` file | application root | Manages TypeScript compilation for the server. | | `tsconfig.json` file | `./src/admin/` | Manages TypeScript compilation for the admin panel. | ## Strapi-specific configuration for TypeScript :::caution 🚧 This feature is considered experimental. These settings are considered experimental and might have issues or break some features. ::: Types generated by Strapi are based on the user project structure. Once the type definitions are emitted into their dedicated files, Strapi reads the type definitions to adapt the autocompletion results accordingly. To avoid having to [manually generate types](/cms/typescript/development#generate-typings-for-content-types-schemas) every time the server restarts, an optional `config/typescript.js|ts` configuration file can be added, which currently accepts only one parameter: | Parameter | Description | Type | Default | | -------------- | -------------------------------------------------------------- | --------- | ------- | | `autogenerate` | Enable or disable automatic types generation on server restart | `Boolean` | `false` | **Example:** # カスタマイズ Source: https://docs.strapi.io/cms/customization # カスタマイズ Strapi は主に 2 つの要素で構成されます。 - Strapi の **バックエンド**は、リクエストを受け取り処理してレスポンスを返す**サーバー**です。コンテンツタイプビルダーやコンテンツマネージャーで作った・保存したデータを返せます。詳細は [バックエンドのカスタマイズ概要](/cms/backend-customization) を参照してください。バックエンドの多くの部分はカスタマイズ可能です。 - Strapi のユーザー向けフロントは **管理パネル**です。GUI でコンテンツ構造の作成、コンテンツの作成・管理、組み込み/サードパーティプラグインで扱える各種操作ができます。管理パネルの一部はカスタマイズ可能です。 典型的な構成では、Strapi はバックエンドサーバーと管理パネルを含み、データを保持するデータベースと、データを表示する外部のフロントエンドアプリと連携します。Strapi の両方はある程度までカスタマイズできます。 :::info データベースや外部フロントエンドアプリそのもののカスタマイズは、このドキュメント節の範囲外です。 - データベースについては、インストールドキュメントの [対応データベース](/cms/installation/cli#preparing-the-installation) と、[データベース設定](/cms/configurations/database) を参照してください。 - 外部フロントが Strapi と連携する方法は Strapi の を参照してください。 ::: # Database migrations Source: https://docs.strapi.io/cms/database-migrations # Database migrations Database migrations exist to run one-time queries against the database, typically to modify the tables structure or the data when upgrading the Strapi application. These migrations are run automatically when the application starts and are executed before the automated schema migrations that Strapi also performs on boot. :::callout 🚧 Experimental feature Database migrations are experimental. This feature is still a work in progress and will continue to be updated and improved. In the meantime, feel free to ask for help on the Additionally, if you want to continue using existing JavaScript migrations alongside TypeScript migrations, you can set `allowJs: true` in your `tsconfig.json` file's compiler options, as mentioned in the [database configuration documentation](/cms/configurations/database#settings-configuration-object). # Database transactions Source: https://docs.strapi.io/cms/database-transactions # Database transactions :::caution This is an experimental feature and is subject to change in future versions. ::: Strapi 5 provide an API to wrap a set of operations in a transaction that ensures the integrity of data. Transactions are a set of operations that are executed together as a single unit. If any of the operations fail, the entire transaction fails and the data is rolled back to its previous state. If all operations succeed, the transaction is committed and the data is permanently saved to the database. ## Usage Transactions are handled by passing a handler function into `strapi.db.transaction`: ```js await strapi.db.transaction(async ({ trx, rollback, commit, onCommit, onRollback }) => { // It will implicitly use the transaction await strapi.entityService.create(); await strapi.entityService.create(); }); ``` After the transaction handler is executed, the transaction is committed if all operations succeed. If any of the operations throws, the transaction is rolled back and the data is restored to its previous state. :::note Every `strapi.entityService` or `strapi.db.query` operation performed in a transaction block will implicitly use the transaction. ::: ### Transaction handler properties The handler function receives an object with the following properties: | Property | Description | | ------------ | ------------------------------------------------------------------------------------------- | | `trx` | The transaction object. It can be used to perform knex queries within the transaction. | | `commit` | Function to commit the transaction. | | `rollback` | Function to rollback the transaction. | | `onCommit` | Function to register a callback that will be executed after the transaction is committed. | | `onRollback` | Function to register a callback that will be executed after the transaction is rolled back. | ### Nested transactions Transactions can be nested. When a transaction is nested, the inner transaction is committed or rolled back when the outer transaction is committed or rolled back. ```js await strapi.db.transaction(async () => { // It will implicitly use the transaction await strapi.entityService.create(); // Nested transactions will implicitly use the outer transaction await strapi.db.transaction(async ({}) => { await strapi.entityService.create(); }); }); ``` ### onCommit and onRollback The `onCommit` and `onRollback` hooks can be used to execute code after the transaction is committed or rolled back. ```js await strapi.db.transaction(async ({ onCommit, onRollback }) => { // It will implicitly use the transaction await strapi.entityService.create(); await strapi.entityService.create(); onCommit(() => { // This will be executed after the transaction is committed }); onRollback(() => { // This will be executed after the transaction is rolled back }); }); ``` ### Using knex queries Transactions can also be used with knex queries, but in those cases `.transacting(trx)` must be explicitly called. ```js await strapi.db.transaction(async ({ trx, rollback, commit }) => { await knex('users').where('id', 1).update({ name: 'foo' }).transacting(trx); }); ``` ## When to use transactions Transactions should be used in cases where multiple operations should be executed together and their execution is dependent on each other. For example, when creating a new user, the user should be created in the database and a welcome email should be sent to the user. If the email fails to send, the user should not be created in the database. ## When not to use transactions Transactions should not be used for operations that are not dependent on each other since it can result in performance penalties. ## Potential problems of transactions Performing multiple operations within a transaction can lead to locking, which can block the execution of transactions from other processes until the original transaction is complete. Furthermore, transactions can stall if they are not committed or rolled back appropriately. For example, if a transaction is opened but there is a path in your code that does not close it, the transaction will be left open indefinitely and could cause instability until your server is restarted and the connection is forced to close. These issues can be difficult to debug, so use transactions with care in the cases they are necessary. # デプロイ Source: https://docs.strapi.io/cms/deployment # デプロイ Strapi にはプロジェクトやアプリケーション向けのデプロイ選択肢が多数あります。従来型のホスティングサーバーや、好みのクラウドプロバイダーにデプロイできます。 以下では、一般的なホスティング向けに Strapi を準備する基本を説明します。 :::strapi Strapi Cloud [Strapi Cloud](/cloud/intro) でプロジェクトを手早くデプロイ・ホストできます。 ::: :::tip ローカル(開発)の Strapi でコンテンツタイプビルダーにより構造を作り、コンテンツマネージャーでデータを入れ済みの場合、[データ管理](/cms/features/data-management) でインスタンス間の移行に使えます。 別の流れとして、まずローカルで構造だけ作成し、Git リポジトリにプッシュして本番へデプロイし、その後に本番インスタンスへコンテンツを追加する方法もあります。 ::: :::caution セルフホストの Kubernetes では **pnpm** より **npm** を推奨します。`pnpm` の積極的な hoisting は、アプリが依存する `mysql2` などのネイティブモジュールを壊すことがあります。`npm` のフラットで予測しやすい `node_modules` 構成の方が、ネイティブパッケージの読み込みに有利です。 ::: ## 一般的な指針 {#general-guidelines} ### ハードウェアとソフトウェアの要件 Strapi に適した環境のために、開発(ローカル)およびステージング・本番の各ワークフローで次を満たしてください。 `production` 設定でサーバーを起動します。 :::caution プロセス管理には の利用を強く推奨します。 ::: `npm run start` ではなく `node server.js` で動かしたい場合は、次の `./server.js` を作成します。 ```js title="path: ./server.js" const strapi = require('@strapi/strapi'); strapi.createStrapi(/* {...} */).start(); ``` :::caution `TypeScript` ベースのプロジェクトでは、サーバー起動時に `distDir` オプションが必要です。 詳しくは [TypeScript ドキュメント](/cms/typescript/development#use-the-createstrapi-factory) を参照してください。 ::: :::tip ヘルスチェック用エンドポイント Strapi は `/_health` に軽量なヘルスチェックルートを公開します(アップタイム監視やロードバランサー向け)。サーバー準備ができていると HTTP `204 No Content` とヘッダー値 `strapi: You are so French!` で応答し、アプリ到達性の確認に使えます。 ::: ### 高度な設定 管理画面を API とは別サーバーでホストする場合は、[こちらの専用の節](/cms/configurations/admin-panel#deploy-on-different-servers) を参照してください。 ## その他のリソース {#additional-resources} :::prerequisites * Strapi プロジェクトを [作成](/cms/installation)済みで、コードが GitHub などにホストされていること。 * [一般的なデプロイの指針](/cms/deployment#general-guidelines) を読んだこと。 ::: Strapi サイトの には、多くのサービスとの連携情報があります。次のサードパーティプラットフォームへのデプロイも掲載されています。
加えて、 にコミュニティ管理の各種ガイドがあります。例:
Strapi が公式に保守しているわけではありませんが、次の外部ガイドも参考になります。 :::strapi マルチテナンシー マルチテナンシーの選択肢については、Strapi ブログの を参照してください。 ::: # Error handling Source: https://docs.strapi.io/cms/error-handling # Error handling Strapi is natively handling errors with a standard format. There are 2 use cases for error handling: - As a developer querying content through the [REST](/cms/api/rest) or [GraphQL](/cms/api/graphql) APIs, you might [receive errors](#receiving-errors) in response to the requests. - As a developer customizing the backend of your Strapi application, you could use controllers and services to [throw errors](#throwing-errors). ## Receiving errors Errors are included in the response object with the `error` key and include information such as the HTTP status code, the name of the error, and additional information. ### REST errors Errors thrown by the REST API are included in the [response](/cms/api/rest#requests) that has the following format: ```json { "data": null, "error": { "status": "", // HTTP status "name": "", // Strapi error name ('ApplicationError' or 'ValidationError') "message": "", // A human readable error message "details": { // error info specific to the error type } } } ``` ### GraphQL errors Errors thrown by the GraphQL API are included in the response that has the following format: ```json { "errors": [ { "message": "", // A human reable error message "extensions": { "error": { "name": "", // Strapi error name ('ApplicationError' or 'ValidationError'), "message": "", // A human reable error message (same one as above); "details": {}, // Error info specific to the error type }, "code": "" // GraphQL error code (ex: BAD_USER_INPUT) } } ], "data": { "graphQLQueryName": null } } ``` ## Throwing errors
### Controllers and middlewares The recommended way to throw errors when developing any custom logic with Strapi is to have the [controller](/cms/backend-customization/controllers) or [middleware](/cms/backend-customization/middlewares) respond with the correct status and body. This can be done by calling an error function on the context (i.e. `ctx`). Available error functions are listed in the ### Services and models lifecycles Once you are working at a deeper layer than the controllers or middlewares there are dedicated error classes that can be used to throw errors. These classes are extensions of #### Example: Throwing an error in a model lifecycle** This example shows building a [custom model lifecycle](/cms/backend-customization/models#lifecycle-hooks) and being able to throw an error that stops the request and will return proper error messages to the admin panel. Generally you should only throw an error in `beforeX` lifecycles, not `afterX` lifecycles. ### Policies [Policies](/cms/backend-customization/policies) are a special type of middleware that are executed before a controller. They are used to check if the user is allowed to perform the action or not. If the user is not allowed to perform the action and a `return false` is used then a generic error will be thrown. As an alternative, you can throw a custom error message using a nested class extensions from the Strapi `ForbiddenError` class, `ApplicationError` class (see [Default error classes](#default-error-classes) for both classes), and finally the ### Default error classes The default error classes are available from the `@strapi/utils` package and can be imported and used in your code. Any of the default error classes can be extended to create a custom error class. The custom error class can then be used in your code to throw errors. ### コンテンツの削除 {#deleting-content} コレクション型の任意のエントリー、またはシングル型の既定エントリーを削除すると、そのコンテンツを削除できます。 1. エントリーの編集ビューで、画面上部右の をクリックし、**Delete document** を選びます。
コンテンツタイプで多言語が有効な場合、**Delete locale** で現在選んでいるロケールだけを削除することもできます。 2. 表示されたダイアログで **Confirm** をクリックして削除を確定します。 :::tip コレクション型のリストビューでも削除できます。表の行の右側にあるエントリー用 から、 **Delete document** を選びます。
コンテンツタイプで [多言語(Internationalization)](/cms/features/internationalization) が有効な場合、**Delete document** はすべてのロケールを削除し、**Delete locale** はリストに表示中のロケールだけを削除します。 ::: # コンテンツタイプビルダー Source: https://docs.strapi.io/cms/features/content-type-builder # コンテンツタイプビルダー 管理パネルのメインナビから ## 概要 {#overview} 3. ダイアログで **Finish** をクリックします。 4. Content-Type Builder のナビゲーションで **Save** をクリックします。 #### フィールド コンテンツタイプのフィールド一覧では次の操作ができます。 - #### Rich Text (Blocks) {#rich-text-blocks} Rich Text (Blocks) フィールドは、リアルタイム表示と豊富なオプションを持つエディターです。長文に加え、画像やコードを含める用途に使えます。 :::strapi React renderer Blocks エディターを使う場合、React フロントでは #### Date {#date} Date フィールドは、日付(年・月・日)、時刻(時・分・秒)、または日時のいずれかを選べる UI になります。 #### Media {#media} Media フィールドでは、アプリのメディアライブラリにアップロード済みのメディア(画像・動画など)を 1 件または複数件選べます。 #### Relation {#relation} Relation フィールドは、別のコンテンツタイプ(コレクション型である必要があります)との関連付けを定義します。 リレーションは次の 6 種類があります。 - One way: コンテンツタイプ A がコンテンツタイプ B を *has one* - One-to-one: コンテンツタイプ A と B が *has and belong to one* - One-to-many: コンテンツタイプ A がコンテンツタイプ B に *belongs to many* - Many-to-one: コンテンツタイプ B がコンテンツタイプ A を *has many* - Many-to-many: コンテンツタイプ A と B が *has and belongs to many* - Many way: コンテンツタイプ A がコンテンツタイプ B を *has many* :::info 複数参照できるリレーションと単一参照 少なくとも一方が複数エントリーを参照できるリレーションをマルチリレーションと呼びます。Content-type Builder では one-to-many、many-to-one、many-to-many、many-way が該当します。コンテンツマネージャーではマルチセレクト風に表示され、REST・GraphQL・Document Service API では配列として返ります。一方、one-way と one-to-one は単一の関連エントリーを返します(詳しくは [API リクエストでのリレーション管理](/cms/api/rest/relations) を参照してください)。 ::: :::tip ネストしたページ階層のモデリング ページの木構造を表現する例です。 1. `Page` コレクション型に "Slug"(UID)と、(任意で)兄弟順序用の "Order"(Integer)を追加します。 2. `Page` から `Page` への Relation で *Many-to-one* を選び、各ページが "Parent page" を持てるようにします。Strapi は逆方向の "Children pages" も自動で用意します。 3. データ取得時は `children` を再帰的に populate して木を読み込みます。レスポンス肥大化を避けるため、再帰の深さは小さく保ちます。
```json title="Populate nested children for a page tree" { populate: { children: { fields: ['title', 'slug'], populate: { children: { fields: ['title', 'slug'], }, }, }, }, } ```
同様の populate は GraphQL や Document Service API でも使えます([populate の理解](/cms/api/rest/guides/understanding-populate#populate-several-levels-deep-for-specific-relations))。 ::: #### Boolean {#boolean} Boolean フィールドは、真偽値(Yes / No、1 / 0、True / False など)を切り替える UI です。 #### JSON {#json} JSON フィールドは JSON 形式でオブジェクトや配列を格納します。 #### Email {#email} Email フィールドは形式チェック付きのメールアドレス入力欄です。 #### Password {#password} Password フィールドは暗号化されるパスワード入力欄です。 #### Enumeration {#enum} Enumeration フィールドは、ドロップダウンに出す値のリストを定義します。 :::caution Enumeration の値は、先頭が数字だけにならないようにします。GraphQL プラグイン有効時、数字だけの値が原因でサーバーが異常終了する場合があります。 ::: #### UID {#uid} UID フィールドは一意の識別子を設定します。同じコンテンツタイプの既存フィールドに基づいて自動生成することもできます。 :::tip Attached field に基づいてスラッグ用の UID を作れます。 ::: #### Rich Text (Markdown) {#rich-text-markdown} Rich Text (Markdown) フィールドは、Markdown でリッチテキストを書くための基本書式付きエディターです。長文向けです。 #### Components {#components} コンポーネントは複数フィールドのまとまりです。再利用できるフィールドセットとして、コンテンツタイプや Dynamic Zone に追加したり、別のコンポーネント内にネストしたりできます。 Content-type Builder でコンポーネントを設定するときは次のいずれかです。 - *Create a new component* で新規作成する([新しいコンポーネント](#new-component)を参照)。 - *Use an existing component* で既存のコンポーネントを選ぶ。 #### Dynamic zones {#dynamiczones} Dynamic Zone は、コンテンツタイプに追加できるコンポーネントの組み合わせです。コンテンツマネージャーでは管理者が Dynamic Zone 内のコンポーネントを自由に構成・並べ替えできるため、柔らかいコンテンツ構造に向きます。 Dynamic Zone の設定を終えたら、含めるコンポーネントも設定します。既存コンポーネントを選ぶか、新規に作れます。 :::caution Dynamic Zone では、異なるコンポーネントのあいだで、同じフィールド名なのに型が異なる組み合わせは使えません(Enumeration の場合は値の定義も一致させる必要があります)。 ::: #### カスタムフィールド {#custom-fields} [カスタムフィールド](/cms/features/custom-fields) は、コンテンツタイプやコンポーネントに新しい種類のフィールドを足して Strapi を拡張する仕組みです。インストール後([マーケットプレース](/cms/plugins/installing-plugins-via-marketplace)の手順を参照)、コンテンツタイプにフィールドを追加するとき *Custom* タブに表示されます。 各カスタムフィールドタイプには基本設定と詳細設定があります。 では利用可能なカスタムフィールドと、タイプごとの専用ドキュメント(設定項目を含む)を確認できます。 ### コンテンツタイプの削除 Content-type Builder からコンテンツタイプやコンポーネントを削除できます。コンテンツタイプを消すと、その型に基づくエントリーはコンテンツマネージャーからも消えます。コンポーネントを消した場合も、使われていたすべてのコンテンツタイプやエントリーから取り除かれます。 1. Content-type Builder のサブナビで、削除するコンテンツタイプまたはコンポーネント名をクリックします。 2. 編集画面で、名前右の **Edit** をクリックします。 3. 編集ウィンドウで **Delete** をクリックします。 4. 確認ダイアログで削除を確定します。 5. Content-type Builder のサブナビで **Save** をクリックします。 :::caution コンテンツタイプの削除は、Content-type Builder(および管理パネル上の定義)から消すだけです。その型で作られたデータ本体はデータベースに残る場合があります。詳細は関連する を参照してください。 ::: # カスタムフィールド(Custom Fields) Source: https://docs.strapi.io/cms/features/custom-fields # カスタムフィールド(Custom Fields) カスタムフィールドは、コンテンツタイプやコンポーネントに新しい種類のフィールドを足して Strapi を拡張します。プラグインで作成・追加したあとは、コンテンツタイプビルダーとコンテンツマネージャーで組み込みフィールドと同様に利用できます。 ## 設定 {#configuration} 用意されたカスタムフィールドは [Marketplace](https://market.strapi.io/plugins?categories=Custom+fields) から入手できます。インストール後は追加設定なしで使い始められます([使い方](#usage) も参照)。 独自のカスタムフィールドを開発することもできます。 ### 独自のカスタムフィールドを開発する 推奨はプラグインで足す方法ですが、アプリ専用のカスタムフィールドは、`src/index` および `src/admin/app` のグローバル `register` [関数](/cms/configurations/functions) 内に登録することもできます。 :::note 現状の制限 * カスタムフィールドをマーケットプレースで共有・配布できるのはプラグイン経由のみです。 * Strapi に新しいデータ型を足すことはできず、[モデルの属性](/cms/backend-customization/models#model-attributes) にある既存の組み込み型だけを使えます。 * 既存のデータ型を変更することはできません。 * relation、media、component、dynamic zone など Strapi 特有の型は、カスタムフィールドでは使えません。 ::: :::prerequisites CLI ジェネレーターでプラグインの骨組みを作っていない場合は、次のように `strapi-server.js` に直接宣言することもできます。 #### 管理パネルでのカスタムフィールドの登録 {#registering-a-custom-field-in-the-admin-panel} :::prerequisites ##### コンポーネント {#components} `app.customFields.register()` は、コンテンツマネージャーの編集ビューで使う `Input` React コンポーネントを含む `components` オブジェクトを渡す必要があります。 **例: Input コンポーネントを登録する** 次の例では、CLI ジェネレーターで `color-picker` プラグインを作成した想定です([プラグイン開発](/cms/plugins-development/developing-plugins.md) を参照)。
カスタムフィールドの Input コンポーネントへ渡される props | Prop | 説明 | 型 | | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | `attribute` | カスタムフィールドの基となった Strapi の型とオプションを含む属性オブジェクト | `{ type: String, customField: String }` | | `description` | [編集ビューの設定](/cms/features/content-manager#edit-view-settings) で設定したフィールドの説明 | :::tip `customFields` に渡される props の詳細と使い方は、Strapi コードベースの :::tip 設定オブジェクトの書き方の例は Strapi コードベースにあります。`base` は 、`advanced` は を参照してください。基本設定フォームは項目をインラインで列挙し、高度な設定フォームの項目は から読み込みます。 ::: ## 使い方 {#usage}
### 管理パネルで カスタムフィールドは、[マーケットプレース](/cms/plugins/installing-plugins-via-marketplace) からインストールするか、自作して Strapi に足せます。 Strapi に追加したあと、任意のコンテンツタイプにカスタムフィールドを追加できます。コンテンツタイプにフィールドを選ぶと、一覧は *Custom* タブに表示されます。 カスタムフィールドの型ごとに基本設定と高度な設定を持てます。 に利用可能なカスタムフィールドと、各フィールド専用の説明(設定を含む)があります。 ### コード上で 利用し始めたあと、カスタムフィールドはモデルのスキーマでは他の属性と同じように定義されます。 モデルの [attributes](/cms/backend-customization/models#model-attributes) で、`type: customField` として明示的に書きます。 ほかの型と比べ、カスタムフィールドの属性には次の点があります。 - `customField` 属性があります。値は登録済みのどのカスタムフィールドを使うかを示す一意の識別子で、次の2形式のいずれかです。 | 形式 | 由来 | |----------------------|------------------| | `plugin::plugin-name.field-name` | プラグインで作成したカスタムフィールド | | `global::field-name` | 現在の Strapi アプリ専用で、`register` [関数](/cms/configurations/functions) 内に直接作成したカスタムフィールド | - 登録時に定義した内容に応じて、カスタムフィールドには追加パラメーターを持てます([サーバーでの登録](#registering-a-custom-field-on-the-server) と[管理パネルでの登録](#registering-a-custom-field-in-the-admin-panel) を参照)。 **例: 単純な `color` カスタムフィールドのモデル定義** ```json title="/src/api/[apiName]/[content-type-name]/content-types/schema.json" { // … "attributes": { "color": { // name of the custom field defined in the Content-Type Builder "type": "customField", "customField": "plugin::color-picker.color", "options": { "format": "hex" } } } // … } ``` # データ管理(Data Management) Source: https://docs.strapi.io/cms/features/data-management # データ管理(Data Management) Data Management では、データのインポート、エクスポート、転送ができます。操作は CLI のみですが、設定の一部は管理パネルで行います。 ## 設定 {#configuration} Data Management の設定には、管理パネルで行うものと Strapi プロジェクトのコードで行うものがあります。 ### 管理パネル設定 {#admin-panel-settings} :::prerequisites `config/admin` の設定ファイルで `transfer.token.salt` を定義しておく必要があります([コードベース設定](#code-based-configuration) を参照)。 ::: **設定の場所:** ## 使い方 {#usage} Data Management は CLI 専用のため、インポート、エクスポート、転送の各コマンドはターミナルから実行します。各コマンドの詳細は次のページを参照してください。 # 下書きと公開(Draft & Publish) Source: https://docs.strapi.io/cms/features/draft-and-publish # 下書きと公開(Draft & Publish) Draft & Publish により、コンテンツの下書きを管理できます。 Strapi のバックエンドでは Document Service API でも `status` を扱えます。 # メール(Email) Source: https://docs.strapi.io/cms/features/email # メール(Email) Email 機能を使うと、Strapi アプリからサーバーまたは外部プロバイダー経由でメール送信できます。 ## 設定 {#configuration} Email 機能の設定の多くは Strapi プロジェクトのコード側で行います。管理パネルでは現在の設定、接続状態、プロバイダー機能を読み取り専用で確認でき、テストメール送信も実行できます。 :::info プロバイダーとホストの違い - メールプロバイダーは、Strapi がメール送信時に呼び出すパッケージです(例: 公式の Sendgrid、コミュニティの `@strapi/provider-email-nodemailer`)。Strapi から呼ばれたときの送信ロジックを実装します。 - プロバイダーホスト(サーバー)は、プロバイダーが公開する接続情報(SMTP ホスト名、ポート、REST API エンドポイントなど)を指します。API キーだけで隠蔽される場合もあれば、設定でホスト関連オプションの指定が必要な場合もあります。 Email 機能が扱うのは送信のみです。受信や受信メッセージ解析は組み込みプラグインの対象外で、プロバイダーの inbound webhook または独自連携で実装する必要があります。 ::: ### 管理パネル設定 **設定の場所:** ##### プロバイダーの設定 {#configuring-providers} Newly installed providers are enabled and configured in [the `/config/plugins` file](/cms/configurations/plugins). If this file does not exist you must create it. :::info メールプロバイダー固有の設定 - Each provider will have different configuration settings available. Review the respective entry for that provider in the [Marketplace](/cms/plugins/installing-plugins-via-marketplace) or :::note メモ * 環境ごとにプロバイダーを切り替える場合は `/config/env/${yourEnvironment}/plugins.js|ts` に環境別設定を定義します([環境設定](/cms/configurations/environment) 参照)。 * 同時に有効なのは 1 つのメールプロバイダーのみです。設定が反映されない場合は `plugins.js|ts` の配置先を確認してください。 * Strapi セットアップ時に作成される 2 つのメールテンプレートで新プロバイダーを試す場合、テンプレートの _shipper email_ は既定で `no-reply@strapi.io` です。プロバイダーに合わせて更新しないとテスト送信に失敗します([テンプレート設定](/cms/features/users-permissions#templating-emails) 参照)。 * 到達率を高めるには、プロバイダー側で SPF / DKIM を設定し、`defaultFrom` のドメインを検証済みドメインに合わせてください。 ::: ###### 環境別設定 プロバイダー設定では、`NODE_ENV` に応じて設定を切り替えたり、環境ごとの資格情報を使い分けたりすることがあります。 `/config/env/{env}/plugins.js|ts` に環境別設定を書くと、既定設定を上書きできます。 一部プロバイダーは API キーの代わりに(または併用で)SMTP 形式の接続情報を要求します。Strapi がプロバイダーホストへ接続できるよう `providerOptions` に設定してください。例えばコミュニティ版 Nodemailer では host、port、認証情報が必要です。 プロバイダーが host / port の代わりに単一 URL を提供する場合は、パッケージが期待するキー名で `providerOptions` にその URL(例: `https://api.eu.mailgun.net`)を渡します。 ##### カスタムプロバイダーの作成 独自プロバイダーを作成し npm 公開またはローカル利用する手順は次を参照してください。 ## 使い方 {#usage} Email 機能は Strapi のグローバル API を使うため、アプリ内のどこからでも呼び出せます。バックエンドの [コントローラー/サービス](#controller-service) 経由でも、管理パネルでのイベント応答([ライフサイクルフック](#lifecycle-hook))でも利用できます。 ### コントローラー/サービスでメール送信する {#controller-service} The Email feature has an `email` [service](/cms/backend-customization/services) that contains 2 functions to send emails: * `send()` はメール内容を直接指定して送る * `sendTemplatedEmail()` は Content Manager のデータでテンプレートを埋め、プログラムからの送信を簡素化する #### `send()` 関数を使う {#using-the-send-function} To trigger an email in response to a user action add the `send()` function to a [controller](/cms/backend-customization/controllers) or [service](/cms/backend-customization/services). The send function has the following properties: | プロパティ | 型 | 説明 | |---------------|-------------------------------|--------------------------------------------------------------------------------------------------| | `from` | `string` (email address) | Sender address. If not specified, uses `defaultFrom` from `plugins.js`. | | `to` | `string` (email address) | Recipient address. Required. | | `cc` | `string` (email address) | Carbon copy recipients. Optional. | | `bcc` | `string` (email address) | Blind carbon copy recipients. Optional. | | `replyTo` | `string` (email address) | Reply-to address. If not specified, uses `defaultReplyTo` from `plugins.js`. | | `subject` | `string` | Email subject. Required. | | `text` | `string` | Plain-text body. Either `text` or `html` is required. | | `html` | `string` | HTML body. Either `text` or `html` is required. | | `attachments` | `object[]` | Array of attachment objects. | | `headers` | `object` | Custom SMTP headers, for example `{ 'X-Custom-Header': 'value' }`. | | `priority` | `'high' \| 'normal' \| 'low'` | Email priority flag. | | `inReplyTo` | `string` | Message-ID of the email being replied to. Used for conversation threading. | | `references` | `string \| string[]` | Message-ID list this email references. Used for conversation threading. | | `envelope` | `object` | Custom SMTP envelope with `from` and `to` fields. Useful for bounce handling. | | `list` | `object` | RFC 2369 List-* headers. Enables one-click unsubscribe in Gmail and Outlook for newsletters. | | `icalEvent` | `object` | Calendar event invitation in iCalendar format. Attach with `{ method, content }`. | | `dsn` | `object` | Delivery Status Notification settings. Requests bounce or delivery confirmation reports. | :::note Nodemailer プロバイダー利用時 The Nodemailer provider uses an explicit allowlist for all `send()` fields. Unknown properties are silently dropped. For the complete list of supported fields — including `dkim`, `amp`, `raw`, `auth` (per-message OAuth2), and others — see the # 多言語(Internationalization) Source: https://docs.strapi.io/cms/features/internationalization # Internationalization (i18n) Internationalization では、言語ごとの設定である「ロケール」単位でコンテンツを管理します。 バックエンドの Document Service API でもロケールを扱えます。 # メディアライブラリ Source: https://docs.strapi.io/cms/features/media-library # メディアライブラリ :::info このページのコード設定の説明は、既定の upload プロバイダー向けです。別プロバイダーを使う場合は、そのドキュメントのパラメーターを参照してください。 ::: #### 利用可能なオプション {#available-options} 既定の upload プロバイダーでは、[`config/plugins`](/cms/configurations/plugins) 内の `upload.config` に次のオプションを宣言できます。いずれも任意です。 | パラメーター | 説明 | 型 | 既定値 | | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------- | ------- | | `providerOptions.localServer` | Upload サーバーのベースになる #### ローカルサーバー {#local-server} 既定では Strapi はローカルにアップロードしたファイル向けに `localServer` 設定を受け付けます。値は #### 最大ファイルサイズ {#max-file-size} 既定の 200 MB を超えるファイルを扱うには、リクエスト解析を担う Strapi のミドルウェアも設定する必要があります。Upload パッケージの `sizeLimit` に加えて行います。 :::caution リバースプロキシ・ロードバランサー・ファイアウォールでも大きなボディを許可する設定が必要な場合があります。例: ミドルウェアに加え、バイト数の整数として `sizeLimit` を [/config/plugins](/cms/configurations/plugins) に書けます。 #### セキュリティ #### アップロード要求のタイムアウト {#upload-request-timeout} 既定では `strapi.server.httpServer.requestTimeout` は 330 秒です。アップロードもこの時間に含まれます。 回線が遅い利用者が大きいファイルを送れるようにするには、この上限を伸ばす必要があることがあります。推奨は [`config/server`](/cms/configurations/server) の `http.serverOptions.requestTimeout` です。 別法として、Strapi 起動前に動く [`bootstrap`](/cms/configurations/functions#bootstrap) で `requestTimeout` をコードから変える方法もあります。一時的に無効化・再有効化するときなどに使います。 #### レスポンシブ画像 {#responsive-images} [管理パネルの `Responsive friendly upload`](#admin-panel-configuration) が有効なとき、プラグインは次のサイズのレスポンシブ画像を生成します。 | 名前 | 長辺の目安 | | :------ | :--------- | | large | 1000px | | medium | 750px | | small | 500px | サイズは `/config/plugins` で上書きできます。 :::caution ブレークポイントの変更は**新規**画像にだけ適用されます。既存画像の再生成やリサイズは行われません。 ::: ## 使い方 {#usage} **利用場所:** ### コードで公開アセットを使う {#public-assets} 公開アセットは、外部にそのまま配信したい静的ファイル(画像・動画・CSS など)です。 API が静的ファイルを返す必要があるため、新規の Strapi プロジェクトには既定で `/public` フォルダーがあります。このディレクトリ内のファイルは、他ルートに一致しないリクエストパスで、かつファイル名が一致すると配信されます(例: `./public/company-logo.png` は `/company-logo.png` で取得できます)。 :::tip リクエストパスがフォルダー名と一致するときは `index.html` が返ります(例: `/pictures` は `public/pictures/index.html` を返そうとします)。 ::: :::caution ドットファイル(`.htaccess` や `.gitignore` など、名前が `.` で始まるファイル)は公開されません。 ::: # プレビュー(Preview) Source: https://docs.strapi.io/cms/features/preview # プレビュー(Preview) プレビュー機能により、Strapi 管理パネルからフロントエンドアプリの表示を確認できます。コンテンツマネージャーの編集ビューでコンテンツを変えたとき、最終的な見え方を把握するのに役立ちます。
Next.js のキャッシュ Next.js では [キャッシュの扱い](https://nextjs.org/docs/app/building-your-application/caching) により、追加手順が要ることがあります。クライアントからサーバーへ API を呼び、サーバー側で再検証する、といった方法が必要になる場合があります。詳しくは Next.js のドキュメント(例: [revalidatePath()](https://nextjs.org/docs/app/building-your-application/caching#revalidatepath))を参照してください。
#### コンテンツソースマップ Live Preview は、Strapi のフィールドに対応するフロント上の箇所を特定できます。文字列コンテンツ(テキストフィールドなど)に、不可視の文字でメタデータを埋め込む **コンテンツソースマップ** で実現します。エンコード/デコードには を使います。 Content API のレスポンスにこのメタデータを載せるには、`strapi-encode-source-maps` ヘッダーを `true` にします。データ取得ユーティリティで付与します。**プレビュー表示中だけ**に限定してください。 Next.js では `next/headers` の `draftMode()` で draft モードかどうか判定し、API 呼び出しすべてにヘッダーを設定する例は次のとおりです。 ```typescript {20-23} contentType: string, params: Record = {} ): Promise { // Check if Next.js draft mode is enabled const { isEnabled: isDraftMode } = await draftMode(); try { const queryParams = { ...params }; // Add status=draft parameter when draft mode is enabled if (isDraftMode) { queryParams.status = "draft"; } const url = `${baseURL}/${contentType}?${qs.stringify(queryParams)}`; const response = await fetch(url, { headers: { // Enable content source maps in preview mode "strapi-encode-source-maps": isDraftMode ? "true" : "false", }, }); if (!response.ok) { throw new Error( `Failed to fetch data from Strapi (url=${url}, status=${response.status})` ); } return await response.json(); } catch (error) { console.error("Error fetching content:", error); throw error; } } ``` ## 使い方 {#usage} **利用場所:** Content Manager — 対象コンテンツタイプの編集ビュー :::strapi Preview と Live Preview CMS プランによって体験が変わります。 - Free プランでは Preview はフルスクリーンのみです。 - / プランでは **Live Preview** が使えます。コンテンツマネージャーの編集ビューとフロントのプレビューを並べて表示でき、プレビュー内のコンテンツをダブルクリックしてその場で編集できます。 ::: プレビューを正しく設定すると、[コンテンツマネージャーの編集ビュー](/cms/features/content-manager#overview) の右側に **Open preview** が表示されます。クリックすると、フロントでの見え方に近いプレビューが Strapi 管理パネル内に開きます。 プレビューが開いたあとにできること: - 左上の閉じる で編集ビューに戻る - プレビュー上部のドロップダウンでデスクトップ/モバイル表示を切り替える - 下書き版と公開版のプレビューを切り替える(コンテンツタイプで [Draft & Publish](/cms/features/draft-and-publish) が有効な場合) - 右上のリンク でプレビュー用 URL をコピーする(表示中のタブに応じて下書き用か公開版用かが変わります) :::note 編集ビューでは、未保存の変更があると **Open preview** は無効になります。保存してから再度プレビューできます。 ::: ### Live Preview {#live-preview} Live Preview は、有料 CMS プランで利用できる強化版の Preview です。 Free プランの Preview に加え、次が利用できます。 * **Side Editor** で、エントリーの編集ビューとフロントのプレビューを左右に並べて表示する。フルスクリーンと並列表示は と で切り替える。 * プレビューペインのコンテンツをダブルクリックすると、その場で編集できるポップオーバーが開き、フロント表示と Strapi の対応フィールドが同期する。 :::caution 試験的機能 この機能は試験的です。や の共有を歓迎します。 現時点の Live Preview には次の制限があります。 * Blocks フィールドは検出されず、Side Editor で変えてもプレビューに反映されません。更新後に **Save** すれば動作は続けられます。 * メディアアセットと Dynamic Zone 内のフィールドは扱われません。 ::: # ロールベースアクセス制御(RBAC) Source: https://docs.strapi.io/cms/features/rbac # ロールベースアクセス制御(RBAC) RBAC は、管理パネルを利用する **管理者** の管理に使います。具体的には、管理者アカウントとロールを管理します。 4. 右上の **Save** をクリックします。 :::tip 独自プラグインの管理画面権限を定義する手順は、[専用ガイド](/cms/plugins-development/guides/admin-permissions-for-plugins) を参照してください。 ::: #### 権限のカスタム条件 {#setting-custom-conditions-for-permissions} 各カテゴリの各権限には ## 使い方 {#usage} **利用場所:** *Settings > Administration panel > Users* *Users* 画面の表には、Strapi アプリの管理者が一覧されます。各行には氏名・メール・付与ロールなどの主なアカウント情報が表示され、初回ログインでアカウントを有効化済みかどうかに応じて active / inactive も表示されます。 この画面から次が行えます。 - テキスト検索 で管理者を探す - フィルター で絞り込む - 管理者アカウントを新規作成する([新しいアカウントを作成する](#creating-a-new-account)) - 管理者アカウントを削除する ([アカウントを削除する](#deleting-an-account)) - 管理者アカウントの詳細を開いて編集する ([アカウントを編集する](#editing-an-account)) :::tip 表のほとんどの列は、ヘッダー名をクリックして並べ替えできます。 ::: ### 新しいアカウントを作成する {#creating-a-new-account} 1. **Invite new user** をクリックします。 2. *Invite new user* で、新しい管理者の Details を入力します。 | User information | 手順 | | ---------------- | ---------------------------------------------------------------------------- | | First name | (必須)テキストボックスに名を入力します。 | | Last name | (必須)テキストボックスに姓を入力します。 | | Email | (必須)テキストボックスにメールアドレスを入力します。 | 3. Login 設定を入力します。 | Setting | 手順 | | ---------------- | --------------------------------------------------------------------------------------------------------------- | | User's roles | (必須)ドロップダウンで新しい管理者に付与するロールを選びます。 | | Connect with SSO | (任意)**TRUE** / **FALSE** で新規管理者を SSO と連携するか指定します。 | 4. *Add new user* ウィンドウ右下の **Invite user** をクリックします。 5. ウィンドウ上部に表示される URL が、初回ログイン用に新しい管理者へ共有する URL です。コピー でクリップボードにコピーします。 6. 右下の **Finish** で作成を完了します。表に新しい管理者が表示されます。 :::note 招待用 URL は、管理者がアカウントを有効化するまで、その管理者のレコードから参照できます。 ::: ### アカウントを削除する {#deleting-an-account} 管理者アカウントを 1 件または複数件まとめて削除できます。 1. 対象行の右側の削除 をクリックするか、左のチェックで複数選択してから表上の **Delete** をクリックします。 2. 確認ダイアログで **Confirm** をクリックします。 ### アカウントを編集する {#editing-an-account} 1. 編集する管理者名をクリックします。 2. *Details* でアカウント情報を編集します。 | User information | 手順 | | --------------------- | ----------------------- | | First name | テキストボックスに名を入力します。 | | Last name | テキストボックスに姓を入力します。 | | Email | テキストボックスにメールアドレスを入力します。 | | Username | テキストボックスにユーザー名を入力します。 | | Password | テキストボックスに新しいパスワードを入力します。 | | Confirm password | 確認のため同じパスワードを入力します。 | | Active | アカウントを有効にするには **TRUE** にします。 | 3. (任意)*Roles* でロールを編集します。 - ドロップダウンで新しいロールを選ぶか、既存に追加します。 - 付与済みロールを外すには削除 をクリックします。 4. 右上の **Save** をクリックします。 # リリース(Releases) Source: https://docs.strapi.io/cms/features/releases # Releases Releases では、管理者がエントリーをコンテナにまとめ、まとめて公開・非公開の操作を行えます。1 つのリリースに複数のコンテンツタイプや複数ロケールを混在できます。 ## 設定 {#configuration} コンテンツをリリースに含めたり、スケジュールして公開したりするには、まずリリースを作成します。公開スケジュールに使う既定タイムゾーンの変更や、不要になったリリースの削除もここで行います。 ### 既定タイムゾーンの選択 **設定場所:** Settings 1. _Default timezone_ ドロップダウンで既定のタイムゾーンを選びます。 2. **Save** をクリックします。 ### リリースの作成 {#creating-a-release} **設定場所:** Releases 1. 右上の **New Release** をクリックします。 2. リリース名を入力します。 3. (任意)手動公開ではなく日時指定する場合、**Schedule release** にチェックを入れ、公開日時とタイムゾーンを設定します。 4. **Continue** をクリックします。 :::tip から **Edit** で、あとからリリース名を変更できます。 ::: ### リリースの削除 **場所:** Releases リリースを削除しても、リリースに含まれていたコンテンツタイプのエントリー自体は削除されません。 1. 管理パネル右上の をクリックします。 2. **Delete** を選びます。 3. 確認ダイアログで **Confirm** をクリックします。 ## 使い方 {#usage} **利用場所:** Releases と Content Manager :::caution リリース経由の公開は下書きを公開版にする操作です。コンテンツタイプで [Draft & Publish](/cms/features/draft-and-publish) がオフのときは Releases は使えません。 ::: ### リリースへのコンテンツの追加 :::prerequisites - エントリーを追加する前に、 Releases からリリースを作成しておきます。 - リリースへ追加するには Content-Releases プラグインの適切な権限が必要です([管理者ロールの設定](/cms/features/users-permissions))。 ::: #### 1 件ずつ追加 **場所:** コンテンツマネージャーの編集ビュー 1. 画面右の _Entry_ 欄で をクリックします。 2. 一覧から **Add to release** をクリックします。 3. このエントリーを追加するリリースを選びます。 4. リリース公開時にこのエントリーを **Publish** するか **Unpublish** するか選び、**Continue** をクリックします。 右の *Releases* 欄に、このエントリーがどのリリースに入っているか表示されます。 :::info [リリースのスケジュール](#scheduling-a-release) が有効で、スケジュール済みリリースに追加した場合は、公開予定日時も表示されます。 ::: #### 複数件まとめて追加 **場所:** コンテンツマネージャーのリストビュー 1. 追加したいエントリーの行左のチェックボックスをオンにします。 2. 表ヘッダーの上にある **Add to release** をクリックします。 3. モーダルでリリースを選びます。 4. リリース公開時に **Publish** か **Unpublish** かを選び、**Continue** をクリックします。 ### リリースからコンテンツを外す {#removing-an-entry-from-a-release} **場所:** コンテンツマネージャーの編集ビュー 1. 右サイドバーの *Releases* で、該当リリース名の下にある をクリックします。 2. **Remove from release** をクリックします。 ### リリースのスケジュール {#scheduling-a-release} **場所:** Releases リリースは[手動で公開](#publishing-a-release)するか、日時とタイムゾーンを指定して自動公開できます。 スケジュールは次のタイミングで設定できます。 - [リリースを新規作成するとき](#creating-a-release) - すでにあるリリースを編集するとき 既存リリースをスケジュールする手順です。 1. リリースページで管理パネル右上の をクリックします。 2. **Edit** を選びます。 3. モーダルで **Schedule release** にチェックを入れます。 4. 公開日時とタイムゾーンを選びます。 5. **Save** をクリックします。 ### リリースの公開 {#publishing-a-release} **場所:** Releases リリースを公開すると、含まれる各エントリーに設定した操作(公開または非公開)が**同時に**実行されます。 公開するには、管理パネル右上の **Publish** をクリックします。その前にリリースと各エントリーのステータスを確認してください。 - 画面上部のバッジがリリース全体の状態を示します。 - `Empty` … まだエントリーが 1 件も入っていない - `Blocked` … エントリーはあるが、少なくとも 1 件に問題がありそのままでは公開できない - `Ready` … エントリーが追加されチェックも通過しており、公開できる - `Done` … リリースは実行済みで完了 - _Status_ 列は各エントリーの状態です。 - Already published … すでに公開済みで、このリリースの公開では変わらない - Already unpublished … すでに非公開で、このリリースの公開では変わらない - Ready to publish … リリースとともに公開できる状態 - Ready to unpublish … リリースとともに非公開にできる状態 - Not ready to publish … 必須フィールド不足などで公開できない。この場合リリースは *Blocked* のままになり、問題が解消されるまで公開できません。 リリースが `Blocked` で、一部エントリーが のときは、 から **Edit the entry** を開き、すべてのエントリーが になるよう修正します。 :::note 修正のたびに **Refresh** を押してリリースページの表示を更新してください。 ::: :::caution 一度公開したリリース自体は更新できません。同じエントリーグループを修正して再リリースすることはできないため、別のリリースを作成してください。 ::: # レビューワークフロー(Review Workflows) Source: https://docs.strapi.io/cms/features/review-workflows # レビューワークフロー(Review Workflows) Review Workflows 機能を使うと、複数のコンテンツタイプ向けにワークフローを作成・管理できます。各ワークフローには任意のレビュー段階を定義でき、チームでのコンテンツ作成フロー(下書きから公開まで)を円滑に進められます。 ## 設定 {#configuration} **設定の場所:** Settings > Global settings > Review Workflows [コンテンツマネージャー](/cms/features/content-manager) でレビューワークフローを利用するには、既定ワークフローを設定するか、新しいワークフローを作成する必要があります。 既定ワークフローには 4 つのステージ(To do、In progress、Ready to review、Reviewed)が用意されています。4 つすべて、必要に応じて編集・並べ替え・削除でき、新しいステージを追加することも可能です。 ### 新しいワークフローを作成する 1. **Create new workflow** をクリックするか、既存ワークフローの編集 をクリックします。 2. ワークフロー編集画面で次を設定します。 | 設定名 | 手順 | | -------------- | ------------------------------------------------------------------------ | | Workflow name | ワークフロー名を一意になるよう入力します。 | | Associated to | (任意)このワークフローを 1 つ以上の既存コンテンツタイプに割り当てます。 | | Stages | レビューステージを追加します([新しいステージを追加する](#adding-a-new-stage) を参照)。 | 3. **Save** をクリックします。新しいワークフローが一覧と、割り当てた各コンテンツタイプに表示されます。 :::note があります。 ::: ### ワークフローを編集する #### 新しいステージを追加する {#adding-a-new-stage} 1. **Add new stage** をクリックします。 2. *Stage name* を入力します。 3. *Color* を選びます。 4. エントリーがそのステージにあるときにステージ変更できる *Roles* を選びます。 5. **Save** をクリックします。 新しいステージは既定で末尾に追加されますが、 でいつでも並べ替えできます。 :::tip 各ステージのロール設定は、**Apply to all stages** で他ステージへ一括適用するか、ステージのコンテキストメニューの **Duplicate stage** を使って複製できます。 ::: #### ステージを複製する 1. 対象ステージのコンテキストメニューで **Duplicate Stage** をクリックします。 2. 複製したステージ名を変更します。 3. **Save** をクリックします。 #### ステージを削除する ステージを削除するには、ステージのコンテキストメニュー から **Delete** をクリックします。 レビュー待ちのエントリーがあるステージを削除すると、エントリーはワークフローの最初のステージへ移動します。各ワークフローには少なくとも 1 つのステージが必要なため、最後の 1 つは削除できません。 ### ワークフローを削除する ワークフローを削除するには、一覧画面の対象ワークフローの削除 をクリックします。 :::note 最後の 1 つのワークフローは削除できません。 ::: ## 使い方 {#usage} **利用場所:** Content Manager ### レビューステージを変更する {#change-review-stage} チームでコンテンツを作成・修正する流れの中で、レビューワークフローで定義した任意のステージへ変更できます。 1. 対象コンテンツタイプの編集ビューを開きます。 2. 画面右側の *Review Workflows* ボックスで、_Review stage_ のドロップダウンをクリックします。 3. エントリーの新しいレビューステージを選びます。自動保存されます。 ### 担当者を設定する {#change-assignee} レビューワークフロー対象のコンテンツタイプのエントリーは、Strapi の任意の管理ユーザーへレビュー担当として割り当てられます。 1. 対象コンテンツタイプの編集ビューを開きます。 2. 画面右側の *Review Workflows* ボックスで、_Assignee_ のドロップダウンをクリックします。 3. エントリーの新しい担当者を選びます。自動保存されます。 # シングルサインオン(SSO) Source: https://docs.strapi.io/cms/features/sso # シングルサインオン(SSO) SSO 機能を有効にすると、Strapi アプリの管理者は ID プロバイダー(例: Microsoft Azure Active Directory)経由でログインできます。 ## 使い方 {#usage} 通常の Strapi 管理者アカウントではなく、特定プロバイダーで管理パネルへログインする手順です。 1. Strapi アプリの管理パネル URL を開きます。 2. ログインフォーム下部に表示された任意のプロバイダーをクリックします。目的のプロバイダーが見つからない場合は で全一覧を開きます。 3. プロバイダーのログインページへリダイレクトされるので、そこで認証します。 # ユーザーと権限(Users & Permissions) Source: https://docs.strapi.io/cms/features/users-permissions # ユーザーと権限(Users & Permissions) Users & Permissions は、Strapi プロジェクトのエンドユーザーを管理します。エンドユーザーとは、 JSON Web Token(JWT)に基づく認証で API を保護し、グループごとに権限を扱う ACL(アクセス制御リスト)を提供します。 ## 管理パネルでの設定 Users & Permissions は、管理パネルの設定とコードの両方から設定します。 ### ロール {#roles} エンドユーザー向けのロールを作成・管理し、どの操作にアクセスできるかを設定できます。 #### 新しいロールを作成する {#creating-a-new-role} **場所:** The `admin_app` slice provides the following actions: | Action type | Payload type | Description | |---|---|---| | `admin/setAppTheme` | `string` | Set the theme (`'light'`, `'dark'`, or `'system'`) | | `admin/setAvailableThemes` | `string[]` | Updates `theme.availableThemes` in `admin_app` | | `admin/setLocale` | `string` | Set the locale (e.g., `'en'`, `'fr'`) | | `admin/setToken` | `string \| null` | Set the authentication token | | `admin/login` | `{ token: string, persist?: boolean }` | Login action with token and persistence option | | `admin/logout` | `void` | Logout action (no payload) | :::note When dispatching actions, use the Redux Toolkit action type format: `'sliceName/actionName'`. The admin slice is named `'admin'`, so actions follow the pattern `'admin/actionName'`. ::: ## Accessing the store instance For advanced use cases, you can access the store instance directly using the `useStore` hook: ## Complete example The following example combines all 3 patterns (useSelector, useDispatch, useStore) described on the present page: {Object.keys(availableLocales).map((locale) => ( ))} {lastChange && ( )} ); }; ```
{Object.keys(availableLocales).map((locale) => ( ))} {lastChange && ( )} ); }; ```
## Best practices - **Use `useSelector` for reading state.** Prefer [`useSelector`](#reading-state-with-useselector) over direct store access. It automatically subscribes to updates and re-renders components when the selected state changes. - **Clean up subscriptions.** Always unsubscribe from store subscriptions in `useEffect` cleanup functions to prevent memory leaks. - **Consider type safety.** For Redux state access in plugins, use `react-redux` hooks (`useSelector`, `useDispatch`) with plugin-local typing (for example `RootState` and `AppDispatch`). If you use Strapi admin utilities, import them from `@strapi/admin/strapi-admin` (not `@strapi/admin`). Avoid relying on undocumented typed Redux hooks as part of Strapi's public API until they are explicitly documented as stable. - **Avoid unnecessary dispatches.** Only dispatch actions when you need to update state. Reading state does not require dispatching actions. - **Respect core state.** Be careful when modifying core admin state (like theme or locale) as it affects the entire admin panel. Consider whether your plugin should modify global state or maintain its own local state. :::tip To add your own state to the Redux store, see [Adding custom reducers](#adding-custom-reducers) above. ::: # Content Manager APIs Source: https://docs.strapi.io/cms/plugins-development/content-manager-apis # Content Manager APIs Content Manager APIs are part of the [Admin Panel API](/cms/plugins-development/admin-panel-api). They are a way for Strapi plugins to add content or options to the [Content Manager](/cms/features/content-manager). The Content Manager APIs allow you to extend the Content Manager by adding functionality from your own plugin, just like you can do it with [Injection zones](/cms/plugins-development/admin-injection-zones). - Passing a function that receives the current elements and return the new ones. This is useful if, for example, you want to add something in a specific position in the list, like in the following code: ### Components You need to pass components to the API in order to add things to the Content Manager. Components are functions that receive some properties and return an object with some shape (depending on the function). Each component's return object is different based on the function you're using, but they receive similar properties, depending on whether you use a ListView or EditView API. Properties include important information about the document(s) you are viewing or editing. #### ListViewContext ```jsx interface ListViewContext { /** * Will be either 'single-types' | 'collection-types' */ collectionType: string; /** * The current selected documents in the table */ documents: Document[]; /** * The current content-type's model. */ model: string; } ``` #### EditViewContext ```jsx interface EditViewContext { /** * This will only be null if the content-type * does not have draft & publish enabled. */ activeTab: 'draft' | 'published' | null; /** * Will be either 'single-types' | 'collection-types' */ collectionType: string; /** * Will be undefined if someone is creating an entry. */ document?: Document; /** * Will be undefined if someone is creating an entry. */ documentId?: string; /** * Will be undefined if someone is creating an entry. */ meta?: DocumentMetadata; /** * The current content-type's model. */ model: string; } ``` :::tip More information about types and APIs can be found in ## Available APIs
### `addEditViewSidePanel` Use this to add new panels to the Edit view sidebar, just like in the following example where something is added to the Releases panel: ![addEditViewSidePanel](/img/assets/content-manager-apis/add-edit-view-side-panel.png) ```jsx addEditViewSidePanel(panels: DescriptionReducer | PanelComponent[]) ``` #### PanelComponent A `PanelComponent` receives the properties listed in [EditViewContext](#editviewcontext) and returns an object with the following shape: ```tsx type PanelComponent = (props: PanelComponentProps) => { title: string; content: React.ReactNode; }; ``` `PanelComponentProps` extends the [EditViewContext](#editviewcontext). ### `addDocumentAction` Use this API to add more actions to the Edit view or the List View of the Content Manager. There are 3 positions available: - `header` of the Edit view: ![Header of the Edit view](/img/assets/content-manager-apis/add-document-action-header.png) - `panel` of the Edit view: ![Panel of the Edit View](/img/assets/content-manager-apis/add-document-action-panel.png) - `table-row` of the List view: ![Table-row in the List View](/img/assets/content-manager-apis/add-document-action-tablerow.png) ```jsx addDocumentAction(actions: DescriptionReducer | DocumentActionComponent[]) ``` #### DocumentActionDescription The interface and properties of the API look like the following: ```jsx interface DocumentActionDescription { label: string; onClick?: (event: React.SyntheticEvent) => Promise | boolean | void; icon?: React.ReactNode; /** * @default false */ disabled?: boolean; /** * @default 'panel' * @description Where the action should be rendered. */ position?: DocumentActionPosition | DocumentActionPosition[]; dialog?: DialogOptions | NotificationOptions | ModalOptions; /** * @default 'secondary' */ variant?: ButtonProps['variant']; loading?: ButtonProps['loading']; } type DocumentActionPosition = 'panel' | 'header' | 'table-row' | 'preview' | 'relation-modal'; interface DialogOptions { type: 'dialog'; title: string; content?: React.ReactNode; variant?: ButtonProps['variant']; onConfirm?: () => void | Promise; onCancel?: () => void | Promise; } interface NotificationOptions { type: 'notification'; title: string; link?: { label: string; url: string; target?: string; }; content?: string; onClose?: () => void; status?: NotificationConfig['type']; timeout?: number; } interface ModalOptions { type: 'modal'; title: string; content: React.ComponentType<{ onClose: () => void; }> | React.ReactNode; footer?: React.ComponentType<{ onClose: () => void; }> | React.ReactNode; onClose?: () => void; } ``` ### `addDocumentHeaderAction` Use this API to add more actions to the header of the Edit view of the Content Manager: ![addEditViewSidePanel](/img/assets/content-manager-apis/add-document-header-action.png) ```jsx addDocumentHeaderAction(actions: DescriptionReducer | HeaderActionComponent[]) ``` #### HeaderActionDescription The interface and properties of the API look like the following: ```jsx interface HeaderActionDescription { disabled?: boolean; label: string; icon?: React.ReactNode; type?: 'icon' | 'default'; onClick?: (event: React.SyntheticEvent) => Promise | boolean | void; dialog?: DialogOptions; options?: Array<{ disabled?: boolean; label: string; startIcon?: React.ReactNode; textValue?: string; value: string; }>; onSelect?: (value: string) => void; value?: string; } interface DialogOptions { type: 'dialog'; title: string; content?: React.ReactNode; footer?: React.ReactNode; } ``` ### `addBulkAction` Use this API to add buttons that show up when entries are selected on the List View of the Content Manager, just like the "Add to Release" button for instance: ![addEditViewSidePanel](/img/assets/content-manager-apis/add-bulk-action.png) ```jsx addBulkAction(actions: DescriptionReducer | BulkActionComponent[]) ``` #### BulkActionDescription The interface and properties of the API look like the following: ```jsx interface BulkActionDescription { dialog?: DialogOptions | NotificationOptions | ModalOptions; disabled?: boolean; icon?: React.ReactNode; label: string; onClick?: (event: React.SyntheticEvent) => void; /** * @default 'default' */ type?: 'icon' | 'default'; /** * @default 'secondary' */ variant?: ButtonProps['variant']; } ``` # Plugin creation & setup Source: https://docs.strapi.io/cms/plugins-development/create-a-plugin # Plugin creation There are many ways to create a Strapi 5 plugin, but the fastest and recommended way is to use the Plugin SDK. The Plugin SDK is a set of commands orientated around developing plugins to use them as local plugins or to publish them on NPM and/or submit them to the Marketplace. With the Plugin SDK, you do not need to set up a Strapi project before creating a plugin. The present guide covers creating a plugin from scratch, linking it to an existing Strapi project, and publishing the plugin. If you already have an existing plugin, you can instead retrofit the plugin setup to utilise the Plugin SDK commands (please refer to the [Plugin SDK reference](/cms/plugins-development/plugin-sdk) for a full list of available commands). :::note This guide assumes you want to develop a plugin external to your Strapi project. However, the steps largely remain the same if you want to develop a plugin within your existing project. If you are not [using a monorepo](#monorepo) the steps are exactly the same. ::: :::prerequisites The path `my-strapi-plugin` can be replaced with whatever you want to call your plugin, including the path to where it should be created (e.g., `code/strapi-plugins/my-new-strapi-plugin`). You will be ran through a series of prompts to help you setup your plugin. If you selected yes to all options the final structure will be similar to the default [plugin structure](/cms/plugins-development/plugin-structure). ### Linking the plugin to your project In order to test your plugin during its development, the recommended approach is to link it to a Strapi project. Linking your plugin to a project is done with the `watch:link` command. The command will output explanations on how to link your plugin to a Strapi project. In a new terminal window, run the following commands: :::note In the above examples we use the name of the plugin (`my-strapi-plugin`) when linking it to the project. This is the name of the package, not the name of the folder. ::: Because this plugin is installed via `node_modules` you won't need to explicity add it to your `plugins` [configuration file](/cms/configurations/plugins), so running the [`develop command`](/cms/cli#strapi-develop) to start your Strapi project will automatically pick up your plugin. Now that your plugin is linked to a project, run `yarn develop` or `npm run develop` to start the Strapi application. You are now ready to develop your plugin how you see fit! If you are making server changes, you will need to restart your server for them to take effect. ### Building the plugin for publishing When you are ready to publish your plugin, you will need to build it. To do this, run the following command: The above commands will not only build the plugin, but also verify that the output is valid and ready to be published. You can then publish your plugin to NPM as you would any other package. :::tip Upgrading from SDK Plugin v5 If you're upgrading from `@strapi/sdk-plugin` v5 to v6: * Delete any `packup.config.ts` file from your plugin (it is no longer used). * Rely on `package.json#exports` for build configuration (it is now derived automatically). * Add `--sourcemap` to your build command if you need sourcemaps (they now default to off). No other changes are required. ::: ## Working with the Plugin SDK in a monorepo environment {#monorepo} If you are working with a monorepo environment to develop your plugin, you don't need to use the `watch:link` command because the monorepo workspace setup will handle the symlink. You can use the `watch` command instead. However, if you are writing admin code, you might add an `alias` that targets the source code of your plugin to make it easier to work with within the context of the admin panel: ```ts config.resolve.alias = { ...config.resolve.alias, 'my-strapi-plugin': path.resolve( __dirname, // We've assumed the plugin is local. '../plugins/my-strapi-plugin/admin/src' ), }; return config; }; ``` :::caution Because the server looks at the `server/src/index.ts|js` file to import your plugin code, you must use the `watch` command otherwise the code will not be transpiled and the server will not be able to find your plugin. ::: ### Configuration with a local plugin Since the Plugin SDK is primarily designed for developing plugins, not locally, the configuration needs to be adjusted manually for local plugins. When developing your plugin locally (using `@strapi/sdk-plugin`), your plugins configuration file looks like in the following example: ```js title="/config/plugins.js|ts" myplugin: { enabled: true, resolve: `./src/plugins/local-plugin`, }, ``` However, this setup can sometimes lead to errors such as the following: ```js Error: 'X must be used within StrapiApp'; ``` This error often occurs when your plugin attempts to import core Strapi functionality, for example using: ```js ``` To resolve the issue, remove `@strapi/strapi` as a dev dependency from your plugin. This ensures that your plugin uses the same instance of Strapi's core modules as the main application, preventing conflicts and the associated errors. ## Setting a local plugin in a monorepo environment without the Plugin SDK In a monorepo, you can configure your local plugin without using the Plugin SDK by adding 2 entry point files at the root of your plugin: - server entry point: `strapi-server.js|ts` - admin entry point: `strapi-admin.js|ts` ### Server entry point The server entry point file initializes your plugin's server-side functionalities. The expected structure for `strapi-server.js` (or its TypeScript variant) is: ```js module.exports = () => { return { register, config, controllers, contentTypes, routes, }; }; ``` Here, you export a function that returns your plugin's core components such as controllers, routes, and configuration. For more details, please refer to the [Server API reference](/cms/plugins-development/server-api). ### Admin entry point The admin entry point file sets up your plugin within the Strapi admin panel. The expected structure for `strapi-admin.js` (or its TypeScript variant) is: ```js register(app) {}, bootstrap() {}, registerTrads({ locales }) {}, }; ``` This object includes methods to register your plugin with the admin application, perform bootstrapping actions, and handle translations. For more details, please refer to the [Admin Panel API reference](/cms/plugins-development/admin-panel-api). :::tip For a complete example of how to structure your local plugin in a monorepo environment, please check out our . ::: # Developing plugins Source: https://docs.strapi.io/cms/plugins-development/developing-plugins # Developing Strapi plugins Strapi allows the development of plugins that work exactly like the built-in plugins or 3rd-party plugins available from the :::strapi Custom fields plugins Plugins can also be used to add [custom fields](/cms/features/custom-fields) to Strapi. ::: ## Guides
:::strapi Additional resources The can also include additional information useful while developing a Strapi plugin. ::: # How to create admin permissions from plugins Source: https://docs.strapi.io/cms/plugins-development/guides/admin-permissions-for-plugins # How to create admin permissions from plugins When [developing a Strapi plugin](/cms/plugins-development/developing-plugins), you might want to create admin permissions for your plugin. By doing that you can hook in to the [RBAC system](/cms/features/rbac) of Strapi to selectively grant permissions to certain pieces of your plugin. To create admin permissions for your Strapi plugin, you'll need to register them on the server side before implementing them on the admin side. ## Register the permissions server side Each individual permission has to registered in the bootstrap function of your plugin, as follows: ## Implement permissions on the admin panel side Before we can implement our permissions on the admin panel side we have to define them in a reusable configuration file. This file can be stored anywhere in your plugin admin code. You can do that as follows: ```js title="/src/plugins/my-plugin/admin/src/permissions.js|ts" const pluginPermissions = { 'accessOverview': [{ action: 'plugin::my-plugin.overview.access', subject: null }], 'accessSidebar': [{ action: 'plugin::my-plugin.sidebar.access', subject: null }], }; ``` ### Page permissions Once you've created the configuration file you are ready to implement your permissions. If you've bootstrapped your plugin using the [plugin SDK init command](/cms/plugins-development/plugin-sdk#npx-strapisdk-plugin-init), you will have an example `HomePage.tsx` file. To implement page permissions you can do the following: ```js title="/src/plugins/my-plugin/admin/src/pages/HomePage.jsx|tsx" {2,5,12,16} const HomePage = () => { const { formatMessage } = useIntl(); return ( ); }; ``` You can see how we use our permissions configuration file together with the `` component to require specific permissions in order to view this page. ### Menu link permissions The previous example makes sure that the permissions of a user that visits your page directly will be validated. However, you might want to remove the menu link to that page as well. To do that, you'll have to make a change to the `addMenuLink` implementation. You can do as follows: ```js title="/src/plugins/my-plugin/admin/src/index.js|ts" {21-23,5} register(app) { app.addMenuLink({ to: `plugins/${PLUGIN_ID}`, icon: PluginIcon, intlLabel: { id: `${PLUGIN_ID}.plugin.name`, defaultMessage: PLUGIN_ID, }, Component: async () => { const { App } = await import('./pages/App'); return App; }, permissions: [ pluginPermissions.accessOverview[0], ], }); app.registerPlugin({ id: PLUGIN_ID, initializer: Initializer, isReady: false, name: PLUGIN_ID, }); }, }; ``` ### Custom permissions with the `useRBAC` hook To get even more control over the permission of the admin user you can use the `useRBAC` hook. With this hook you can use the permissions validation just like you want, as in the following example: ```js title="/src/plugins/my-plugin/admin/src/components/Sidebar.jsx|tsx" const Sidebar = () => { const { allowedActions: { canAccessSidebar }, } = useRBAC(pluginPermissions); if (!canAccessSidebar) { return null; } return (
Sidebar component
); }; ``` # How to create components for Strapi plugins Source: https://docs.strapi.io/cms/plugins-development/guides/create-components-for-plugins # How to create components for Strapi plugins When [developing a Strapi plugin](/cms/plugins-development/developing-plugins), you might want to create reusable components for your plugin. Components in Strapi are reusable data structures that can be used across different content-types. To create components for your Strapi plugin, you'll need to follow a similar approach to creating content-types, but with some specific differences. ## Creating components You can create components for your plugins in 2 different ways: using the Content-Type Builder (recommended way) or manually. ### Using the Content-Type Builder The recommended way to create components for your plugin is through the Content-Type Builder in the admin panel. The [Content-Type Builder documentation](/cms/features/content-type-builder#new-component) provides more details on this process. ### Creating components manually If you prefer to create components manually, you'll need to: 1. Create a component schema in your plugin's structure. 2. Make sure the component is properly registered. Components for plugins should be placed in the appropriate directory within your plugin structure. You would typically create them within the server part of your plugin (see [plugin structure documentation](/cms/plugins-development/plugin-structure)). For more detailed information about components in Strapi, you can refer to the [Model attributes documentation](/cms/backend-customization/models#components-json). ## Reviewing the component structure Components in Strapi follow the following format in their definition: ```javascript title="/my-plugin/server/components/category/component-name.json" { "attributes": { "myComponent": { "type": "component", "repeatable": true, "component": "category.componentName" } } } ``` ## Component schema example A component schema defines the structure of a reusable data fragment. Here is an example of a component schema for a plugin: ```json title="my-plugin/server/components/my-category/my-component.json" { "collectionName": "components_my_category_my_components", "info": { "displayName": "My Component", "icon": "align-justify" }, "attributes": { "name": { "type": "string", "required": true }, "description": { "type": "text" } } } ``` This configuration ensures your components will be available in both the Content-Type Builder and Content Manager when used in a content-type that has `pluginOptions` visibility enabled. # How to pass data from server to admin panel with a Strapi plugin Source: https://docs.strapi.io/cms/plugins-development/guides/pass-data-from-server-to-admin # How to pass data from server to admin panel with a Strapi plugin Strapi is **headless** . The admin panel is completely separate from the server. When [developing a Strapi plugin](/cms/plugins-development/developing-plugins) you might want to pass data from the `/server` to the `/admin` folder. Within the `/server` folder you have access to the Strapi object and can do database queries whereas in the `/admin` folder you can't. Passing data from the `/server` to the `/admin` folder can be done using the admin panel's Axios instance: To pass data from the `/server` to `/admin` folder you would first [create a custom admin route](#create-a-custom-admin-route) and then [get the data returned in the admin panel](#get-the-data-in-the-admin-panel). ## Create a custom admin route Admin routes are like the routes that you would have for any controller, except that the `type: 'admin'` declaration hides them from the general API router, and allows you to access them from the admin panel. The following code will declare a custom admin route for the `my-plugin` plugin: ```js title="/my-plugin/server/routes/index.js" module.exports = { 'pass-data': { type: 'admin', routes: [ { method: 'GET', path: '/pass-data', handler: 'myPluginContentType.index', config: { policies: [], auth: false, }, }, ] } // ... }; ``` This route will call the `index` method of the `myPluginContentType` controller when you send a GET request to the `/my-plugin/pass-data` URL endpoint. Let's create a basic custom controller that simply returns a simple text: ```js title="/my-plugin/server/controllers/my-plugin-content-type.js" 'use strict'; module.exports = { async index(ctx) { ctx.body = 'You are in the my-plugin-content-type controller!'; } } ``` This means that when sending a GET request to the `/my-plugin/pass-data` URL endpoint, you should get the `You are in the my-plugin-content-type controller!` text returned with the response. ## Get the data in the admin panel Any request sent from an admin panel component to the endpoint for which we defined the custom route `/my-plugin/pass-data` should now return the text message returned by the custom controller. So for instance, if you create an `/admin/src/api/foobar.js` file and copy and paste the following code example: ```js title="/my-plugin/admin/src/api/foobar.js" const foobarRequests = { getFoobar: async () => { const data = await axios.get(`/my-plugin/pass-data`); return data; }, }; ``` You will be able to use `foobarRequests.getFoobar()` in the code of an admin panel component and have it return the `You are in the my-plugin-content-type controller!` text with the data. For instance, within a React component, you could use `useEffect` to get the data after the component initializes: ```js title="/my-plugin/admin/src/components/MyComponent/index.js" const [foobar, setFoobar] = useState([]); // … useEffect(() => { foobarRequests.getFoobar().then(res => { setFoobar(res.data); }); }, [setFoobar]); // … ``` This would set the `You are in the my-plugin-content-type controller!` text within the `foobar` data of the component's state. # How to store and access data from a Strapi plugin Source: https://docs.strapi.io/cms/plugins-development/guides/store-and-access-data # How to store and access data from a Strapi plugin To store data with a Strapi [plugin](/cms/plugins-development/developing-plugins), use a plugin content-type. Plugin content-types work exactly like other [content-types](/cms/backend-customization/models). Once the content-type is [created](#create-a-content-type-for-your-plugin), you can start [interacting with the data](#interact-with-data-from-the-plugin). ## Create a content-type for your plugin To create a content-type with the CLI generator, run the following command in a terminal within the `server/src/` directory of your plugin: The generator CLI is interactive and asks a few questions about the content-type and the attributes it will contain. Answer the first questions, then for the `Where do you want to add this model?` question, choose the `Add model to existing plugin` option and type the name of the related plugin when asked.
Generating a content-type plugin with the CLI
The strapi generate content-type CLI generator is used to create a basic content-type for a plugin.

The CLI will generate some code required to use your plugin, which includes the following: - the [content-type schema](/cms/backend-customization/models#model-schema) - and a basic [controller](/cms/backend-customization/controllers), [service](/cms/backend-customization/services), and [route](/cms/backend-customization/routes) for the content-type :::tip You may want to create the whole structure of your content-types either entirely with the CLI generator or by directly creating and editing `schema.json` files. We recommend you first create a simple content-type with the CLI generator and then leverage the [Content-Type Builder](/cms/features/content-type-builder) in the admin panel to edit your content-type. If your content-type is not visible in the admin panel, you might need to set the `content-manager.visible` and `content-type-builder.visible` parameters to `true` in the `pluginOptions` object of the content-type schema:
Making a plugin content-type visible in the admin panel: The following highlighted lines in an example `schema.json` file show how to make a plugin content-type visible to the Content-Type Builder and Content-Manager: ```json title="/server/content-types/my-plugin-content-type/schema.json" {13-20} showLineNumbers { "kind": "collectionType", "collectionName": "my_plugin_content_types", "info": { "singularName": "my-plugin-content-type", "pluralName": "my-plugin-content-types", "displayName": "My Plugin Content-Type" }, "options": { "draftAndPublish": false, "comment": "" }, "pluginOptions": { "content-manager": { "visible": true }, "content-type-builder": { "visible": true } }, "attributes": { "name": { "type": "string" } } } ```
::: ### Ensure plugin content-types are imported The CLI generator might not have imported all the related content-type files for your plugin, so you might have to make the following adjustments after the `strapi generate content-type` CLI command has finished running: 1. In the `/server/index.js` file, import the content-types: ```js {7,22} showLineNumbers title="/server/index.js" 'use strict'; const register = require('./register'); const bootstrap = require('./bootstrap'); const destroy = require('./destroy'); const config = require('./config'); const contentTypes = require('./content-types'); const controllers = require('./controllers'); const routes = require('./routes'); const middlewares = require('./middlewares'); const policies = require('./policies'); const services = require('./services'); module.exports = { register, bootstrap, destroy, config, controllers, routes, services, contentTypes, policies, middlewares, }; ``` 2. In the `/server/content-types/index.js` file, import the content-type folder: ```js title="/server/content-types/index.js" 'use strict'; module.exports = { // In the line below, replace my-plugin-content-type // with the actual name and folder path of your content type "my-plugin-content-type": require('./my-plugin-content-type'), }; ``` 3. Ensure that the `/server/content-types/[your-content-type-name]` folder contains not only the `schema.json` file generated by the CLI, but also an `index.js` file that exports the content-type with the following code: ```js title="/server/content-types/my-plugin-content-type/index.js 'use strict'; const schema = require('./schema'); module.exports = { schema, }; ``` ## Interact with data from the plugin Once you have created a content-type for your plugin, you can create, read, update, and delete data. :::note A plugin can only interact with data from the `/server` folder. If you need to update data from the admin panel, please refer to the [passing data guide](/cms/plugins-development/guides/pass-data-from-server-to-admin). ::: To create, read, update, and delete data, you can use either the [Document Service API](/cms/api/document-service) or the [Query Engine API](/cms/api/query-engine). While it's recommended to use the Document Service API, especially if you need access to components or dynamic zones, the Query Engine API is useful if you need unrestricted access to the underlying database. Use the `plugin::your-plugin-slug.the-plugin-content-type-name` syntax for content-type identifiers in Document Service and Query Engine API queries. **Example:** Here is how to find all the entries for the `my-plugin-content-type` collection type created for a plugin called `my-plugin`: ```js // Using the Document Service API let data = await strapi.documents('plugin::my-plugin.my-plugin-content-type').findMany(); // Using the Query Engine API let data = await strapi.db.query('plugin::my-plugin.my-plugin-content-type').findMany(); ```` :::tip You can access the database via the `strapi` object which can be found in `middlewares`, `policies`, `controllers`, `services`, as well as from the `register`, `boostrap`, `destroy` lifecycle functions. ::: # Plugin SDK reference Source: https://docs.strapi.io/cms/plugins-development/plugin-sdk # Plugin SDK reference The Plugin SDK is set of commands provided by the package orientated around developing plugins to use them as local plugins or to publish them on NPM and/or submit them to the Marketplace. The present documentation lists the available Plugin SDK commands. The [associated guide](/cms/plugins-development/create-a-plugin) illustrates how to use these commands to create a plugin from scratch, link it to an existing project, and publish it. ## npx @strapi/sdk-plugin init Create a new plugin at a given path. ```bash npx @strapi/sdk-plugin init ``` | Arguments | Type | Description | Default | | --------- | :----: | ------------------ | ------------------------- | | `path` | string | Path to the plugin | `./src/plugins/my-plugin` | | Option | Type | Description | Default | | ------------- | :--: | --------------------------------------- | ------- | | `-d, --debug` | - | Enable debugging mode with verbose logs | false | | `--silent` | - | Do not log anything | false | ## strapi-plugin build Bundle the Strapi plugin for publishing. ```bash strapi-plugin build ``` | Option | Type | Description | Default | | -------------- | :----: | ----------------------------------------------------------------------------------------------------------------- | ------- | | `--force` | string | Automatically answer "yes" to all prompts, including potentially destructive requests, and run non-interactively. | - | | `-d, --debug` | - | Enable debugging mode with verbose logs | false | | `--silent` | - | Do not log anything | false | | `--minify` | - | Minify the output | false | | `--sourcemap` | - | Produce sourcemaps | false | :::note As of v6, the build configuration is automatically derived from your `package.json` exports field. No configuration file (such as `vite.config.ts` or `rollup.config.ts`) is needed. ::: ## strapi-plugin watch:link Recompiles the plugin automatically on changes and runs `yalc push --publish`. For testing purposes, it is very convenient to link your plugin to an existing application to experiment with it in real condition. This command is made to help you streamline this process. ```bash strapi-plugin watch:link ``` | Option | Type | Description | Default | | ------------- | :--: | --------------------------------------- | ------- | | `-d, --debug` | - | Enable debugging mode with verbose logs | false | | `--silent` | - | Do not log anything | false | ## strapi-plugin watch Watch the plugin source code for any change and rebuild it everytime. Useful when implementing your plugin and testing it in an application. ```bash strapi-plugin watch ``` | Option | Type | Description | Default | | ------------- | :--: | --------------------------------------- | ------- | | `-d, --debug` | - | Enable debugging mode with verbose logs | false | | `--silent` | - | Do not log anything | false | ## strapi-plugin verify Verify the output of the plugin before publishing it. ```bash strapi-plugin verify ``` | Option | Type | Description | Default | | ------------- | :--: | --------------------------------------- | ------- | | `-d, --debug` | - | Enable debugging mode with verbose logs | false | | `--silent` | - | Do not log anything | false | # Plugin structure Source: https://docs.strapi.io/cms/plugins-development/plugin-structure # Plugin structure When [creating a plugin with Plugin SDK](/cms/plugins-development/create-a-plugin), Strapi generates the following boilerplate structure for you in the `/src/plugins/my-plugin` folder: A Strapi plugin is divided into 2 parts, each living in a different folder and offering a different API: | Plugin part | Description | Folder | API | |-------------|-------------|--------------|-----| | Admin panel | Includes what will be visible in the [admin panel](/cms/intro) (components, navigation, settings, etc.) | `admin/` |[Admin Panel API](/cms/plugins-development/admin-panel-api)| | Backend server | Includes what relates to the [backend server](/cms/backend-customization) (content-types, controllers, middlewares, etc.) |`server/` |[Server API](/cms/plugins-development/server-api)|
:::note Notes about the usefulness of the different parts for your specific use case - **Server-only plugin**: You can create a plugin that will just use the server part to enhance the API of your application. For instance, this plugin could have its own visible or invisible content-types, controller actions, and routes that are useful for a specific use case. In such a scenario, you don't need your plugin to have an interface in the admin panel. - **Admin panel plugin vs. application-specific customization**: You can create a plugin to inject some components into the admin panel. However, you can also achieve this by creating a `/src/admin/index.js` file and invoking the `bootstrap` lifecycle function to inject your components. In this case, deciding whether to create a plugin depends on whether you plan to reuse and distribute the code or if it's only useful for a unique Strapi application. :::
:::strapi What to read next? The next steps of your Strapi plugin development journey will require you to use any of the Strapi plugins APIs. 2 different types of resources help you understand how to use the plugin APIs: - The reference documentation for the [Admin Panel API](/cms/plugins-development/admin-panel-api) and [Server API](/cms/plugins-development/server-api) give an overview of what is possible to do with a Strapi plugin. - [Guides](/cms/plugins-development/developing-plugins#guides) cover some specific, use-case based examples. ::: # Plugins extension Source: https://docs.strapi.io/cms/plugins-development/plugins-extension # Plugins extension Strapi comes with plugins that can be installed from the [Marketplace](/cms/plugins/installing-plugins-via-marketplace#installing-marketplace-plugins-and-providers) or as npm packages. You can also create your own plugins (see [plugins development](/cms/plugins-development/developing-plugins)) or extend the existing ones. :::warning * Any plugin update could break this plugin's extensions. * New versions of Strapi will be released with migration guides when required, but these guides never cover plugin extensions. Consider forking a plugin if extensive customizations are required. * Currently, the admin panel part of a plugin can only be extended using , but please consider that doing so might break your plugin in future versions of Strapi. ::: Plugin extensions code is located in the `./src/extensions` folder (see [project structure](/cms/project-structure)). Some plugins automatically create files there, ready to be modified.
Example of extensions folder structure ```bash /extensions /some-plugin-to-extend strapi-server.js|ts /content-types /some-content-type-to-extend schema.json /another-content-type-to-extend schema.json /another-plugin-to-extend strapi-server.js|ts ```
Plugins can be extended in 2 ways: - [extending the plugin's content-types](#extending-a-plugins-content-types) - [extending the plugin's interface](#extending-a-plugins-interface) (e.g. to add controllers, services, policies, middlewares and more) ## Extending a plugin's content-types A plugin's Content-Types can be extended in 2 ways: using the programmatic interface within `strapi-server.js|ts` and by overriding the content-types schemas. The final schema of the content-types depends on the following loading order: 1. the content-types of the original plugin, 2. the content-types overridden by the declarations in the [schema](/cms/backend-customization/models#model-schema) defined in `./src/extensions/plugin-name/content-types/content-type-name/schema.json` 3. the content-types declarations in the [`contentTypes` export from `strapi-server.js|ts`](/cms/plugins-development/server-content-types) 4. the content-types declarations in the [`register()` function](/cms/configurations/functions#register) of the Strapi application To overwrite a plugin's [content-types](/cms/backend-customization/models): 1. _(optional)_ Create the `./src/extensions` folder at the root of the app, if the folder does not already exist. 2. Create a subfolder with the same name as the plugin to be extended. 3. Create a `content-types` subfolder. 4. Inside the `content-types` subfolder, create another subfolder with the same [singularName](/cms/backend-customization/models#model-information) as the content-type to overwrite. 5. Inside this `content-types/name-of-content-type` subfolder, define the new schema for the content-type in a `schema.json` file (see [schema](/cms/backend-customization/models#model-schema) documentation). 6. _(optional)_ Repeat steps 4 and 5 for each content-type to overwrite. ## Extending a plugin's interface When a Strapi application is initializing, plugins, extensions and global lifecycle functions events happen in the following order: 1. Plugins are loaded and their interfaces are exposed. 2. Files in `./src/extensions` are loaded. 3. The `register()` and `bootstrap()` functions in `./src/index.js|ts` are called. A plugin's interface can be extended at step 2 (i.e. within `./src/extensions`) or step 3 (i.e. inside `./src/index.js|ts`). :::note If your Strapi project is TypeScript-based, please ensure that the `index` file has a TypeScript extension (i.e., `src/index.ts`) otherwise it will not be compiled. ::: ### Within the extensions folder To extend a plugin's server interface using the `./src/extensions` folder: 1. _(optional)_ Create the `./src/extensions` folder at the root of the app, if the folder does not already exist. 2. Create a subfolder with the same name as the plugin to be extended. 3. Create a `strapi-server.js|ts` file to extend a plugin's back end using the [Server API](/cms/plugins-development/server-api). 4. Within this file, define and export a function. The function receives the `plugin` interface as an argument so it can be extended.
Example of backend extension ```js title="./src/extensions/some-plugin-to-extend/strapi-server.js|ts" module.exports = (plugin) => { plugin.controllers.controllerA.find = (ctx) => {}; plugin.policies[newPolicy] = (ctx) => {}; plugin.routes['content-api'].routes.push({ method: 'GET', path: '/route-path', handler: 'controller.action', }); return plugin; }; ```
:::note The `strapi-server.js|ts` file is also where you can override the image function, by replacing the Upload plugin's `generateFileName()` function so that it generates custom image names.
Example of custom file-naming logic ```js title="./src/extensions/upload/strapi-server.js|ts" module.exports = (plugin) => { plugin.services['image-manipulation'].generateFileName = (file) => { // Example: prefix a timestamp before the generated base name return `${Date.now()}_${name}`; }; return plugin; }; ```
::: `generateFileName()` belongs to the Upload plugin's `image-manipulation` service and expects a single `name: string` argument. :::caution This customization relies on an internal Upload plugin service (`image-manipulation`). Internal extension points are not part of Strapi's stable public API and can change between versions. ::: ### Within the register and bootstrap functions To extend a plugin's interface within `./src/index.js|ts`, use the `bootstrap()` and `register()` [functions](/cms/configurations/functions) of the whole project, and access the interface programmatically with [getters](/cms/plugins-development/server-getters-usage).
Example of extending a plugin's content-type within ./src/index.js|ts ```js title="./src/index.js|ts" module.exports = { register({ strapi }) { const contentTypeName = strapi.contentType('plugin::my-plugin.content-type-name') contentTypeName.attributes = { // Spread previous defined attributes ...contentTypeName.attributes, // Add new, or override attributes 'toto': { type: 'string', } } }, bootstrap({ strapi }) {}, }; ```
# Server API for plugins Source: https://docs.strapi.io/cms/plugins-development/server-api # Server API for plugins: An overview A Strapi plugin can interact with both the back end and the front end of a Strapi application. The Server API covers the back-end part: it defines what the plugin registers, exposes, and executes on the Strapi server. The server part is defined in the entry file, which exports an object (or a function returning an object). That object describes what the plugin contributes to the server. For more information on how plugins can customize the admin panel UI, see [Admin Panel API](/cms/plugins-development/admin-panel-api). All server code can technically live in the single entry file, but splitting each concern into its own folder, as generated by the Plugin SDK, is strongly recommended. The examples in this documentation follow that structure. :::note Notes * The entry file accepts either an object literal or a function that returns the same object shape. When the function form is used, Strapi calls it with `{ env }` (not `{ strapi }`) while loading the plugin module. * `config` is a configuration object, not an executable lifecycle hook. Unlike `register()`, `bootstrap()`, or `destroy()`, it is not called as a function during the plugin lifecycle. It is loaded at startup and used to set defaults and validate user configuration. See [server lifecycle](/cms/plugins-development/server-lifecycle) for more information. ::: ## Available actions The Server API lets a plugin take advantage of several building blocks to define its server-side behavior. Use the following table to find which capability matches your goal: | Goal | Parameter to use | When it runs | | --- | --- | --- | | Run code before the server starts | [`register()`](/cms/plugins-development/server-lifecycle#register) | Before database and routing initialization | | Run code after all plugins are loaded | [`bootstrap()`](/cms/plugins-development/server-lifecycle#bootstrap) | After database, routes, and permissions are initialized | | Clean up resources on shutdown | [`destroy()`](/cms/plugins-development/server-lifecycle#destroy) | On shutdown | | Define plugin options with defaults and validation | [`config`](/cms/plugins-development/server-configuration) | Loaded at startup | | Declare plugin content-types | [`contentTypes`](/cms/plugins-development/server-content-types) | Loaded at startup | | Expose HTTP endpoints | [`routes`](/cms/plugins-development/server-routes) | Loaded at startup | | Handle HTTP requests | [`controllers`](/cms/plugins-development/server-controllers-services#controllers) | Called per request | | Implement business logic | [`services`](/cms/plugins-development/server-controllers-services#services) | Called from controllers or lifecycle hooks | | Enforce access rules on routes | [`policies`](/cms/plugins-development/server-policies-middlewares#policies) | Evaluated per request, before controller | | Intercept and modify request/response flow | [`middlewares`](/cms/plugins-development/server-policies-middlewares#middlewares) | Attached in `register()` or referenced in route config | | Access plugin features at runtime | [Getters](/cms/plugins-development/server-getters-usage) | Any lifecycle or request handler |
The following cards link directly to each dedicated page: :::strapi Backend customization Plugin routes, controllers, services, policies, and middlewares follow the same conventions as [backend customization](/cms/backend-customization) in a standard Strapi application. The Server API wraps these into the plugin namespace automatically (see [server content types](/cms/plugins-development/server-content-types#uids-and-naming-conventions) for details on UIDs and naming conventions). ::: # Server configuration Source: https://docs.strapi.io/cms/plugins-development/server-configuration # Server API: Configuration A plugin can expose a `config` object from its [server entry file](/cms/plugins-development/server-api#entry-file). This object defines default configuration values and validates any user-provided overrides loaded from the application's `config/plugins.js|ts` file. A user can override these values in the application's plugin configuration file: After deep-merging defaults with user overrides, the final config is `{ enabled: true, maxItems: 25, endpoint: 'https://api.production.example.com' }`. ## Runtime access Once the plugin is loaded, its configuration is available anywhere the `strapi` object is accessible: ```js // Read one key const maxItems = strapi.plugin('my-plugin').config('maxItems'); ``` ```js // Read the entire plugin config object const pluginConfig = strapi.config.get('plugin::my-plugin'); ``` Both `strapi.plugin().config()` and `strapi.config.get()` are typically used inside lifecycle functions, controllers, or services. :::tip Use `yarn strapi console` or `npm run strapi console` to inspect the live configuration of a running Strapi instance. ::: ## Best practices - **Always provide a `default`.** A plugin with no defaults forces every user to supply all configuration values, which creates friction. Make every option optional with a sensible default. - **Use the function form of `default` for environment-aware config.** The `({ env }) => ({...})` form lets users drive configuration from environment variables without any extra setup. The plain object form is fine for truly static defaults. - **Keep validation simple and explicit.** The `validator` runs at startup, before any request is served. Throw descriptive errors so the operator knows exactly what is wrong. For example, `'"maxItems" must be a positive number'` is more useful than `'Invalid config'`. - **Do not store secrets in plugin config.** Plugin configuration is accessible server-side via `strapi.config` and can be exposed unintentionally through logs, debug tooling, or custom endpoints if mishandled. Use environment variables directly in services, or read those values via the `env` helper in `default`, rather than embedding raw credentials in the config object. - **Read config in services, not inline.** Accessing `strapi.plugin('my-plugin').config('key')` inside a service method rather than at module load time ensures the value is always the final merged value, not a snapshot taken before user overrides are applied. # Server content-types Source: https://docs.strapi.io/cms/plugins-development/server-content-types # Server API: Content-types A plugin can declare its own content-types by exporting a `contentTypes` object from the [server entry file](/cms/plugins-development/server-api#entry-file). Strapi registers these content-types under the plugin namespace at startup and makes them available through the Document Service API and the content-type registry. ## UIDs and naming conventions When a plugin content-type is registered, Strapi builds its runtime UID from the plugin namespace and the key used in the `contentTypes` export: ``` plugin::. ``` The recommended convention is to set `content-types-key === info.singularName`. Following this convention keeps the schema naming and runtime UID aligned and easier to read. When the key matches `singularName` (recommended), the resulting UID follows this format: ``` plugin::. ``` For example, a plugin named `my-plugin` with a content-type whose `singularName` is `article` and export key `article` has the UID `plugin::my-plugin.article`. :::warning If the `contentTypes` key and `info.singularName` diverge, getters and queries use the UID built from the registered key (not from `singularName`). This can introduce naming inconsistencies across your plugin code. ::: This UID is used consistently across all APIs: | Use case | Example | | --- | --- | | Query via Document Service | `strapi.documents('plugin::my-plugin.article').findMany()` | | Access schema via getter | `strapi.contentType('plugin::my-plugin.article')` | | Reference in route handler | `handler: 'article.find'` (short form, resolved via plugin registry) | | Pass to sanitization API | `strapi.contentAPI.sanitize.output(data, schema, { auth })` | :::note Controllers, services, policies, and middlewares use the same `plugin::.` UID format for global getters, but are referenced by their short registry key (e.g., `'article'`) within plugin-level APIs such as route `handler` and `policies`. See [Getters & usage](/cms/plugins-development/server-getters-usage) for details. ::: ## Access at runtime ### Querying with the Document Service API Use the Document Service API to query plugin content-types from controllers, services, or lifecycle hooks: :::strapi Document Service API For the full list of available methods and parameters, see the [Document Service API](/cms/api/document-service). ::: ### Accessing the schema Use the content-type getter to retrieve the schema object, for example to pass it to the sanitization API: ## Best practices - **Match the export key to `info.singularName` exactly.** This keeps naming readable and consistent. At runtime, Strapi derives the plugin content-type UID from the key of the `contentTypes` map under the plugin namespace. A mismatch may create confusing UIDs and maintenance issues, even if registration still succeeds. - **Use `collectionName` to avoid table name conflicts.** The `collectionName` field sets the database table name. Prefix it with the plugin name (e.g., `my_plugin_articles`) to avoid collisions with application content-types or other plugins. - **Keep content-type schemas in their own files.** Define each schema in a dedicated `schema.json` file inside a subfolder named after the `singularName` (e.g., `content-types/article/schema.json`). This matches the structure generated by the Plugin SDK and keeps the index file readable. - **Enable `draftAndPublish` only when needed.** Draft and Publish adds a publication workflow to the content-type. Enable it only if the plugin's use case requires it, as it adds complexity to queries and content management. # Server controllers & services Source: https://docs.strapi.io/cms/plugins-development/server-controllers-services # Server API: Controllers & services Controllers and services are the 2 building blocks that handle request processing and business logic in a plugin server. They work together in a clear separation of concerns: controllers own the HTTP layer, services own the domain layer: | Goal | Use | | --- | --- | | Receive `ctx`, read the request, set the response | [Controller](#controllers) | | Query the database or apply business rules | [Service](#services) | | Reuse logic across multiple controllers or lifecycle hooks | [Service](#services) | | Call an external API as part of a request | [Service](#services) | ### Sanitization When your plugin exposes Content API routes, sanitize query parameters and output data before returning them. This prevents leaking private fields or bypassing access rules. Plugin controllers are plain factory functions and do not extend `createCoreController` like in the Strapi core (see [backend customization](/cms/backend-customization/controllers) for details). This means the `this.sanitizeQuery` and `this.sanitizeOutput` shorthands are not available. Use `strapi.contentAPI.sanitize` directly instead, passing the content-type schema explicitly: :::strapi Backend customization For the full sanitization and validation reference, including `sanitizeInput`, `validateQuery`, and `validateInput`, see [Controllers](/cms/backend-customization/controllers#sanitize-validate-custom-controllers). ::: ## Services A service is a factory function that receives `{ strapi }` and returns an object of named methods, or a plain object; like [controllers](#declaration), Strapi resolves both at runtime. Services hold business logic called from controllers, lifecycle hooks, or other services. ### Declaration :::caution TypeScript service typing `services` is typed as `unknown` in the current `ServerObject` TypeScript interface (`@strapi/types`). This means `strapi.plugin('my-plugin').service('article')` returns `unknown` and requires a cast to call methods with type safety. For fully typed service calls, define and export the service type explicitly and cast at the call site. ::: :::strapi Document Service API Services interact with content-types through the [Document Service API](/cms/api/document-service), which documents the full list of available methods and parameters. ::: ## End-to-end example The following example shows the complete request flow across routes, a controller, and a service for a simple article resource. ## Best practices - **Keep controllers thin.** A controller action should do 3 things: receive `ctx`, delegate to a service, and set the response. Business logic, database calls, and conditional branching all belong in services. - **One service per resource.** Organize services by the resource they manage (e.g., `article`, `comment`, `settings`) rather than by action type. This keeps each file focused and easy to test. - **Use the Document Service API in services, not in controllers.** Calling `strapi.documents(...)` directly in a controller bypasses the service layer and makes logic harder to reuse. Put all Document Service calls in services. - **Sanitize Content API responses.** When exposing Content API routes, use `strapi.contentAPI.sanitize.output()` before returning data. Skipping sanitization can leak private fields to end users. Admin routes are not subject to the same content-type field visibility rules, but sanitizing them as well is harmless. - **Cast service types explicitly in TypeScript.** Until `services` is strongly typed in `@strapi/types`, cast the return value of `strapi.plugin('my-plugin').service('my-service')` to the service interface at each call site. Avoid using `any` throughout the codebase. # Server getters & usage Source: https://docs.strapi.io/cms/plugins-development/server-getters-usage # Server API: Getters & usage Plugin server resources, such as controllers, services, policies, middlewares, and content-types, are accessible from any server-side location through the `strapi` instance: other plugins, lifecycle hooks, application controllers, or custom scripts. Routes and configuration use dedicated APIs — see the [getter reference](#full-getter-reference) below. ### Calling a plugin service from bootstrap Services called in `bootstrap()` have access to the full `strapi` instance, including other plugins' services: ### Calling across plugins or from application code From application-level controllers or services (outside the plugin), or when calling from another plugin, global getters using the full UID are often clearer: ### Reading plugin configuration at runtime ```js // Read a single key const maxItems = strapi.plugin('todo').config('maxItems'); ``` ```js // Read the full config object const todoConfig = strapi.config.get('plugin::todo'); ``` ```js // Read a nested key const endpoint = strapi.config.get('plugin::todo.endpoint'); ``` :::note `strapi.plugin('my-plugin').config('key')` reads the merged configuration (user overrides applied on top of plugin defaults). It is the recommended way to read config inside plugin code. See [Server configuration](/cms/plugins-development/server-configuration) for how plugin configuration is declared and merged. ::: ### Accessing a content-type schema Use the content-type getter when you need the schema object, for example to pass it to the sanitization API: ## Common errors - **Naming mismatch between route handler and controller key.** If your route declares `handler: 'task.find'`, your controllers index must export a key called `task` and that controller must have a method called `find`. A mismatch throws a runtime error when the route is matched. - **Misusing the policy context argument.** The first argument to a policy function is a policy context object, not a raw Koa `ctx`. It wraps the request context but exposes a different interface. Naming it `ctx` in your code won't cause an error, but treating it as a Koa context (for example, calling `ctx.body` or `ctx.status`) will not work as expected. Use `policyContext.state` to access auth state, and call `return false` or throw a `PolicyError` to block the request. - **Calling a service at module load time.** The `strapi` object is not initialized when modules are first loaded. Always call getters inside a function body. Never call them at the top level of a module file. - **Using an incomplete UID in global getters.** `strapi.service('todo.task')` is not a valid plugin UID. Use the full `plugin::todo.task` form. Without the proper namespace, the service call fails or returns `undefined` at runtime. | Scope | Example UID | | --- | --- | | Plugin service | `plugin::todo.task` | | API service | `api::project.project` | ## Best practices - **Prefer top-level getters inside your own plugin.** `strapi.plugin('my-plugin').service('task')` is more readable than the global form when both are inside the same plugin. - **Use global getters in application code and cross-plugin calls.** When calling from `src/api/` or from another plugin, the full UID `plugin::todo.task` makes the dependency explicit and is easier to search for. - **Access services in services, not at declaration time.** Avoid capturing service references in closures at module initialization. Always resolve them at call time using the getter, to ensure Strapi is fully loaded. # Server lifecycle Source: https://docs.strapi.io/cms/plugins-development/server-lifecycle # Server API: Lifecycle Lifecycle functions control when your plugin's server-side logic runs during the Strapi application startup and shutdown sequence. They are exported from the [server entry file](/cms/plugins-development/server-api#entry-file) alongside routes, controllers, services, and other server blocks. ## bootstrap() **Type:** `Function` `bootstrap()` runs after module lifecycle registration (plugins/APIs), database initialization, route initialization, and Content API action registration. Use `bootstrap()` to: - Seed the database with initial data - Register admin RBAC actions using `strapi.service('admin::permission').actionProvider.registerMany(...)` - Register cron jobs - Subscribe to database lifecycle events - Call services from your plugin or other plugins - Set up cross-plugin integrations that require other plugins to be registered first ## destroy() **Type:** `Function` `destroy()` is called when the Strapi instance is shutting down. It is optional. Only implement it when your plugin holds resources that need explicit cleanup. Use `destroy()` to: - Close external connections (databases, message queues, WebSocket servers) - Clear intervals or timeouts set in `bootstrap()` - Remove event listeners registered during the plugin's lifetime ## Best practices - **Keep `register()` lightweight.** It runs before full initialization. - **Use `bootstrap()` for database reads/writes.** The database is initialized during the bootstrap phase, not during register. Any call to `strapi.documents()` or a service that queries the database belongs in `bootstrap()`. - **Register admin RBAC actions in `bootstrap()`.** Use `strapi.service('admin::permission').actionProvider.registerMany(...)` in `bootstrap()`. This is when the permission service is available. Content API actions are registered automatically by Strapi during the same phase. - **Always pair resource creation with `destroy()`.** If your plugin opens a connection, registers a global interval, or attaches a process listener in `bootstrap()`, implement `destroy()` to clean up those resources. This prevents resource leaks during testing and graceful restarts. - **Avoid hard dependencies between plugins in `register()`.** At registration time, the order in which other plugins have registered is not guaranteed. Cross-plugin calls that rely on another plugin being initialized belong in `bootstrap()`. - **Prefer services over inline logic.** Move non-trivial bootstrap logic into a dedicated service method (e.g. `strapi.plugin('my-plugin').service('setup').initialize()`). This keeps lifecycle files readable and the logic testable. # Server policies & middlewares Source: https://docs.strapi.io/cms/plugins-development/server-policies-middlewares # Server API: Policies & middlewares Policies and middlewares are the two mechanisms for intercepting requests in a plugin server. Policies decide whether a request should proceed. Middlewares shape how it is processed. ### Usage in routes Once declared, reference a plugin policy from a route using the `plugin::my-plugin.policy-name` namespace: :::caution Policy return values Returning `false` causes Strapi to send a `403 Forbidden` response. Returning nothing (`undefined`) is treated as permissive (allowed), not as a block. Always return `true` or `false` explicitly. Throwing an error causes Strapi to send a `500` response unless you throw a Strapi HTTP error class (e.g., `new errors.PolicyError(...)`, `new errors.ForbiddenError(...)`, or `new errors.UnauthorizedError(...)`). ::: :::strapi Backend customization For the full policy reference including GraphQL support and the `policyContext` API, see [Policies](/cms/backend-customization/policies). ::: ## Middlewares A middleware is a Koa-style function that wraps the request/response cycle. Unlike [policies](#policies) (which are pass/fail guards), middlewares can read and modify the request before it reaches the controller, and modify the response after the controller has executed. Plugins can export middlewares in 2 ways: - as a **route-level middleware**, declared in the `middlewares` export of the server entry file and referenced in route `config.middlewares` - as a **server-level middleware**, registered directly on the Strapi HTTP server via `strapi.server.use()` in `register()` ### Route-level middlewares Route-level middlewares are scoped to a specific route and are declared like policies: as an object of named factory functions, then referenced in the route config. Note the two-level signature: the outer function receives `(config, { strapi })` and returns the actual Koa middleware `async (ctx, next) => {}`. This allows Strapi to pass per-route configuration to the function. :::note - `middlewares` exports middleware functions from the plugin so they can be referenced and reused in route config. - `strapi.server.use(...)` attaches a middleware to the global server pipeline. - Middleware execution is request-based: once attached to a route or to the server pipeline, it runs for each matching request. ::: Reference a route-level middleware in a route using the same `plugin::my-plugin.middleware-name` namespace as policies: ### Server-level middlewares A server-level middleware is registered on the Strapi HTTP server directly and runs for every request, not just plugin routes. Register it in `register()` using `strapi.server.use()`: :::caution Server-level middlewares affect all routes across all plugins and the application itself, not just your plugin's routes. A server-level middleware that throws or never calls `next()` will break every request on the server, not just your plugin's endpoints. Use route-level middlewares when the concern is specific to your plugin's endpoints. ::: :::note Version/runtime behavior For route declarations, validation accepts object entries shaped as `{ name, options }` for both `policies` and `middlewares` (see `services/server/routing.ts`). At runtime, some internals still reference `{ resolve, config }` support in the middleware resolver (`services/server/middleware.ts`), but that shape is not accepted by route validation in standard route files. To avoid validation errors, use `{ name, options }` in route configurations. ::: :::strapi Backend customization For the full middleware reference, see [Middlewares](/cms/backend-customization/middlewares). ::: ## Best practices - **Use `policyContext`, not `ctx`, in policies.** The first argument to a policy is `policyContext`, a wrapper around the Koa context. Using it correctly ensures the policy works for both REST and GraphQL resolvers. - **Return explicitly from policies.** A policy that returns `undefined` is treated as permissive (allowed). Always return `true` to allow or `false` to deny. Never return implicitly if the intent is to block the request. - **Prefer route-level middlewares over server-level.** Server-level middlewares run on every request in the entire Strapi server. Scope middleware to plugin routes unless the behavior genuinely applies to all traffic. - **Always call `await next()` in middlewares.** Forgetting `next()` means the request chain is interrupted and the controller never executes, resulting in a hanging request with no response. - **Use `options` for reusable policies.** When the same policy logic needs different parameters per route (e.g., a required role name), pass them from the route's `{ name, options }` object. These values are received in the policy function's `config` argument. This avoids duplicating similar policies. # Server routes Source: https://docs.strapi.io/cms/plugins-development/server-routes # Server API: Routes Routes expose your plugin's HTTP endpoints and map incoming requests to controller actions. They are exported from the [server entry file](/cms/plugins-development/server-api#entry-file) as a `routes` value. ### Named router format With the named router format, use an object with named keys (`admin`, `content-api`, or any custom name) to declare separate router groups. Each group is a router object with a `type`, optional `prefix`, and a `routes` array. Use this format when your plugin exposes both admin and Content API routes. ### Factory callback format For advanced cases where you need access to the `strapi` instance at route configuration time (for example, to build dynamic paths or conditionally include routes based on configuration), you can export a factory callback. :::note The factory callback must be attached to a named route entry (such as `admin` or `content-api`), not exported as the root of `routes/index`. `module.exports = ({ strapi }) => ({ ... })` at the root level is not a valid format. ::: For details on what Strapi adds automatically at registration time, see [Defaults applied by Strapi](#defaults-applied-by-strapi). ## Defaults applied by Strapi When Strapi registers plugin routes, it applies the following defaults automatically: | Property | Default value | Notes | | --- | --- | --- | | `type` | `'admin'` | Applied when using the array format, or when `type` is omitted from a router object in the named format | | `prefix` | `'/'` | Applied when using the array format, or when `prefix` is omitted from a router object | | `config.auth.scope` | `['plugin::.']` | Auto-generated for string handlers only, using `defaultsDeep` so existing values are not overwritten | The following 2 declarations are equivalent. Strapi applies the defaults from the table above automatically: ## Route configuration reference Each route accepts an optional `config` object with the following properties: ### `policies` **Type:** `Array` Policies to run before the controller action. Each item is either a policy name string, an inline function, or an object with required `name` and optional `options`. The `options` object is passed as-is to the policy function's second argument (`config` in policy signatures). The shape of this object depends on the policy. Plugin policies are referenced as `plugin::my-plugin.policy-name`. ### `middlewares` **Type:** `Array` Middlewares to apply to this route. Each item is a middleware name string, an inline function, or an object with: - `name`: a registered middleware name, - `options` (optional): middleware options. :::note Route middlewares vs. global server middlewares At route validation time, Strapi validates middleware/policy objects against `{ name: string; options?: object }` (see `services/server/routing.ts`). The middleware resolver (`services/server/middleware.ts`) still contains runtime support for `{ resolve, config }` objects, but this shape is rejected by route validation before resolution for standard plugin route declarations. Use `{ name, options }` in route configs for compatibility with validation. ::: ### `auth` **Type:** `false | { scope: string[]; strategies?: string[] }` Set to `false` to make the route public. Pass an object to define the auth scope and, optionally, custom auth strategies. At runtime, `scope` must be present when `auth` is an object. :::note For **string handlers** (for example, `handler: 'article.find'`), Strapi auto-injects a default `config.auth.scope` value, so patterns such as `auth: {}` can still work. For **non-string handlers** (inline functions), do not assume auto-scope injection. Define `config.auth.scope` explicitly when `auth` is an object. ::: :::caution Setting `auth: false` on an admin route is almost never intentional: it exposes the endpoint to unauthenticated requests. ::: :::strapi General backend customization examples For configuration examples including policies, public routes, dynamic URL parameters, and regular expressions in paths, see [Routes](/cms/backend-customization/routes). ::: ## Best practices - **Use the named router format when exposing both admin and Content API endpoints.** It makes the intent of each route explicit and avoids relying on the `type` default, which can be surprising. - **Keep `handler` as a string.** String handlers get automatic auth scope generation, function handlers do not. Authentication still runs for both string and function handlers unless you set `config.auth: false`, but only string handlers get automatic `config.auth.scope`. If you use a function handler and need route-level permission scoping, define `config.auth.scope` explicitly. - **Scope policies to their namespace.** When referencing a plugin policy in a route, use the full `plugin::my-plugin.policy-name` form. This avoids ambiguity if a policy with the same short name exists elsewhere in the application. - **Do not disable auth on admin routes.** Admin routes default to requiring admin authentication. Disabling auth on an admin route exposes it to unauthenticated requests, which is almost never intentional. - **Group related routes in dedicated files.** As the plugin grows, a single route index file becomes hard to navigate. Split by resource (e.g., `routes/article.js`, `routes/comment.js`) and re-export from `routes/index.js`. # Documentation plugin Source: https://docs.strapi.io/cms/plugins/documentation # Documentation plugin The Documentation plugin automates your API documentation creation. It basically generates a swagger file. It follows the :::caution Unmaintained plugin The Documentation plugin is not actively maintained and may not work with Strapi 5. ::: Once the plugin is installed, starting Strapi generates the API documentation. ## Configuration Most configuration options for the Documentation plugin are handled via your Strapi project's code. A few settings are available in the admin panel. ### Admin panel settings The Documentation plugin affects multiple parts of the admin panel. The following table lists all the additional options and settings that are added to a Strapi application once the plugin has been installed: | Section impacted | Options and settings | |------------------|-------------------------------------------------------------| | Documentation |
    Addition of a new Documentation option in the main navigation which shows a panel with buttons to open and regenerate the documentation.
| | Settings |
  • Addition of a "Documentation plugin" setting section, which controls whether the documentation endpoint is private or not (see [restricting access](#restrict-access)).
    👉 Path reminder: *Settings > Documentation plugin*

  • Activation of role based access control for accessing, updating, deleting, and regenerating the documentation. Administrators can authorize different access levels to different types of users in the *Plugins* tab and the *Settings* tab (see [Users & Permissions documentation](/cms/features/users-permissions)).
    👉 Path reminder: *Settings > Administration Panel > Roles*
| #### Restricting access to your API documentation {#restrict-access} By default, your API documentation will be accessible by anyone. To restrict API documentation access, enable the **Restricted Access** option from the admin panel: 1. Navigate to *Settings* in the main navigation of the admin panel. 2. Choose **Documentation**. 3. Toggle **Restricted Access** to `ON`. 4. Define a password in the `password` input. 5. Save the settings. ### Code-based configuration To configure the Documentation plugin, create a `settings.json` file in the `src/extensions/documentation/config` folder. In this file, you can specify all your environment variables, licenses, external documentation links, and all the entries listed in the . The following is an example configuration: ```json title="src/extensions/documentation/config/settings.json" { "openapi": "3.0.0", "info": { "version": "1.0.0", "title": "DOCUMENTATION", "description": "", "termsOfService": "YOUR_TERMS_OF_SERVICE_URL", "contact": { "name": "TEAM", "email": "contact-email@something.io", "url": "mywebsite.io" }, "license": { "name": "Apache 2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0.html" } }, "x-strapi-config": { "plugins": ["upload", "users-permissions"], "path": "/documentation" }, "servers": [ { "url": "http://localhost:1337/api", "description": "Development server" } ], "externalDocs": { "description": "Find out more", "url": "https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html" }, "security": [ { "bearerAuth": [] } ] } ``` :::tip If you need to add a custom key, prefix it by `x-` (e.g., `x-strapi-something`). ::: #### Creating a new version of the documentation {#create-a-new-version-of-the-documentation} To create a new version, change the `info.version` key in the `settings.json` file: ```json title="src/extensions/documentation/config/settings.json" { "info": { "version": "2.0.0" } } ``` This will automatically create a new version. #### Defining which plugins need documentation generated {#define-which-plugins} If you want plugins to be included in documentation generation, they should be included in the `plugins` array in the `x-strapi-config` object. By default, the array is initialized with `["upload", "users-permissions"]`: ```json title="src/extensions/documentation/config/settings.json" { "x-strapi-config": { "plugins": ["upload", "users-permissions"] } } ``` To add more plugins, such as your custom plugins, add their name to the array. If you do not want plugins to be included in documentation generation, provide an empty array (i.e., `plugins: []`). #### Overriding the generated documentation The Documentation plugins comes with 3 methods to override the generated documentation: [`excludeFromGeneration`](#excluding-from-generation), [`registerOverride`](#register-override), and [`mutateDocumentation`](#mutate-documentation). ##### excludeFromGeneration() {#excluding-from-generation} To exclude certain APIs or plugins from being generated, use the `excludeFromGeneration` found on the documentation plugin’s `override` service in your application or plugin's [`register` lifecycle](/cms/plugins-development/admin-panel-api#register). :::note `excludeFromGeneration` gives more fine-grained control over what is generated. For example, pluginA might create several new APIs while pluginB may only want to generate documentation for some of those APIs. In that case, pluginB could still benefit from the generated documentation it does need by excluding only what it does not need. ::: ***** | Parameter | Type | Description | | --------- | -------------------------- | -------------------------------------------------------- | | `api` | String or Array of Strings | The name of the API/plugin, or list of names, to exclude | ```js title="Application or plugin register lifecycle" module.exports = { register({ strapi }) { strapi .plugin("documentation") .service("override") .excludeFromGeneration("restaurant"); // or several strapi .plugin("documentation") .service("override") .excludeFromGeneration(["address", "upload"]); } } ``` ##### registerOverride() {#register-override} If the Documentation plugin fails to generate what you expect, it is possible to replace what has been generated. The Documentation plugin exposes an API that allows you to replace what was generated for the following OpenAPI root level keys: `paths`, `tags`, `components` . To provide an override, use the `registerOverride` function found on the Documentation plugin’s `override` service in your application or plugin's [`register` lifecycle](/cms/plugins-development/admin-panel-api#register). | Parameter | Type | Description | | ----------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------- | | `override` | Object | OpenAPI object including any of the following keys paths, tags, components. Accepts JavaScript, JSON, or yaml | | `options` | Object | Accepts `pluginOrigin` and `excludeFromGeneration` | | `options.pluginOrigin` | String | The plugin that is registering the override | | `options.excludeFromGeneration` | String or Array of String | The name of the API/plugin, or list of names, to exclude | :::caution Plugin developers providing an override should always specify the `pluginOrigin` options key. Otherwise the override will run regardless of the user’s configuration. ::: The Documentation plugin will use the registered overrides to replace the value of common keys on the generated documentation with what the override provides. If no common keys are found, the plugin will add new keys to the generated documentation. If the override completely replaces what the documentation generates, you can specify that generation is no longer necessary by providing the names of the APIs or plugins to exclude in the options key array `excludeFromGeneration`. If the override should only be applied to a specific version, the override must include a value for `info.version`. Otherwise, the override will run on all documentation versions. ```js title="Application or plugin register lifecycle" module.exports = { register({ strapi }) { if (strapi.plugin('documentation')) { const override = { // Only run this override for version 1.0.0 info: { version: '1.0.0' }, paths: { '/answer-to-everything': { get: { responses: { 200: { description: "*" }} } } } } strapi .plugin('documentation') .service('override') .registerOverride(override, { // Specify the origin in case the user does not want this plugin documented pluginOrigin: 'upload', // The override provides everything don't generate anything excludeFromGeneration: ['upload'], }); } }, } ``` The overrides system is provided to try and simplify amending the generated documentation. It is the only way a plugin can add or modify the generated documentation. ##### mutateDocumentation() {#mutate-documentation} The Documentation plugin’s configuration also accepts a `mutateDocumentation` function on `info['x-strapi-config']`. This function receives a draft state of the generated documentation that be can be mutated. It should only be applied from an application and has the final say in the OpenAPI schema. | Parameter | Type | Description | | --------------------------- | ------ | ---------------------------------------------------------------------- | | `generatedDocumentationDraft` | Object | The generated documentation with applied overrides as a mutable object | ```js title="config/plugins.js" module.exports = { documentation: { config: { "x-strapi-config": { mutateDocumentation: (generatedDocumentationDraft) => { generatedDocumentationDraft.paths[ "/answer-to-everything" // must be an existing path ].get.responses["200"].description = "*"; }, }, }, }, }; ``` ## Usage The Documentation plugin visualizes your API using . To access the UI, select in the main navigation of the admin panel. Then click **Open documentation** to open the Swagger UI. Using the Swagger UI you can view all of the endpoints available on your API and trigger API calls. :::tip Once the plugin is installed, the plugin user interface can be accessed at the following URL: `:/documentation/` (e.g., ). ::: ### Regenerating documentation {#regenerate-documentation} There are 2 ways to update the documentation after making changes to your API: - restart your application to regenerate the version of the documentation specified in the Documentation plugin's configuration, - or go to the Documentation plugin page and click the **regenerate** button for the documentation version you want to regenerate. ### Authenticating requests Strapi is secured by default, which means that most of your endpoints require the user to be authorized. If the CRUD action has not been set to Public in the [Users & Permissions feature](/cms/features/users-permissions#roles) then you must provide your JSON web token (JWT). To do this, while viewing the API Documentation, click the **Authorize** button and paste your JWT in the _bearerAuth_ _value_ field. # GraphQL plugin Source: https://docs.strapi.io/cms/plugins/graphql # GraphQL plugin By default Strapi create [REST endpoints](/cms/api/rest#endpoints) for each of your content-types. The GraphQL plugin adds a GraphQL endpoint to fetch and mutate your content. With the GraphQL plugin installed, you can use the Apollo Server-based GraphQL Sandbox to interactively build your queries and mutations and read documentation tailored to your content types. Once installed, the GraphQL sandbox is accessible at the `/graphql` URL and can be used to interactively build your queries and mutations and read documentation tailored to your content-types. Once the plugin is installed, the **GraphQL Sandbox** is accessible at the `/graphql` route (e.g., #### Dynamically enable Apollo Sandbox You can use a function to dynamically enable Apollo Sandbox depending on the environment: #### CORS exceptions for Landing Page If the landing page is enabled in production environments (which is not recommended), CORS headers for the Apollo Server landing page must be added manually. To add them globally, you can merge the following into your middleware configuration: ```javascript title="/config/middlewares" { name: "strapi::security", config: { contentSecurityPolicy: { useDefaults: true, directives: { "connect-src": ["'self'", "https:", "apollo-server-landing-page.cdn.apollographql.com"], "img-src": ["'self'", "data:", "blob:", "apollo-server-landing-page.cdn.apollographql.com"], "script-src": ["'self'", "'unsafe-inline'", "apollo-server-landing-page.cdn.apollographql.com"], "style-src": ["'self'", "'unsafe-inline'", "apollo-server-landing-page.cdn.apollographql.com"], "frame-src": ["sandbox.embed.apollographql.com"] } } } } ``` To add these exceptions only for the `/graphql` path (recommended), you can create a new middleware to handle it. For example: #### Shadow CRUD To simplify and automate the build of the GraphQL schema, we introduced the Shadow CRUD feature. It automatically generates the type definitions, queries, mutations and resolvers based on your models. **Example:** If you've generated an API called `Document` using [the interactive `strapi generate` CLI](/cms/cli#strapi-generate) or the administration panel, your model looks like this: ```json title="/src/api/[api-name]/content-types/document/schema.json" { "kind": "collectionType", "collectionName": "documents", "info": { "singularName": "document", "pluralName": "documents", "displayName": "document", "name": "document" }, "options": { "draftAndPublish": true }, "pluginOptions": {}, "attributes": { "name": { "type": "string" }, "description": { "type": "richtext" }, "locked": { "type": "boolean" } } } ```
Generated GraphQL type and queries ```graphql # Document's Type definition input DocumentFiltersInput { name: StringFilterInput description: StringFilterInput locked: BooleanFilterInput createdAt: DateTimeFilterInput updatedAt: DateTimeFilterInput publishedAt: DateTimeFilterInput and: [DocumentFiltersInput] or: [DocumentFiltersInput] not: DocumentFiltersInput } input DocumentInput { name: String description: String locked: Boolean createdAt: DateTime updatedAt: DateTime publishedAt: DateTime } type Document { name: String description: String locked: Boolean createdAt: DateTime updatedAt: DateTime publishedAt: DateTime } type DocumentEntity { id: ID attributes: Document } type DocumentEntityResponse { data: DocumentEntity } type DocumentEntityResponseCollection { data: [DocumentEntity!]! meta: ResponseCollectionMeta! } type DocumentRelationResponseCollection { data: [DocumentEntity!]! } # Queries to retrieve one or multiple restaurants. type Query { document(id: ID): DocumentEntityResponse documents( filters: DocumentFiltersInput pagination: PaginationArg = {} sort: [String] = [] publicationState: PublicationState = LIVE ):DocumentEntityResponseCollection } # Mutations to create, update or delete a restaurant. type Mutation { createDocument(data: DocumentInput!): DocumentEntityResponse updateDocument(id: ID!, data: DocumentInput!): DocumentEntityResponse deleteDocument(id: ID!): DocumentEntityResponse } ```
#### Customization Strapi provides a programmatic API to customize GraphQL, which allows: * disabling some operations for the [Shadow CRUD](#shadow-crud) * [using getters](#using-getters) to return information about allowed operations * registering and using an `extension` object to [extend the existing schema](#extending-the-schema) (e.g. extend types or define custom resolvers, policies and middlewares)
Example of GraphQL customizations
##### Disabling operations in the Shadow CRUD The `extension` service provided with the GraphQL plugin exposes functions that can be used to disable operations on Content-Types: | Content-type function | Description | Argument type | Possible argument values | | -------------------- | ---------------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------- | | `disable()` | Fully disable the Content-Type | - | - | | `disableQueries()` | Only disable queries for the Content-Type | - | - | | `disableMutations()` | Only disable mutations for the Content-Type | - | - | | `disableAction()` | Disable a specific action for the Content-Type | String | One value from the list:
  • `create`
  • `find`
  • `findOne`
  • `update`
  • `delete`
| | `disableActions()` | Disable specific actions for the Content-Type | Array of Strings | Multiple values from the list:
  • `create`
  • `find`
  • `findOne`
  • `update`
  • `delete`
| Actions can also be disabled at the field level, with the following functions: | Field function | Description | | ------------------ | -------------------------------- | | `disable()` | Fully disable the field | | `disableOutput()` | Disable the output on a field | | `disableInput()` | Disable the input on a field | | `disableFilters()` | Disable filters input on a field | **Examples:** ```js // Disable the 'find' operation on the 'restaurant' content-type in the 'restaurant' API strapi .plugin('graphql') .service('extension') .shadowCRUD('api::restaurant.restaurant') .disableAction('find') // Disable the 'name' field on the 'document' content-type in the 'document' API strapi .plugin('graphql') .service('extension') .shadowCRUD('api::document.document') .field('name') .disable() ``` ##### Using getters The following getters can be used to retrieve information about operations allowed on content-types: | Content-type getter | Description | Argument type | Possible argument values | | -------------------------- | ----------------------------------------------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------- | | `isEnabled()` | Returns whether a content-type is enabled | - | - | | `isDisabled()` | Returns whether a content-type is disabled | - | - | | `areQueriesEnabled()` | Returns whether queries are enabled on a content-type | - | - | | `areQueriesDisabled()` | Returns whether queries are disabled on a content-type | - | - | | `areMutationsEnabled()` | Returns whether mutations are enabled on a content-type | - | - | | `areMutationsDisabled()` | Returns whether mutations are disabled on a content-type | - | - | | `isActionEnabled(action)` | Returns whether the passed `action` is enabled on a content-type | String | One value from the list:
  • `create`
  • `find`
  • `findOne`
  • `update`
  • `delete`
| | `isActionDisabled(action)` | Returns whether the passed `action` is disabled on a content-type | String | One value from the list:
  • `create`
  • `find`
  • `findOne`
  • `update`
  • `delete`
| The following getters can be used to retrieve information about operations allowed on fields: | Field getter | Description | | --------------------- | --------------------------------------------- | | `isEnabled()` | Returns whether a field is enabled | | `isDisabled()` | Returns whether a field is disabled | | `hasInputEnabled()` | Returns whether a field has input enabled | | `hasOutputEnabled()` | Returns whether a field has output enabled | | `hasFiltersEnabled()` | Returns whether a field has filtering enabled | ###### Extending the schema The schema generated by the Content API can be extended by registering an extension. This extension, defined either as an object or a function returning an object, will be used by the `use()` function exposed by the `extension` [service](/cms/backend-customization/services) provided with the GraphQL plugin. The object describing the extension accepts the following parameters: | Parameter | Type | Description | | ----------------- | ------ | -------------------------------------------------------------------------------------------- | | `types` | Array | Allows extending the schema types using
::: ###### Custom configuration for resolvers A resolver is a GraphQL query or mutation handler (i.e. a function, or a collection of functions, that generate(s) a response for a GraphQL query or mutation). Each field has a default resolver. When [extending the GraphQL schema](#extending-the-schema), the `resolversConfig` key can be used to define a custom configuration for a resolver, which can include: * [authorization configuration](#authorization-configuration) with the `auth` key * [policies with the `policies`](#policies) key * and [middlewares with the `middlewares`](#middlewares) key :::tip The [advanced queries](/cms/api/graphql/advanced-queries) guide might contain additional information suitable for your use case, including multi-level queries and custom resolvers examples. ::: ###### Authorization configuration By default, the authorization of a GraphQL request is handled by the registered authorization strategy that can be either [API token](/cms/features/api-tokens) or through the [Users & Permissions plugin](#usage-with-the-users--permissions-plugin). The Users & Permissions plugin offers a more granular control.
Authorization with the Users & Permissions plugin With the Users & Permissions plugin, a GraphQL request is allowed if the appropriate permissions are given. For instance, if a 'Category' content-type exists and is queried through GraphQL with the `Query.categories` handler, the request is allowed if the appropriate `find` permission for the 'Categories' content-type is given. To query a single category, which is done with the `Query.category` handler, the request is allowed if the the `findOne` permission is given. Please refer to the user guide on how to [define permissions with the Users & Permissions plugin](/cms/features/rbac#editing-a-role).
To change how the authorization is configured, use the resolver configuration defined at `resolversConfig.[MyResolverName]`. The authorization can be configured: * either with `auth: false` to fully bypass the authorization system and allow all requests, * or with a `scope` attribute that accepts an array of strings to define the permissions required to authorize the request.
Examples of authorization configuration
###### Policies [Policies](/cms/backend-customization/policies) can be applied to a GraphQL resolver through the `resolversConfig.[MyResolverName].policies` key. The `policies` key is an array accepting a list of policies, each item in this list being either a reference to an already registered policy or an implementation that is passed directly (see [policies configuration documentation](/cms/backend-customization/routes#policies)). Policies directly implemented in `resolversConfig` are functions that take a `context` object and the `strapi` instance as arguments. The `context` object gives access to: * the `parent`, `args`, `context` and `info` arguments of the GraphQL resolver, * Koa's :::tip The [advanced policies](/cms/api/graphql/advanced-policies) guide might contain additional information suitable for your use case. ::: ###### Middlewares [Middlewares](/cms/backend-customization/middlewares) can be applied to a GraphQL resolver through the `resolversConfig.[MyResolverName].middlewares` key. The only difference between the GraphQL and REST implementations is that the `config` key becomes `options`. The `middlewares` key is an array accepting a list of middlewares, each item in this list being either a reference to an already registered middleware or an implementation that is passed directly (see [middlewares configuration documentation](/cms/backend-customization/routes#middlewares)). Middlewares directly implemented in `resolversConfig` can take the GraphQL resolver's ##### Security GraphQL is a query language allowing users to use a broader panel of inputs than traditional REST APIs. GraphQL APIs are inherently prone to security risks, such as credential leakage and denial of service attacks, that can be reduced by taking appropriate precautions. ### Disable introspection and Sandbox in production In production environments, disabling the GraphQL Sandbox and the introspection query is strongly recommended. If you haven't edited the [configuration file](#available-options), it is already disabled in production by default. ###### Limit max depth and complexity A malicious user could send a query with a very high depth, which could overload your server. Use the `depthLimit` [configuration parameter](/cms/plugins/graphql#code-based-configuration) to limit the maximum number of nested fields that can be queried in a single request. By default, `depthLimit` is set to 10 but can be set to a higher value during testing and development. :::tip To increase GraphQL security even further, 3rd-party tools can be used. See the guide about You should see a new user is created in the `Users` collection type in your Strapi admin panel. #### Authentication To perform authorized requests, you must first get a JWT: Then on each request, send along an `Authorization` header in the form of `{ "Authorization": "Bearer YOUR_JWT_GOES_HERE" }`. This can be set in the HTTP Headers section of your GraphQL Sandbox. #### Usage with API tokens {#api-tokens} To use API tokens for authentication, pass the token in the `Authorization` header using the format `Bearer your-api-token`. :::note Using API tokens in the the GraphQL Sandbox requires adding the authorization header with your token in the `HTTP HEADERS` tab: ```http { "Authorization" : "Bearer # Installing Plugins via the Marketplace Source: https://docs.strapi.io/cms/plugins/installing-plugins-via-marketplace # Using the Marketplace Strapi comes with built-in plugins such as [Documentation](/cms/plugins/documentation), [GraphQL](/cms/plugins/graphql), and [Sentry](/cms/plugins/sentry). The Marketplace is where users can find additional plugins to customize Strapi applications, and additional providers to extend plugins. The Marketplace is located in the admin panel, indicated by _Marketplace_. In the Marketplace, users can browse or search for plugins and providers, link to detailed descriptions for each, and submit new plugins and providers. :::note strapi In-app Marketplace vs. Market website The Marketplace in the admin panel displays all existing plugins, regardless of the version of Strapi they are for. All plugins can also be discoverable through the website. Keep in mind however that v4 and v5 plugins are not cross-compatible, but that providers are compatible both with v4 and v5 plugins. ::: The Plugins and Providers tabs display each plugin/provider on individual cards containing: - their name, sometimes followed by either of the following badges: - maintained by Strapi icon to indicate it is made by Strapi, - to indicate it was verified by Strapi. - the number of times the plugin/provider was starred on GitHub and downloaded - the description - a **More** button to be redirected to the Market website for additional information, including about the version of Strapi the plugin is for, and implementation instructions In the top right corner of the Marketplace, the **Submit plugin** button redirects to the Strapi Market where it is possible to submit your own plugin and provider. :::tip Tips - The search bar displays incremental search results based on the plugin/provider name and description. - Use the "Sort by" button or set filters to find plugins more easily. ::: ## Installing Marketplace plugins and providers To install a new plugin or provider via the Marketplace: 1. Go to the *Marketplace*. 2. Choose the **Plugins** tab to browse available plugins or the **Providers** tab to browse available providers. 3. Choose an available plugin/provider and click on the **More** button. 4. Once redirected to the Strapi Market website, follow the plugin/provider-specific implementation instructions. :::strapi Developing Strapi plugins Can't find a plugin that suits your use case? Feel free to [create your own](/cms/plugins-development/developing-plugins)! ::: # Sentry plugin Source: https://docs.strapi.io/cms/plugins/sentry # Sentry plugin This plugin enables you to track errors in your Strapi application using Sentry. By using the Sentry plugin you can: * Initialize a Sentry instance upon startup of a Strapi application * Send Strapi application errors as events to Sentry * Include additional metadata in Sentry events to assist in debugging * Expose a global Sentry service usable by the Strapi server ## Installation Install the Sentry plugin by adding the dependency to your Strapi application as follows: ## Configuration Create or edit your `/config/plugins` file to configure the Sentry plugin. The following properties are available: | Property | Type | Default Value | Description | | -------- | ---- | ------------- |------------ | | `dsn` | string | `null` | Your Sentry ### Disabling for non-production environments If the `dsn` property is set to a nil value (`null` or `undefined`) while `sentry.enabled` is true, the Sentry plugin will be available to use in the running Strapi instance, but the service will not actually send errors to Sentry. That allows you to write code that runs on every environment without additional checks, but only send errors to Sentry in production. When you start Strapi with a nil `dsn` config property, the plugin will print the following warning:
`info: @strapi/plugin-sentry is disabled because no Sentry DSN was provided` You can make use of that by using the [`env` utility](/cms/configurations/guides/access-cast-environment-variables) to set the `dsn` configuration property depending on the environment. ### Disabling the plugin completely Like every other Strapi plugin, you can also disable this plugin in the plugins configuration file. This will cause `strapi.plugins('sentry')` to return `undefined`: ## Usage After installing and configuring the plugin, you can access a Sentry service in your Strapi application as follows: ```js const sentryService = strapi.plugin('sentry').service('sentry'); ``` This service exposes the following methods: | Method | Description | Parameters | | ------ | ----------- | ---------- | | `sendError()` | Manually send errors to Sentry. |
  • error: The error to be sent.
  • configureScope: Optional. Enables you to customize the error event.
See the official for more details. | | `getInstance()` | Used for direct access to the Sentry instance. | - | The `sendError()` method can be used as follows: ```js try { // Your code here } catch (error) { // Either send a simple error strapi .plugin('sentry') .service('sentry') .sendError(error); // Or send an error with a customized Sentry scope strapi .plugin('sentry') .service('sentry') .sendError(error, (scope, sentryInstance) => { // Customize the scope here scope.setTag('my_custom_tag', 'Tag value'); }); throw error; } ``` The `getInstance()` method is accessible as follows: ```js const sentryInstance = strapi .plugin('sentry') .service('sentry') .getInstance(); ``` # プロジェクト構成 Source: https://docs.strapi.io/cms/project-structure # プロジェクト構成 Strapi プロジェクトのディレクトリ構成は、[TypeScript](/cms/typescript) で作成したか(プロジェクト作成時の既定)、バニラ JavaScript かによって異なります。おおまかには次のようになります。 # クイックスタート - Strapi 開発者向けドキュメント Source: https://docs.strapi.io/cms/quick-start # クイックスタート Strapi は柔軟性が高く、手早く結果を見たい場合も、プロダクトを深く掘り下げたい場合もカバーできます。このチュートリアルではゼロからプロジェクトとコンテンツ構造を作る流れに沿い、その後 Strapi Cloud にデプロイしてクラウド側からデータを追加します。 :::strapi Strapi を試す 3 つの方法 次のいずれかを選んでください。 * Strapi の [ホストされたデモ](https://strapi.io/demo) では、コンテンツマネージャーをすぐ試し、コンテンツ編集の流れを学べます。デモは本番モードのため、コンテンツタイプビルダーは[仕様により無効](/cms/faq#why-cant-i-create-or-update-content-types-in-productionstaging)です。 * Strapi バックエンド、Next.js フロント、サンプルデータ一式を含む完成形を試すなら、[LaunchPad](https://github.com/strapi/launchpad) をローカルにインストールしてください。 * 一から学びたい場合は、このクイックスタートに従ってください。 ::: :::prerequisites 2. ターミナルにログインまたはサインアップの案内が出ます。完了すると、 3. ターミナルの質問に答えます。プロジェクト名(Enter で既定)、推奨の Node.js バージョン、近いリージョンを選びます。 ![Strapi Cloud のターミナルでの質問と回答](/img/assets/quick-start-guide/qsg-strapi-cloud-terminal-questions.png) しばらくするとローカルプロジェクトが Strapi Cloud 上にホストされます。🚀 完了すると、ターミナルに `https://cloud.strapi.io/projects` で始まるリンクが表示されます。クリックするかアドレスバーに貼り付けて開きます。 Strapi Cloud のダッシュボードに、作成した `my-strapi-project` が表示されます。右上の **Visit app** をクリックして、デプロイした Strapi にアクセスします。 :::callout おつかれさまでした! プロジェクトが Strapi Cloud 上にあり、オンラインからアクセスできます。詳しくは [Strapi Cloud ドキュメント](/cloud/intro) を読むか、パート D でオンラインの管理パネルにログインし、データを追加してください。 ::: :::tip コンテンツタイプビルダーでフィールドやタイプを追加したら、再度 `deploy` コマンドを実行して Strapi Cloud に反映すると、数分でホスト側も更新されます。🪄 ::: ## パート D: コンテンツマネージャーで Strapi Cloud プロジェクトにコンテンツを追加する 「Restaurant」と「Category」の 2 つのコレクションタイプを用意し Strapi Cloud にデプロイしたので、クラウド上でエントリーを作成してコンテンツを追加します。
ステップ 1: 新しい Strapi Cloud プロジェクトの管理パネルにログインする ### ステップ 1: 新しい Strapi Cloud プロジェクトの管理パネルにログインする Strapi Cloud プロジェクトができたので、ログインします。 1. で `my-strapi-project` をクリックします。 2. **Visit app** をクリックします。 3. 開いたページのフォームに入力し、この Strapi Cloud プロジェクトの最初の管理者ユーザーを作成します。 ログインできたら、ここからデータを追加します。
ユーザーと Strapi Cloud プロジェクトに関する補足: :::note 補足: ローカルユーザーと Strapi Cloud のユーザーは別です Strapi Cloud プロジェクトとローカルプロジェクトではデータベースが別です。ローカルから Strapi Cloud へデータは自動では引き継がれず、ローカルで作ったユーザーも含まれます。そのため、初めて Strapi Cloud プロジェクトにログインするときは、新しい管理者アカウントの作成を求められます。 ::: :::tip ヒント: Strapi Cloud プロジェクトの管理パネルに直接アクセスする Strapi Cloud の各プロジェクトは `https://my-strapi-project-name.strapiapp.com` のような URL でアクセスできます。オンラインの管理パネルは URL の末尾に `/admin` を付けます(例: `https://my-strapi-project-name.strapiapp.com/admin`)。URL はダッシュボードでも確認でき、プロジェクト名と **Visit app** からも開けます。 :::
ステップ 2: 「Restaurant」コレクションタイプのエントリーを作成する ### ステップ 2: 「Restaurant」コレクションタイプのエントリーを作成する 1. ナビの _Content Manager > Collection types - Restaurant_ を開きます。 2. **Create new entry** をクリックします。 3. _Name_ に好きな地元のレストラン名を入力します。例: `Biscotte Restaurant`。 4. _Description_ に短い説明を書きます。例文を使う場合は `Welcome to Biscotte restaurant! Restaurant Biscotte offers a cuisine based on fresh, quality products, often local, organic when possible, and always produced by passionate producers.` でも構いません。 5. **Save** をクリックします。 レストランが _Content Manager_ の _Collection types - Restaurant_ 一覧に表示されます。
ステップ 3: カテゴリを追加する #### ステップ 3: カテゴリを追加する _Content Manager > Collection types - Category_ でカテゴリを 2 件作成します。 1. **Create new entry** をクリックします。 2. _Name_ に `French Food` と入力します。 3. **Save** をクリックします。 4. _Collection types - Category_ に戻り、再度 **Create new entry** をクリックします。 5. _Name_ に `Brunch` と入力し、**Save** をクリックします。 「French Food」と「Brunch」が _Content Manager_ の _Collection types - Category_ に下書きとして表示されます。 レストランにカテゴリを紐づけます。 1. _Content Manager > Collection types - Restaurant_ から "Biscotte Restaurant" を開きます。 2. ページ下部の **Categories** ドロップダウンで "French Food" を選び、上にスクロールして **Save** をクリックします。
ステップ 4: ロールと権限を設定する ### ステップ 4: ロールと権限を設定する {#step-4-set-roles--permissions} レストランとカテゴリを追加したので、API から公開取得できるようにします。 1. メインナビ下部の _ Settings_ をクリックします。 2. _Users & Permissions Plugin_ から _Roles_ を選びます。 3. **Public** ロールを開きます。 4. _Permissions_ まで下にスクロールします。 5. _Permissions_ タブで _Restaurant_ を開きます。 6. **find** と **findOne** にチェックを入れます。 7. _Category_ でも同様に **find** と **findOne** にチェックを入れます。 8. ページ上部の **Save** をクリックします。
ステップ 5: コンテンツを公開する ### ステップ 5: コンテンツを公開する 作成したコンテンツは既定で下書きです。カテゴリとレストランを公開します。 まず _Content Manager > Collection types - Category_ を開きます。 1. "Brunch" エントリーを開きます。 2. 次の画面で **Publish** をクリックします。 一覧に戻り、"French Food" でも同様に **Publish** します。 最後に _Content Manager > Collection types - Restaurant_ で "Biscotte Restaurant" を開き、**Publish** します。
ステップ 6: API を使う ### ステップ 6: API を使う コンテンツを作成し API で取得できる状態にしました。Strapi Cloud プロジェクトの URL に `/api/restaurants` を付けたパス(例: `https://beautiful-first-strapi-project.strapiapp.com/api/restaurants`)にアクセスすると、レストラン一覧が返るはずです。 試してみてください。レスポンスは次の例に近い形になります 👇。
クリックして API レスポンスの例を表示 ```json { "data": [ { "id": 3, "documentId": "wf7m1n3g8g22yr5k50hsryhk", "Name": "Biscotte Restaurant", "Description": [ { "type": "paragraph", "children": [ { "type": "text", "text": "Welcome to Biscotte restaurant! Restaurant Biscotte offers a cuisine based on fresh, quality products, often local, organic when possible, and always produced by passionate producers." } ] } ], "createdAt": "2024-09-10T12:49:32.350Z", "updatedAt": "2024-09-10T13:14:18.275Z", "publishedAt": "2024-09-10T13:14:18.280Z", "locale": null } ], "meta": { "pagination": { "page": 1, "pageSize": 25, "pageCount": 1, "total": 1 } } } ```
:::callout おつかれさまでした! コンテンツを作成・公開し、API から取得する権限も設定できました。引き続きコンテンツを充実させてください。 ::: :::tip ヒント: ローカルと Strapi Cloud 間でデータを移すには Strapi Cloud とローカルではデータベースが別のため、データは自動では同期されません。[データ管理](/cms/features/data-management) を使ってプロジェクト間で転送できます。 ::: ## 次にやること Strapi でコンテンツを作成・公開する基本がわかったら、次のトピックを掘り下げてみてください。 Strapi の [REST](/cms/api/rest) API でコンテンツを取得する方法を学ぶ
**機能** カテゴリで Strapi の機能を読む
[Strapi Cloud ドキュメント](/cloud/intro) でクラウドプロジェクトについて学ぶ
上級向けに [Strapi バックエンドのカスタマイズ](/cms/backend-customization) や [管理パネルのカスタマイズ](/cms/admin-panel-customization) に進む
# Templates Source: https://docs.strapi.io/cms/templates # Templates Templates in Strapi 5 are standalone, pre-made Strapi applications designed for specific use cases. Strapi 5 templates are folders that include all files and folders that you would find in a typical Strapi application (see [project structure](/cms/project-structure)). ## Using a template To create a new Strapi project based on a template, run the following command: In addition to the mandatory `--template` parameter, you can pass the optional `--template-path` and `--template-branch` options to more precisely define the template to use. The following table lists all the possible ways to define which template to use: | Syntax | Description | |--------|-------------| | `--template website` | Using one of the calling it by its (folder) name. | | `--template strapi/strapi` | Using the template's GitHub repository shorthand.
This will use the default repository branch. | | `--template strapi/strapi/some/sub/path` | Using the template's GitHub repository shorthand and specifying a subpath.
This will use the default repository branch. | | `--template strapi/strapi`
`--template-branch=xxx`
`--template-path=some/sub/path` | The most verbose way, explicitly defining a template branch and a subpath. | | `--template https://github.com/owner/some-template-repo` | Using a full repository URL.
This will use the default repository branch. | | `--template https://github.com/owner/some-template-repo --template-branch=xxx --template-path=sub/path` | Using a full repository URL, and specifying both the branch and the subpath for the template. | | `--template https://github.com/strapi/strapi/tree/branch/sub/path` | Using a repository, branch, and subpath directly.

⚠️ _Warning: This won't work with branch names that include a `/`. In such cases, it's best to explicitly define `--template-branch` and `--template-path`._ | ## Creating a template Creating a Strapi 5 template is as simple as creating a Strapi application. Create the application (see [CLI installation](/cms/installation/cli)) and the generated folder containing your Strapi 5 application can serve as a template. You can then pass it to the `--template` flag when creating a new Strapi 5 application to use it as a template. An example of what a template could look like is the . # Testing Source: https://docs.strapi.io/cms/testing # Unit and integration testing guide The present guide provides a hands-on approach to configuring * `Jest` provides the test runner and assertion utilities. * `Supertest` allows you to test all the `api` routes as they were instances of utilities to recreate just the parts of the Strapi object and any request context that your code relies on. ### Controller example Create a test file such as `./tests/todo-controller.test.js` that instantiates your controller with a mocked Strapi object and verifies every call the controller performs: ```js title="./tests/todo-controller.test.js" const todoController = require('./todo-controller'); describe('Todo controller', () => { let strapi; beforeEach(() => { strapi = { plugin: jest.fn().mockReturnValue({ service: jest.fn().mockReturnValue({ create: jest.fn().mockReturnValue({ data: { name: 'test', status: false, }, }), complete: jest.fn().mockReturnValue({ data: { id: 1, status: true, }, }), }), }), }; }); it('creates a todo item', async () => { const ctx = { request: { body: { name: 'test', }, }, body: null, }; await todoController({ strapi }).index(ctx); expect(ctx.body).toBe('created'); expect(strapi.plugin('todo').service('create').create).toHaveBeenCalledTimes(1); }); it('completes a todo item', async () => { const ctx = { request: { body: { id: 1, }, }, body: null, }; await todoController({ strapi }).complete(ctx); expect(ctx.body).toBe('todo completed'); expect(strapi.plugin('todo').service('complete').complete).toHaveBeenCalledTimes(1); }); }); ``` The `beforeEach` hook rebuilds the mock so every test starts with a clean Strapi instance. Each test prepares the `ctx` request object that the controller expects, calls the controller function, and asserts both the response and the interactions with Strapi services. ### Service example Services can be tested in the same test suite or in a dedicated file by mocking only the Strapi query layer they call into. ```js title="./tests/create-service.test.js" const createService = require('./create-service'); describe('Create service', () => { let strapi; beforeEach(() => { strapi = { query: jest.fn().mockReturnValue({ create: jest.fn().mockReturnValue({ data: { name: 'test', status: false, }, }), }), }; }); it('persists a todo item', async () => { const todo = await createService({ strapi }).create({ name: 'test' }); expect(strapi.query('plugin::todo.todo').create).toHaveBeenCalledTimes(1); expect(todo.data.name).toBe('test'); }); }); ``` By focusing on mocking the specific Strapi APIs your code touches, you can grow these tests to cover additional branches, error cases, and services while keeping them fast and isolated. ## Set up a testing environment For API-level testing with that sets up and tears down Strapi instances for tests ### TypeScript compiler configuration Create `tests/ts-compiler-options.js` with the following content: ```js title="./tests/ts-compiler-options.js" const fs = require('fs'); const path = require('path'); const ts = require('typescript'); const projectRoot = path.resolve(__dirname, '..'); const tsconfigPath = path.join(projectRoot, 'tsconfig.json'); const baseCompilerOptions = { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2019, moduleResolution: ts.ModuleResolutionKind.NodeJs, esModuleInterop: true, jsx: ts.JsxEmit.React, }; const loadCompilerOptions = () => { let options = { ...baseCompilerOptions }; if (!fs.existsSync(tsconfigPath)) { return options; } try { const tsconfigContent = fs.readFileSync(tsconfigPath, 'utf8'); const parsed = ts.parseConfigFileTextToJson(tsconfigPath, tsconfigContent); if (!parsed.error && parsed.config && parsed.config.compilerOptions) { options = { ...options, ...parsed.config.compilerOptions, }; } } catch (error) { // Ignore tsconfig parsing errors and fallback to defaults } return options; }; module.exports = { compilerOptions: loadCompilerOptions(), loadCompilerOptions, }; ``` This file loads your project's TypeScript configuration and provides sensible defaults if the config file doesn't exist. ### TypeScript runtime loader Create `tests/ts-runtime.js` with the following content: ```js title="./tests/ts-runtime.js" const Module = require('module'); const { compilerOptions } = require('./ts-compiler-options'); const fs = require('fs'); const ts = require('typescript'); const extensions = Module._extensions; if (!extensions['.ts']) { extensions['.ts'] = function compileTS(module, filename) { const source = fs.readFileSync(filename, 'utf8'); const output = ts.transpileModule(source, { compilerOptions, fileName: filename, reportDiagnostics: false, }); return module._compile(output.outputText, filename); }; } if (!extensions['.tsx']) { extensions['.tsx'] = extensions['.ts']; } module.exports = { compilerOptions, }; ``` This file teaches Node.js how to load `.ts` and `.tsx` files by transpiling them to JavaScript on the fly. ### Main test harness Create `tests/strapi.js` with the following content: What the test harness does: 1. **TypeScript Support**: Patches Strapi's configuration loader to understand TypeScript files (`.ts`, `.cts`, `.mts`) in your config directory 2. **Configuration Validation**: Ensures only valid config files are loaded and warns about common mistakes (like naming a file `middleware.js` instead of `middlewares.js`) 3. **Database Normalization**: Maps database client names to their actual driver names (e.g., `sqlite` → `sqlite3`) and handles connection pooling 4. **Environment Setup**: Sets all required environment variables for testing, including JWT secrets and database configuration 5. **Automatic Route Registration**: Automatically registers a `/api/hello` test endpoint that you can use in your tests 6. **User Permission Helper**: Patches the user service to automatically assign the "authenticated" role to newly created users, simplifying authentication tests 7. **Cleanup**: Properly closes connections and removes temporary database files after tests complete :::note The code example for the `tests/strapi.js` harness highlights lines 313-321 because these are optional, to be used if you [seed predictable test data](#optional-seed-predictable-test-data). ::: Once these files are in place, the harness handles several Strapi 5 requirements automatically, letting you focus on writing actual test logic rather than configuration boilerplate. ## (optional) Seed predictable test data Some API tests benefit from having a known set of documents preloaded. You can expose your project seeding as a reusable function and call it from the harness behind an environment flag: 1. Export a seeding function from your project script (e.g. `./scripts/seed.js`): ```js title="./scripts/seed.js" async function seedExampleApp() { // In test environment, skip complex seeding and just log if (process.env.NODE_ENV === 'test') { console.log('Test seeding: Skipping complex data import (not needed for basic tests)'); return; } const shouldImportSeedData = await isFirstRun(); if (shouldImportSeedData) { try { console.log('Setting up the template...'); await importSeedData(); console.log('Ready to go'); } catch (error) { console.log('Could not import seed data'); console.error(error); } } } // Allow usage both as a CLI and as a library from tests if (require.main === module) { main().catch((error) => { console.error(error); process.exit(1); }); } module.exports = { seedExampleApp }; ``` 2. In the test harness, call the function when `TEST_SEED=true` (see lines 313-321 highlighted in the code example from the [main test harness](#main-test-harness)). 3. Run your tests with seeding enabled: Seeding runs after Strapi starts, so services, permissions, and uploads are available. It's recommended to keep seeds deterministic to ensure stable assertions. If you publish entries, prefer fixed timestamps or assert on structural properties rather than transient dates. ## Create smoke tests With the harness in place you can confirm Strapi boots correctly by adding a minimal Jest suite with the following **smoke tests** in a `tests/app.test.js` as follows: ```js title="./tests/app.test.js" const { setupStrapi, cleanupStrapi } = require('./strapi'); /** this code is called once before any test is called */ beforeAll(async () => { await setupStrapi(); // Singleton so it can be called many times }); /** this code is called once before all the tests are finished */ afterAll(async () => { await cleanupStrapi(); }); it('strapi is defined', () => { expect(strapi).toBeDefined(); }); require('./hello'); require('./user'); ``` Running `yarn test` or `npm run test` should now yield: ```bash PASS tests/create-service.test.js PASS tests/todo-controller.test.js Test Suites: 6 passed, 6 total Tests: 7 passed, 7 total Snapshots: 0 total Time: 7.952 s Ran all test suites. ✨ Done in 8.63s. ``` :::caution If you receive a timeout error for Jest, increase the timeout by calling `jest.setTimeout(30000)` in `tests/strapi.js` or at the top of your test file. ::: ## Test a basic API endpoint Create `tests/hello.test.js` with the following: ```js title="./tests/hello.test.js" const { setupStrapi, cleanupStrapi } = require('./strapi'); const request = require('supertest'); beforeAll(async () => { await setupStrapi(); }); afterAll(async () => { await cleanupStrapi(); }); it('should return hello world', async () => { await request(strapi.server.httpServer) .get('/api/hello') .expect(200) .then((data) => { expect(data.text).toBe('Hello World!'); }); }); ``` The harness registers the `/api/hello` route automatically, so the test only has to make the request. ## Test API authentication Strapi uses a JWT token to handle authentication. We will create one user with a known username and password, and use these credentials to authenticate and get a JWT token. The patched `user.add` helper in the harness ensures the authenticated role is applied automatically. Create `tests/auth.test.js`: ```js title="./tests/auth.test.js" const { setupStrapi, cleanupStrapi } = require('./strapi'); const request = require('supertest'); beforeAll(async () => { await setupStrapi(); }); afterAll(async () => { await cleanupStrapi(); }); // User mock data const mockUserData = { username: 'tester', email: 'tester@strapi.com', provider: 'local', password: '1234abc', confirmed: true, blocked: null, }; it('should login user and return JWT token', async () => { await strapi.plugins['users-permissions'].services.user.add({ ...mockUserData, }); await request(strapi.server.httpServer) .post('/api/auth/local') .set('accept', 'application/json') .set('Content-Type', 'application/json') .send({ identifier: mockUserData.email, password: mockUserData.password, }) .expect('Content-Type', /json/) .expect(200) .then((data) => { expect(data.body.jwt).toBeDefined(); }); }); ``` You can use the JWT token returned to make authenticated requests to the API. Using this example, you can add more tests to validate that the authentication and authorization are working as expected. ## Advanced API testing with user permissions When you create API tests, you will most likely need to test endpoints that require authentication. In the following example we will implement a helper to get and use the JWT token. Create `tests/user.test.js`: ```js title="./tests/user.test.js" const { setupStrapi, cleanupStrapi } = require('./strapi'); const request = require('supertest'); beforeAll(async () => { await setupStrapi(); }); afterAll(async () => { await cleanupStrapi(); }); let authenticatedUser = {}; // User mock data const mockUserData = { username: 'tester', email: 'tester@strapi.com', provider: 'local', password: '1234abc', confirmed: true, blocked: null, }; describe('User API', () => { beforeAll(async () => { await strapi.plugins['users-permissions'].services.user.add({ ...mockUserData, }); const response = await request(strapi.server.httpServer) .post('/api/auth/local') .set('accept', 'application/json') .set('Content-Type', 'application/json') .send({ identifier: mockUserData.email, password: mockUserData.password, }); authenticatedUser.jwt = response.body.jwt; authenticatedUser.user = response.body.user; }); it('should return users data for authenticated user', async () => { await request(strapi.server.httpServer) .get('/api/users/me') .set('accept', 'application/json') .set('Content-Type', 'application/json') .set('Authorization', 'Bearer ' + authenticatedUser.jwt) .expect('Content-Type', /json/) .expect(200) .then((data) => { expect(data.body).toBeDefined(); expect(data.body.id).toBe(authenticatedUser.user.id); expect(data.body.username).toBe(authenticatedUser.user.username); expect(data.body.email).toBe(authenticatedUser.user.email); }); }); }); ``` ## Automate tests with GitHub Actions To go further, you can run your Jest test suite automatically on every push and pull request with . Create a `.github/workflows/test.yaml` file in your project and add the workflow as follows: ```yaml title="./.github/workflows/test.yaml" name: 'Tests' on: pull_request: push: jobs: run-tests: name: Run Tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install modules run: npm ci - name: Run Tests run: npm run test ``` Pairing continuous integration with your unit and API tests helps prevent regressions before they reach production. # TypeScript Source: https://docs.strapi.io/cms/typescript # TypeScript - Add TypeScript support to an existing Strapi project using the provided [conversion](/cms/typescript/adding-support-to-existing-project) steps.
:::strapi What to do next? - Understand the [structure](/cms/project-structure) of a TypeScript-based Strapi project - Learn about the [configuration options](/cms/configurations/typescript) options related to TypeScript - Deep dive into TypeScript-related development [options and features](/cms/typescript/development) - Read the [guides](/cms/typescript/guides) for specific use cases ::: # TypeScript development Source: https://docs.strapi.io/cms/typescript/development # TypeScript development with Strapi While developing a [TypeScript](/cms/typescript)-based application with Strapi, you can: - access [typings for the `Strapi`](#use-strapi-typescript-typings) class with autocompletion, - [generate typings](#generate-typings-for-content-types-schemas) for your project's content-types, - [start Strapi programmatically](#start-strapi-programmatically), - and follow some TypeScript-specific instructions for [plugins development](#develop-a-plugin-using-typescript). :::strapi Documents and entries More information and best practices on how to manipulate documents and entries with a TypeScript-based project can be found in the [dedicated guide](/cms/typescript/documents-and-entries). ::: ## Use `Strapi` TypeScript typings Strapi provides typings on the `Strapi` class to enhance the TypeScript development experience. These typings come with an autocomplete feature that automatically offers suggestions while developing. To experience TypeScript-based autocomplete while developing Strapi applications, you could try the following: 1. Open the `./src/index.ts` file from your code editor. 2. Import the `Core` types from `@strapi/strapi` and declare the `strapi` argument as type `Core.Strapi` within the global `register` method: ```typescript title="./src/index.ts" import type { Core } from '@strapi/strapi'; export default { register({ strapi }: { strapi: Core.Strapi }) { // ... }, }; ``` 3. Within the body of the `register` method, start typing `strapi.` and use keyboard arrows to browse the available properties. 4. Choose `runLifecyclesFunctions` from the list. 5. When the `strapi.runLifecyclesFunctions` method is added, a list of available lifecycle types (i.e. `register`, `bootstrap` and `destroy`) are returned by the code editor. Use keyboard arrows to choose one of the lifecycles and the code will autocomplete. ## Generate typings for content-types schemas To generate typings for your project schemas use the [`ts:generate-types` CLI command](/cms/cli#strapi-ts). The `ts:generate-types` command creates the folder `types`, at the project root, which stores the typings for your project. The optional `--debug` flag returns a detailed table of the generated schemas. To use `ts:generate-types`run the following code in a terminal at the project root: :::tip Tip: Automatically generate types Types can be automatically generated on server restart by adding `autogenerate: true` to [the `config/typescript.js|ts` configuration file](/cms/configurations/typescript#strapi-specific-configuration-for-typescript). ::: :::tip Tip: Using types in your front-end application To use Strapi types in your front-end application, you can until Strapi implements an official solution. ::: ### Fix build issues with the generated types The generated types can be excluded so that the Entity Service doesn't use them and falls back on looser types that don't check the actual properties available in the content types. To do that, edit the `tsconfig.json` of the Strapi project and add `types/generated/**` to the `exclude` array: ```json title="./tsconfig.json" // ... "exclude": [ "node_modules/", "build/", "dist/", ".cache/", ".tmp/", ".strapi/", "src/admin/", "**/*.test.ts", "src/plugins/**", "types/generated/**" ] // ... ``` However, if you still want to use the generated types on your project, but don't want Strapi to use them, a workaround could be to copy those generated types and paste them outside of the `generated` directory (so that they aren't overwritten when the types are regenerated) and remove the `declare module '@strapi/types'` from the bottom of the file. :::warning Types should only be imported from `@strapi/strapi` to avoid breaking changes. The types in `@strapi/types` are for internal use only and may change without notice. ::: ## Start Strapi programmatically To start Strapi programmatically in a TypeScript project the Strapi instance requires the compiled code location. This section describes how to set and indicate the compiled code directory. ### Use the `strapi()` factory {#use-the-createstrapi-factory} Strapi can be run programmatically by using the `strapi()` factory. Since the code of TypeScript projects is compiled in a specific directory, the parameter `distDir` should be passed to the factory to indicate where the compiled code should be read: ```js title="./server.js" const strapi = require('@strapi/strapi'); const app = strapi.createStrapi({ distDir: './dist' }); app.start(); ``` ### Use the `strapi.compile()` function The `strapi.compile()` function should be mostly used for developing tools that need to start a Strapi instance and detect whether the project includes TypeScript code. `strapi.compile()` automatically detects the project language. If the project code contains any TypeScript code, `strapi.compile()` compiles the code and returns a context with specific values for the directories that Strapi requires: ```js const strapi = require('@strapi/strapi'); strapi.compile().then(appContext => strapi(appContext).start()); ``` ## Develop a plugin using TypeScript New plugins can be generated following the [plugins development documentation](/cms/plugins-development/developing-plugins), ensuring you select "TypeScript" when prompted by the CLI tool. There are 2 important distinctions for TypeScript applications: - After creating the plugin, run `yarn` or `npm install` in the plugin directory `src/admin/plugins/[my-plugin-name]` to install the dependencies for the plugin. - Run `yarn build` or `npm run build` in the plugin directory `src/admin/plugins/[my-plugin-name]` to build the admin panel including the plugin. :::note It is not necessary to repeat the `yarn` or `npm install` command after the initial installation. The `yarn build` or `npm run build` command is necessary to implement any plugin development that affects the admin panel. ::: # TypeScript Guides Source: https://docs.strapi.io/cms/typescript/guides # TypeScript guides The following guides will help you on specific aspects of a [Typescript-based](/cms/typescript) Strapi project. # Upgrade tool Source: https://docs.strapi.io/cms/upgrade-tool # Upgrade tool The upgrade tool assists Strapi users in upgrading their Strapi application dependencies and code to a specific version. Running the upgrade tool triggers the update of the application dependencies, their installation, and the execution of a series of **codemods**