コンテンツにスキップ

絞り込む、並べる、ページに分ける

エントリーの一覧は、条件で絞り込み、好きな順に並べ、何件かずつに分けて取り出せます。使うのは、一覧の URL に付ける 4 つのパラメーターです。

パラメーター すること 既定
where 条件で絞り込む 絞り込まない
order 並べる 公開した日時の新しい順(-sys.publishedAt)
limit 1 回に返す数。0〜100 20
offset 先頭から飛ばす数 0

この 4 つは一覧だけで使えます。1 件やシングルを取り出す URL に付けると、400 が返ります。

下の例では、<ホスト名> をあなたの環境のホスト名に、<API キー> を API キーに置き換えてください。コンテンツタイプ ID は「posts」、フィールド ID は「title」の例です。

where には、SQL の WHERE 句に似た式を書きます。式には空白や記号が入るので、URL に入れるときはエンコードします。curl なら --data-urlencode を使います。

タイトルに「Rust」を含むエントリーに絞り込みます。

ターミナルウィンドウ
curl -G https://<ホスト名>.hakocms.net/api/v1/content/posts \
-H "Authorization: Bearer <API キー>" \
--data-urlencode 'where=title contains "Rust"'

当てはまるエントリーだけが items に入り、total が当てはまる数になります。

JavaScript では、URLSearchParams がエンコードします。

const params = new URLSearchParams({
where: 'title contains "Rust" and sys.publishedAt >= "2026-10-01"',
});
const res = await fetch(
`https://<ホスト名>.hakocms.net/api/v1/content/posts?${params}`,
{ headers: { Authorization: "Bearer <API キー>" } },
);
const { items, total } = await res.json();
やりたいこと 書き方
等しい、等しくない category = "tech"、category != "tech"
大小 price < 1000、price <= 1000、price > 0、price >= 0
日時 sys.publishedAt >= "2026-10-01"、eventAt < "2026-10-08T09:00:00+09:00"
含む、含まない title contains "Rust"、title not contains "Rust"
前方一致 title startsWith "Rust"
どれかに一致、どれにも一致しない sys.id in ("a", "b")、category not in ("pr", "ad")
値がある、ない eyecatch exists、eyecatch not exists
組み合わせる and、or、not、括弧 ( )

条件を組み合わせた例です。

category = "tech" and (title contains "Rust" or title contains "Go")
  • 文字列と日時は "…" か '…' で囲みます。中の引用符は \" \'、\ は \\ と書きます
  • 数値と true、false は囲みません
  • 日時は、RFC 3339 か、日付だけで書きます。日付だけなら、その日の 0 時(UTC)です。比べるときは UTC にそろえます
  • and or not などのキーワードは、大文字でも小文字でもかまいません
  • 先に結び付くのは not、次に and、最後に or です(SQL と同じ)
  • contains は部分一致です。% や _ に特別な意味はありません
  • !=、not contains、not in、not で否定したときは、値のないエントリーも当てはまります

ユーザーが入れた語を式に埋め込むときは、" と \ の前に \ を足してから囲んでください。そのまま埋め込むと、語の中の " で式が壊れます。

const quote = (s) => `"${s.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
const where = `title contains ${quote(keyword)}`;

フィールドの種類ごとに使える演算子

Section titled “フィールドの種類ごとに使える演算子”
対象 使える演算子
sys.id = != contains not contains startsWith in not in
sys.createdAt sys.updatedAt sys.publishedAt sys.firstPublishedAt = != < <= > >= startsWith in not in
テキスト、テキストエリア = != contains not contains startsWith in not in exists
数値 = != < <= > >= in not in exists
日時 = != < <= > >= startsWith in not in exists
真偽値 = != in not in。値がなければ false として比べる
参照 参照先のエントリー ID で = != in not in exists
複数参照、セレクト = != contains not contains in not in exists。= は「その値を要素に含む」
画像、ファイル、リッチテキスト、カスタム exists
複数画像、繰り返し exists(空でないか)

参照先のフィールドで絞り込むこと(author.name = "Kohei" など)は、まだできません。参照先のエントリー ID で絞り込んでください(author = "kohei")。

1 つの式に書ける条件は 30 個まで、括弧と not の入れ子は 5 段まで、式の長さは 2000 文字まで、in の値は 100 個までです。URL 全体は 8 KB までで、超えると 414 が返ります。

order に、並べる基準を書きます。先頭に - を付けると、大きい順(新しい順)になります。カンマで区切ると、前の基準で同じものを次の基準で並べます。

公開した日時の新しい順に並べ、同じならタイトルの順に並べます。

ターミナルウィンドウ
curl -G https://<ホスト名>.hakocms.net/api/v1/content/posts \
-H "Authorization: Bearer <API キー>" \
--data-urlencode "order=-sys.publishedAt,title"
  • 並べられるのは、sys.id、sys.createdAt、sys.updatedAt、sys.publishedAt、sys.firstPublishedAt と、テキスト、テキストエリア、日時、数値のフィールドです
  • 文字列はバイトの順、数値は数の大きさ、日時は時刻の順に比べます
  • 値のないエントリーは、どちらの向きでも後ろに並びます
  • 基準がすべて同じエントリーは、新しく作った順に並びます

ページに分ける(limit と offset)

Section titled “ページに分ける(limit と offset)”

limit で 1 回に返す数を、offset で先頭から飛ばす数を決めます。1 ページ 10 件の 3 ページ目(21〜30 件目)を取り出します。

ターミナルウィンドウ
curl -G https://<ホスト名>.hakocms.net/api/v1/content/posts \
-H "Authorization: Bearer <API キー>" \
-d limit=10 \
-d offset=20

次のように返ります(items の中は省いています)。

{ "items": [], "total": 42, "limit": 10, "offset": 20 }

total は、limit と offset で区切る前の、当てはまる全体の数です。全体のページ数は、total を limit で割って切り上げた数です。

全部のエントリーを順に取り出すときは、offset を limit ずつ増やし、total に届くまでくり返します。並びが変わらないように、order を決めておきます。

const base = "https://<ホスト名>.hakocms.net/api/v1/content/posts";
const headers = { Authorization: "Bearer <API キー>" };
const all = [];
for (let offset = 0; ; offset += 100) {
const params = new URLSearchParams({
order: "sys.createdAt",
limit: "100",
offset: String(offset),
});
const res = await fetch(`${base}?${params}`, { headers });
const { items, total } = await res.json();
all.push(...items);
if (items.length === 0 || all.length >= total) break;
}
console.log(all.length);

1 回の応答は 5 MB までです。超えると 400 が返ります。そのときは limit を小さくするか、select で返すフィールドを減らしてください(エントリーを取り出す)。

返った total が、管理画面で同じ条件のエントリーを数えた数と同じなら、絞り込めています。

式が読めないときや、そのフィールドに使えない演算子を書いたときは、400 が返り、message に理由が出ます。式の誤りは、何文字目かも出ます。

式 message
title like "x" where: expected an operator (=, !=, <, <=, >, >=, contains, startsWith, in, exists) at character 7, found "like"
nope = "x" where: unknown field "nope"
title < "a" where: lt (<) cannot be used with the text field "title"
price = "abc" where: "abc" is not a number ("price")
title = 1 where: 1 is not a string; put it in quotes ("title")