コンテンツにスキップ

GraphQL で取り出す

GraphQL の API を使うと、ページに要るものを 1 回の呼び出しで取り出せます。記事の一覧とサイトの設定のように、別のコンテンツタイプのエントリーも一緒に取れます。返るのは、問い合わせに書いたフィールドだけです。

GraphQL のスキーマはスペースのコンテンツタイプから自動で作られます。コンテンツタイプやフィールドを足すと、そのまま問い合わせに使えます。

  • [読み取り]の権限のある API キー。発行のしかたは API キーを作る、権限を決める にあります。権限は REST の Content API と同じです
  • 取り出すエントリーが[公開中]になっていること。下書きを取るときは、この下の「下書きを取る」を見てください
  • コンテンツタイプ ID。コンテンツタイプの画面で[エンドポイント]と出ている値です(例:「posts」)

下の例では、次の値を置き換えてください。

  • <ホスト名>:あなたの環境のホスト名。管理画面のアドレス https://<ホスト名>.hakocms.net の部分です
  • <API キー>:hako_ で始まる API キー

例のスペースには、コレクションの「posts」(記事)と「authors」(著者)、シングルの「site-settings」(サイトの設定)があります。記事のフィールドは title(テキスト)、body(リッチテキスト)、tags(セレクト)、author(著者への参照)です。

問い合わせは /api/v1/graphql に POST で送ります。本文は JSON で、query に問い合わせを書きます。API キーは REST と同じく Authorization: Bearer で送ります。

記事の数を数え、2 件のタイトルを取り出します。

ターミナルウィンドウ
curl https://<ホスト名>.hakocms.net/api/v1/graphql \
-H "Authorization: Bearer <API キー>" \
-H "Content-Type: application/json" \
-d '{"query": "{ postsCollection(limit: 2) { total items { title } } }"}'

次のように返ります。

{
"data": {
"postsCollection": {
"total": 3,
"items": [
{ "title": "年末年始のお休み" },
{ "title": "GraphQL で読む" }
]
}
}
}

本文には query のほかに variables(変数)と operationName(実行する問い合わせの名前)も書けます。

型とフィールドの名前は、コンテンツタイプ ID とフィールド ID から決まります。

取り出すもの 問い合わせのフィールド コンテンツタイプ ID が「blog-posts」なら
コレクションの一覧 ID をつなげて先頭を小文字にした名前に Collection blogPostsCollection
コレクションの 1 件 ID をつなげて先頭を小文字にした名前 blogPosts(id: "hello")
シングル ID をつなげて先頭を小文字にした名前 (「site-settings」なら)siteSettings
  • 型の名前は ID をつなげて先頭を大文字にした名前です(BlogPosts)
  • フィールドの名前はフィールド ID のままです。GraphQL の名前に使えない - は _ になります(old-field は old_field)
  • どのエントリーにも sys があり、id、contentType、createdAt、updatedAt、publishedAt、firstPublishedAt、version を取り出せます

正確な型はこの下の「スキーマを取る」で、スペースのスキーマを取り出して確かめられます。

トップページに要る、新しい記事 2 件(タイトル、タグ、著者の名前)と、サイトの名前を 1 回で取り出します。Home は問い合わせの名前で、好きに付けられます。

query Home {
postsCollection(limit: 2) {
total
items {
sys { id publishedAt }
title
tags
author { name }
}
}
siteSettings { siteName }
}

次のように返ります。

{
"data": {
"siteSettings": { "siteName": "山田ブログ" },
"postsCollection": {
"total": 3,
"items": [
{
"sys": {
"id": "holiday",
"publishedAt": "2026-10-21T15:16:12.691Z"
},
"title": "年末年始のお休み",
"tags": ["news"],
"author": { "name": "山田 花子" }
},
{
"sys": {
"id": "graphql",
"publishedAt": "2026-10-21T15:16:11.661Z"
},
"title": "GraphQL で読む",
"tags": ["tech"],
"author": { "name": "山田 花子" }
}
]
}
}
}
  • 一覧は既定で公開した日時の新しい順に、20 件までです。limit(0〜100)と offset で区切ります
  • 参照(author)は問い合わせに書いた分だけたどります。REST の include は要りません。たどれるのは、いちばん上を含めて 4 段までです
  • 参照先が公開されていないときや消されたときは、参照のフィールドは null になります。複数参照なら、配列から除かれます

一覧のフィールドに where と order を付けます。値は変数で渡せます。タグ「news」の記事を、公開した日時の新しい順に取り出します。

query News($tag: String!) {
postsCollection(
where: { tags: { contains: $tag } }
order: [sys_publishedAt_DESC]
) {
items { title }
}
}

変数は本文の variables に書きます。

{ "tag": "news" }

次のように返ります。

{
"data": {
"postsCollection": {
"items": [
{ "title": "年末年始のお休み" },
{ "title": "サイトを公開しました" }
]
}
}
}
  • where にはフィールドごとに条件を書きます。使える条件はフィールドの種類で決まります(テキストなら eq、contains、startsWith など、数値と日時なら lt、gte など)。意味は REST の where と同じで、絞り込む、並べる、ページに分ける にあります
  • 条件を組み合わせるときは、and、or、not を使います。sys の id や日時でも絞り込めます
  • order は、<フィールド ID>_ASC(小さい順)か <フィールド ID>_DESC(大きい順)を並べます。並べられるのは、テキスト、テキストエリア、日時、数値のフィールドと、sys の id と日時です
  • 一覧のフィールドに q を付けると、全文検索になります。意味は 全文検索を使う と同じです

1 件を取り、リッチテキストを HTML で受け取る

Section titled “1 件を取り、リッチテキストを HTML で受け取る”

エントリー ID を id に渡します。リッチテキストのフィールドは、html を選ぶとサーバーで HTML にしたものが、json を選ぶと JSON の形が返ります。

query Post($id: ID!) {
posts(id: $id) {
title
body { html }
}
}

変数に { "id": "hello" } を渡すと、次のように返ります。

{
"data": {
"posts": {
"title": "サイトを公開しました",
"body": { "html": "<p>今日からサイトを公開します。</p>" }
}
}
}

エントリーがないときや、公開していないときは、posts が null になります。JSON の形は リッチテキストの形(Hako Rich Text v1) にあります。

JavaScript(ブラウザ、Node.js)では、fetch で送ります。次のコードは上の「絞り込む、並べる」の問い合わせを送り、タイトルを表示します。

const res = await fetch(
"https://<ホスト名>.hakocms.net/api/v1/graphql",
{
method: "POST",
headers: {
Authorization: "Bearer <API キー>",
"Content-Type": "application/json",
},
body: JSON.stringify({
query: `query News($tag: String!) {
postsCollection(where: { tags: { contains: $tag } }) {
items { title }
}
}`,
variables: { tag: "news" },
}),
},
);
const { data, errors } = await res.json();
if (errors) throw new Error(errors[0].message);
console.log(data.postsCollection.items.map((p) => p.title));

どのオリジンからも呼べます(CORS)。ブラウザに渡す API キーは[読み取り]だけの権限にしてください。

問い合わせのいちばん上のフィールドに preview: true を付けると、公開する前の下書きを取り出せます。その下でたどる参照先も下書きの値になります。

{
posts(id: "hello", preview: true) { title }
}

下書きを読めるのは、[プレビュー]の権限のある API キーだけです。このキーはサイトのサーバーの中だけで使い、ブラウザに渡さないでください。詳しくは 下書きを取る(プレビュー) にあります。

スペースの GraphQL のスキーマ(SDL)は、次のように取り出せます。イントロスペクションにも答えるので、GraphQL の道具(エディターの補完、GraphQL Code Generator など)をそのままつなげます。

ターミナルウィンドウ
curl https://<ホスト名>.hakocms.net/api/v1/schema/graphql \
-H "Authorization: Bearer <API キー>"

次のように始まるテキストが返ります(一部)。コンテンツタイプとフィールドの名前が、説明として入っています。

"""
著者(authors)
"""
type Authors {
sys: Sys!
"""
名前
"""
name: String
}

フィールドの種類ごとの型は次のとおりです。

フィールドの種類 GraphQL の型 値がないとき
テキスト、テキストエリア String null
リッチテキスト RichText(json、html) null
画像 Image(url、width、height、alt) null
複数画像 [Image!]! []
ファイル File(url、fileSize) null
日時 DateTime(RFC 3339 の文字列) null
真偽値 Boolean! false
数値 Float null
セレクト [String!]!(選択肢の値) []
参照 参照先の型 null
複数参照 参照先の型の配列 []
カスタム コンテンツタイプとカスタムフィールドの名前をつなげた型 null
繰り返し カスタムの型の配列。カスタムが 2 つ以上なら union の配列 []

重い問い合わせでサイトが遅くならないよう、次の上限があります。

もの 上限
1 回の一覧の件数(limit) 0〜100。既定は 20
1 回の呼び出しで返すエントリーの合計(参照先を含む) 1,000
参照のたどり いちばん上を含めて 4 段
問い合わせの深さ 10
問い合わせの複雑さ(書いたフィールドの数) 2,000
本文の大きさ 64 KB。超えると 413

data に、書いたフィールドが返っていれば取り出せています。うまくいかないときは、応答の errors を見てください。GraphQL の誤りは HTTP の 200 と、errors で返ります。

{
"data": null,
"errors": [
{
"message": "limit must be an integer from 0 to 100",
"locations": [{ "line": 2, "column": 3 }],
"extensions": { "code": "BAD_REQUEST" }
}
]
}

1 つの問い合わせに書いたフィールドのうち、誤りのあったものだけが data から除かれ、ほかのフィールドは返ります。

返ってきたもの 原因 直し方
401 unauthorized API キーがない、違う、または失効している Authorization: Bearer のあとに、hako_ で始まるキーをそのまま入れているか確かめます
400 bad_request 本文が GraphQL の要求の形(query を持つ JSON)でない 本文を {"query": "…"} の形にし、JSON として正しいか確かめます
errors の code が FORBIDDEN キーに、そのコンテンツタイプを読む権限がない。または preview: true にプレビューの権限がない [API キー]の画面で、キーの権限を確かめます
errors の code が BAD_REQUEST 引数の値が正しくない(limit が範囲の外、where の条件が合わないなど) message に理由が出ます
errors で Unknown field スキーマにないフィールドを書いた 名前を「名前の決まり」で確かめます。スキーマを取ると、正確な名前が分かります