GraphCMS Management SDKでスキーマの生成とコンテンツのインポート 2022.05.27
背景
既存のCMSの移行を想定していくつかのHeadless CMSを検討していたが、無料で小規模のCMSを運用できてインポートに対応してそうなGraph CMSを試してみることにした。
他にもMicroCMS(無料だと制限がきつい)、prismic.io(インポートが有料プランから)、Shifter(WordPressはちょっと)、sanity.io(CMSがセルフホストっぽい?)、Headless WordPress(WordPressは)などを検討した。
WordPressは妥当な選択肢ではあるが、いまどきクラシックテーマで独特なWordPress関数群と首っ引きになるのは時間がもったいない気がするし、新しいブロックテーマもHTMLタグ(というか特殊なコメント)で論理構造を記述し、JSONでスタイルを記述するというのはおよそ尋常とは思えない。
というわけで、なんとかしてHeadless CMSで道筋をつけたい。
管理画面での設定
まずはGraphCMSのウェブサイトで初期設定を行う。
プロジェクトの作成
アカウントはGitHubアカウントで作成。「Create a new project」の画面で「Blank」テンプレートから開始する。
「Project name」を入力。リージョンは「Japan(Tokyo)」を選択。「Create project」をクリック。
プランは「Community(Free forever)」を選択する。
「Invite your team members」はスキップ。
管理画面に到達。左メニュー下の歯車アイコンから「Settings」に移動。
エンドポイントの確認
「Environments」に移動して「Master Environment」のURL(エンドポイント)を控えておく。
認証トークンの設定
「API Access」に移動して一番下の「Permanent Auth Tokens」で「Create Token」。ここに「Management API」というエンドポイントがあるが今回は使わない。これは何のためにあるのだろう。内部的に呼んでいるとか?
「Create token」ダイアログで、名前は適当に「Developer」などとして「Create & configure permissons」。
Management APIの権限設定
自動的にトークンの詳細を設定する画面に移動した。順番が前後するが、まず一番下の「Management API」から「Yes, initialize defaults」としてみる。
3つほど権限が追加されたが、これでは足りないので「Edit Permissions」で権限を追加する。
適当に使いそうな権限をチェック。スキーマを送信するときに「Read existing environment」が必要なのでこれは必ず入れておく。
Content APIの権限設定
「Management API」の権限が設定できたら、コンテンツを送信するために「Content API」の権限も設定する(API Access画面ではなく、トークンに対して設定する)。「Create permission」をクリック。
適当に使いそうな権限を追加。今回はRead、Create、Update、Publishの権限をチェック。
「Content API」の権限が設定できた。
認証トークンの確認
「API Access」の画面に戻って、Developerトークンの「Value」を控えておく。
これで管理画面での設定ができた。
Management SDKでの作業
ここからは@graphcms/managementを使ってローカル環境からスキーマ定義とコンテンツを追加していく。
スキーマの作成については@graphcms/managementのリポジトリのREADMEにQuickstartがあるので参考にする。
コンテンツのインポートについては公式のMigrating to GraphCMSを参考にする。
% mkdir graphcms-sdk-trial; cd $_
% npm init -y
% npm install -D @graphcms/management graphql-request dotenv
% touch {migration,import}.js
% touch .env
.env
ファイルに認証情報を追加。管理画面で控えておいた「Environments」の「Master Environment」のURLと「Manegement Auth Token」を追加。
GRAPHCMS_ENDPOINT="https://api-ap-northeast-1.graphcms.com/v2/.../master"
GRAPHCMS_TOKEN="eyJh..."
スキーマの作成
migration.js
を実行することでスキーマを送信できるようにする。
% node ./migration.js
内容はほぼQuickstartの通り。ブログを意識しているのでモデル名はPost
としている。
require("dotenv").config();
const { newMigration, FieldType, Renderer } = require("@graphcms/management");
const migration = newMigration({
endpoint: process.env.GRAPHCMS_ENDPOINT,
authToken: process.env.GRAPHCMS_TOKEN,
name: "createPostSchema",
});
const post = migration.createModel({
apiId: "Post",
apiIdPlural: "Posts",
displayName: "Post",
});
post.addSimpleField({
apiId: "title",
displayName: "Title",
type: FieldType.String,
});
post.addSimpleField({
apiId: "content",
displayName: "Content",
type: FieldType.String,
formRenderer: Renderer.MultiLine,
});
const changes = migration.dryRun();
console.log(changes);
まず、ドライランしてみる。console.log
で以下の通りの出力を得る。
[
{
"createModel": {
"apiId": "Post",
"apiIdPlural": "Posts",
"displayName": "Post"
}
},
{
"createSimpleField": {
"apiId": "title",
"displayName": "Title",
"type": "STRING",
"modelApiId": "Post",
"formRenderer": "GCMS_SINGLE_LINE"
}
},
{
"createSimpleField": {
"apiId": "content",
"displayName": "Content",
"type": "STRING",
"formRenderer": "GCMS_MULTI_LINE",
"modelApiId": "Post"
}
}
]
問題なさそうなので、実行できるようにする。
- const changes = migration.dryRun();
- console.log(changes);
+ // run migration
+ const foreground = true;
+ (async function () {
+ const result = await migration.run(foreground);
+ if (result.errors) {
+ console.log(result.errors);
+ return;
+ }
+ console.log(result.name);
+ })();
% node ./migration.js
createPostSchema
で、スキーマが作成できた。
コンテンツのインポート
公式の記事では CSVを使っているが、ここでは簡単のため最初からJSONを使う。あと、Redisが必要そうなbee-queueは使わない。
この記事ではなんの脈絡もなくライブラリ由来のインスタンスが出てくるので面食らうが、サンプルをいくつか眺めるとわかる。
- csvToJson → convert-csv-to-json
- GraphQLClient、gql → graphql-request
- Queue → bee-queue
% touch import.json
[
{
"title": "投稿です",
"content": "<strong>投稿です</strong>\n<a>http://example.com</a>"
},
{
"title": "投稿2",
"content": "あああああ\nあああああ\nあああああ"
},
{
"title": "投稿3",
"content": "<div>あああああ</div>"
}
]
このJSONファイルを読み込んでコンテンツを送信するようにimport.js
のコードを追加する。
require("dotenv").config();
const fs = require("fs");
const { GraphQLClient, gql } = require("graphql-request");
const createContentEntry = async (row) => {
const client = new GraphQLClient(process.env.GRAPHCMS_ENDPOINT, {
headers: {
Authorization: `Bearer ${process.env.GRAPHCMS_TOKEN}`,
},
});
const query = gql`
mutation createPost($title: String, $content: String) {
createPost(data: { title: $title, content: $content }) {
id
}
}
`;
return client.request(query, row);
};
const run = async () => {
const data = JSON.parse(fs.readFileSync("./import.json", "utf8"));
await Promise.all(
data.map(async (row) => {
return await createContentEntry(row);
}),
);
};
run();
% node ./import.js
実行すると、コンテンツをインポートできた。
コンテンツの公開
コンテンツが「Draft」になっているのでAPIを使って公開する。
% touch publish.js
require("dotenv").config();
const { GraphQLClient, gql } = require("graphql-request");
const publishContentEntries = async () => {
const client = new GraphQLClient(process.env.GRAPHCMS_ENDPOINT, {
headers: {
Authorization: `Bearer ${process.env.GRAPHCMS_TOKEN}`,
},
});
const query = gql`
mutation {
publishManyPostsConnection(first: 5, to: PUBLISHED) {
edges {
node {
id
}
}
}
}
`;
return client.request(query);
};
const run = async () => {
await publishContentEntries();
};
run();
GraphCMSではモデルを作成すると自動でmutation
が生成される。createPost
やpublishManyPostsConnection
がそれにあたる。とても便利。
% node ./publish.js
公開できた。
実際にCMSを移行するとなるとそれなりに苦労しそうではあるものの、コンテンツのインポートはできそうなことがわかった。
API Playground
左メニュー中ほどの右向き三角形アイコンから「Playground」に移動。実際にAPIのGraphQLのレスポンスを確認できる。