kuroco-api-integration
Kuroco API連携パターン
Kuroco HeadlessCMSのAPI設計・実装に関するベストプラクティスを提供します。
ドキュメント参照: /kuroco-docs スキルを使用してKuroco公式ドキュメントを検索・参照できます。
エンドポイント設計
基本構造
KurocoのAPIパスは以下の形式:
https://{サイトキー}.g.kuroco.app/rcms-api/{api_id}/{endpoint_path}
例:
https://example.g.kuroco.app/rcms-api/1/news
https://example.g.kuroco.app/rcms-api/1/member/login
エンドポイント設定の主要項目
| 項目 | 説明 | 例 |
|---|---|---|
| パス | エンドポイントのURL | news, member/list |
| モデル | 操作対象 | Topics, Member, InquiryForm |
| オペレーション | 操作種別 | list, details, insert, update, delete |
| キャッシュ | レスポンスキャッシュ期間 | 86400(1日) |
| 流量制限 | リクエスト数制限 | 100回/分 |
| 認証必須 | ログイン必須かどうか | true/false |
主要カテゴリとモデル
認証(Authentication)
| オペレーション | 説明 | メソッド |
|---|---|---|
login_challenge |
ログイン | POST |
token |
アクセストークン取得 | POST |
logout |
ログアウト | POST |
profile |
ログインユーザー情報取得 | GET |
reminder |
パスワードリマインダー | POST |
コンテンツ(Topics)
| オペレーション | 説明 | メソッド |
|---|---|---|
list |
一覧取得 | GET |
details |
詳細取得 | GET |
insert |
新規追加 | POST |
update |
更新 | POST |
delete |
削除 | POST |
bulk_upsert |
一括更新 | POST |
メンバー(Member)
| オペレーション | 説明 | メソッド |
|---|---|---|
list |
メンバー一覧 | GET |
details |
メンバー詳細 | GET |
insert |
メンバー登録 | POST |
update |
メンバー更新 | POST |
フォーム(InquiryMessage/InquiryForm)
| オペレーション | 説明 | メソッド |
|---|---|---|
send |
フォーム送信 | POST |
list |
回答一覧 | GET |
details |
回答詳細 | GET |
セキュリティ設定
詳細リファレンス: セキュリティ設定の詳細は
references/security-settings.mdを参照してください。ドキュメント同期:
docs/ディレクトリが未同期の場合、ユーザーに「Kurocoドキュメントが未同期です。/kuroco-docsスキルで同期してよいですか?」と確認し、同期後にdocs/management/api-security.md等を参照してください。
認証方式
管理画面: [API] → [セキュリティ] で4種類から選択。
| 認証方式 | 用途 | ヘッダー |
|---|---|---|
| なし | 開発・テスト用(本番非推奨) | 不要 |
| 静的アクセストークン | サーバー間通信、公開API | X-RCMS-API-ACCESS-TOKEN: {固定トークン} |
| 動的アクセストークン | ログイン必須サイト(JWT) | X-RCMS-API-ACCESS-TOKEN: {動的トークン} |
| Cookie | ログイン必須Webサイト | credentials: 'include'(フロントエンド側) |
1. Cookie認証(Webアプリ推奨)
セッションベースの認証。credentials: 'include' が必須。
// ログイン
const response = await fetch('https://example.g.kuroco.app/rcms-api/1/login', {
method: 'POST',
credentials: 'include', // 必須
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: 'user@example.com',
password: 'password123'
})
})
// レスポンス例
// {
// "grant_token": "xxxxx",
// "status": 0,
// "member_id": 123
// }
注意点:
- サードパーティCookie問題(Safari等でブロックされる)
- APIドメインとフロントエンドを**同一ドメイン(サブドメイン違い)**に設定が必要(ファーストパーティCookie化)
- 例:
api.example.comとwww.example.com
- 例:
- Cookie認証APIが複数ある場合、各API間で認証状態が共有される
2. トークン認証(モバイルアプリ推奨)
JWTベースの認証。ヘッダーにトークンを付与。
// トークン取得
const tokenResponse = await fetch('https://example.g.kuroco.app/rcms-api/1/token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: 'user@example.com',
password: 'password123'
})
})
const { access_token, refresh_token } = await tokenResponse.json()
// レスポンス例
// {
// "access_token": {
// "value": "eyJhbGciOiJS...",
// "expiresAt": "2024-01-01T12:00:00+09:00"
// },
// "refresh_token": {
// "value": "xxxxxx",
// "expiresAt": "2024-01-08T12:00:00+09:00"
// }
// }
// API呼び出し時
const response = await fetch('https://example.g.kuroco.app/rcms-api/1/news', {
headers: {
'X-RCMS-API-ACCESS-TOKEN': access_token.value
}
})
前提条件: ユーザー1人以上、login_challenge + token エンドポイント必須。トークン認証APIが複数ある場合、各API間で認証状態は共有されない。
3. StaticToken認証(サーバー間通信)
固定トークンによるAPIアクセス制限。
const response = await fetch('https://example.g.kuroco.app/rcms-api/1/internal-api', {
headers: {
'X-RCMS-API-ACCESS-TOKEN': 'your-static-token-here'
}
})
設定場所: 管理画面 → API → セキュリティ → StaticToken
注意: 静的トークンはフロントエンドに組み込まれるとユーザーに見える。流出時のトークン更新を想定した運用が必要。
IPアドレス制限
管理画面: [API] → [セキュリティ] → [IPアドレス制限]
指定されたIPアドレスからのアクセスのみ許可します。
| 指定形式 | 例 | 説明 |
|---|---|---|
| 個別IP | 192.0.2.1 |
単一IPアドレス |
| CIDR | 192.0.2.0/24 |
サブネット単位 |
| 範囲指定 | 192.0.2.1-192.0.2.2 |
ハイフンによるIP範囲 |
IPアドレスグループ: 定数機能で IPSETS_* を定義し、[[IPSETS_*]] で参照可能(docs/faq/is-it-possible-to-set-multiple-ip-addresses-at-once.mdx 参照)。
CORS設定
管理画面: [API] → [セキュリティ] → [CORS]
| 項目 | 対応ヘッダー | 説明 |
|---|---|---|
| CORS_ALLOW_ORIGINS | Access-Control-Allow-Origin | 許可オリジン(ワイルドカード*は非推奨) |
| CORS_ALLOW_METHODS | Access-Control-Allow-Methods | 許可HTTPメソッド |
| CORS_ALLOW_HEADERS | Access-Control-Allow-Headers | 許可リクエストヘッダー |
| CORS_MAX_AGE | Access-Control-Max-Age | プリフライトキャッシュ秒数 |
| CORS_ALLOW_CREDENTIALS | Access-Control-Allow-Credentials | Cookie送信の許可 |
CSRF対策: CORS + Content-Type: application/json でモダンブラウザでのCSRF攻撃を防御。ワイルドカードを使うと防御効果がなくなるため、必ず特定ドメインを指定すること。
変更反映の遅延: CORS設定変更後は CORS_MAX_AGE 分だけブラウザにキャッシュされる。即時反映にはブラウザキャッシュクリアまたは CORS_MAX_AGE を 0 に設定。
APIリクエスト制限
| 制限タイプ | 説明 |
|---|---|
| None | 制限なし |
| GroupAuth | ログインユーザーのグループ権限をチェックし、合致した場合のみ許可 |
| MemberCustomSearchAuth | ログインユーザーがカスタムメンバーフィルターの条件に合致する場合のみ許可 |
閲覧制限の優先順序
コンテンツ返却時の制限は以下の順序で評価されます(上位優先):
- API → IPアドレス制限(API全体)
- エンドポイント → APIリクエスト制限(エンドポイント単位)
- コンテンツ定義 → APIリクエスト制限
- コンテンツカテゴリ → APIリクエスト制限
- 個別コンテンツ → APIリクエスト制限
後処理によるレスポンス制限
管理画面: [API] → エンドポイント → [後処理]
APIレスポンスから不要なフィールドを除外し、公開情報を制御:
| 処理タイプ | 説明 |
|---|---|
| 出力許可リスト | 指定フィールドのみ返す(ホワイトリスト)。例: list.subject, pageInfo |
| 出力変換リスト | フィールドの削除・名称変更・変換関数の適用 |
| カスタム処理 | Smartyテンプレートでの独自ロジック |
パフォーマンスTip: 出力許可リストは他の処理の前に配置するとSQLレベルで効果あり。
プラットフォームセキュリティ
Kurocoプラットフォームが提供するインフラレベルのセキュリティ:
- 通信: HTTPS完全暗号化、TLS証明書自動管理
- 防御: WAF、CDN、DDoS対策(オプションでFastly DDoS Protection)
- 認証連携: SAML/OAuth外部ログイン、クライアント証明書(オプション)
- 監査: アクセスログ、アプリケーションログ
- 認定: ISMS (ISO 27001)、ISMSクラウド (ISO 27017)、プライバシーマーク
- 診断: 毎日のコンテナ脆弱性スキャン、VADDY連携自動診断
管理API(mng_api)による設定変更
APIのセキュリティ設定は管理画面だけでなく、管理API経由でも操作可能です。/kuroco-mng-api-browser スキルを使用してブラウザ経由で管理APIを実行できます。
キャッシュ戦略
推奨設定
| ユースケース | キャッシュ期間 | 設定値 |
|---|---|---|
| 静的コンテンツ(ニュース等) | 1日 | 86400 |
| 更新頻度低いコンテンツ | 1週間 | 604800 |
| リアルタイム性が必要 | キャッシュなし | 0 |
| 認証が必要なAPI | キャッシュなし | 0 |
重要: コンテンツ・メンバー等のデータ更新時、キャッシュは自動クリアされます。
キャッシュヘッダー
レスポンスヘッダーで確認可能:
Cache-Control: max-age=86400
流量制限
レスポンスヘッダー
x-rcms-ratelimit-limit: 100 # 制限数
x-rcms-ratelimit-remaining: 95 # 残りリクエスト数
x-rcms-ratelimit-reset: 60 # リセットまでの秒数
429エラー時の対応
const response = await fetch(url)
if (response.status === 429) {
const resetTime = response.headers.get('x-rcms-ratelimit-reset')
console.log(`流量制限超過。${resetTime}秒後に再試行してください`)
}
API呼び出しパターン
一覧取得(ページネーション付き)
async function fetchNewsList(page = 1, perPage = 10) {
const params = new URLSearchParams({
pageID: page,
cnt: perPage
})
const response = await fetch(
`https://example.g.kuroco.app/rcms-api/1/news?${params}`,
{ credentials: 'include' }
)
const data = await response.json()
// レスポンス構造
// {
// "list": [...],
// "pageInfo": {
// "totalCnt": 100,
// "perPage": 10,
// "totalPageCnt": 10,
// "pageNo": 1
// }
// }
return data
}
フィルター検索
// filter パラメータで検索
const params = new URLSearchParams({
filter: 'subject contains "重要"',
order_by: 'ymd desc'
})
const response = await fetch(
`https://example.g.kuroco.app/rcms-api/1/news?${params}`,
{ credentials: 'include' }
)
詳細取得
async function fetchNewsDetail(topicsId) {
const response = await fetch(
`https://example.g.kuroco.app/rcms-api/1/newsdetail/${topicsId}`,
{ credentials: 'include' }
)
const data = await response.json()
// レスポンス構造
// {
// "details": {
// "topics_id": 1,
// "subject": "タイトル",
// "contents": "<p>本文</p>",
// ...
// }
// }
return data.details
}
コンテンツ作成
async function createNews(newsData) {
const response = await fetch(
'https://example.g.kuroco.app/rcms-api/1/news/insert',
{
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
subject: newsData.title,
contents: newsData.body,
ymd: newsData.date,
topics_flg: 1 // 1: 公開, 0: 非公開
})
}
)
return response.json()
}
エラーハンドリング
主要エラーコード
| コード | 説明 | 対応 |
|---|---|---|
| 400 | リクエストエラー | リクエストパラメータを確認 |
| 401 | 認証エラー | ログイン状態・トークンを確認 |
| 403 | 権限エラー | APIの権限設定を確認 |
| 404 | リソース未存在 | パス・IDを確認 |
| 429 | 流量制限超過 | リトライまで待機 |
| 500 | サーバーエラー | Kurocoサポートに連絡 |
エラーレスポンス例
{
"errors": [
{
"code": "authentication_error",
"message": "ログインが必要です"
}
]
}
エラーハンドリング実装
async function apiRequest(url, options = {}) {
try {
const response = await fetch(url, {
credentials: 'include',
...options
})
if (!response.ok) {
const errorData = await response.json()
switch (response.status) {
case 401:
// ログイン画面へリダイレクト
throw new Error('認証が必要です')
case 403:
throw new Error('アクセス権限がありません')
case 429:
throw new Error('リクエスト制限を超えました')
default:
throw new Error(errorData.errors?.[0]?.message || 'APIエラー')
}
}
return response.json()
} catch (error) {
console.error('API Error:', error)
throw error
}
}
関連スキル
/kuroco-content-management- コンテンツCRUD操作/kuroco-frontend-integration- Nuxt.js/Next.jsでのAPI呼び出しパターン/kuroco-ai-deployment- AI自動デプロイ(mng_api経由・ブラウザ認証)/kuroco-mng-api-browser- 管理API(mng_api)の操作
関連ドキュメント
スキル内リファレンス
references/security-settings.md- セキュリティ設定の詳細リファレンス
Kuroco公式ドキュメント(docs/)
docs/management/api-security.md- APIセキュリティ設定(認証方式、IP制限)docs/management/api-list.md- API一覧・CORS設定docs/management/api-postprocessing.md- API後処理の設定docs/reference/endpoint-settings.md- エンドポイント設定項目一覧docs/reference/post-processing.md- 後処理の詳細リファレンスdocs/tutorials/configure-endpoint.md- エンドポイント設定方法docs/tutorials/login.md- ログイン実装docs/tutorials/restricting-api-access-with-statictoken.md- StaticToken認証docs/reference/api-cache.md- APIキャッシュdocs/reference/filter-query.md- フィルタークエリdocs/about/security.md- プラットフォームセキュリティ概要docs/faq/in-what-order-are-viewing-restrictions-applied.mdx- 閲覧制限の優先順序docs/faq/cors-and-content-type-prevent-csrf-attacks.mdx- CSRF対策docs/faq/the-api-returns-403-forbidden-even-though-no-restrictions-are-applied.mdx- 403エラーの解決