0Pricing
Linux Command Line & Bash Scripting Mastery · レッスン

curlとjqを組み合わせたREST APIの利用

curlのリクエストをjqにつなぎ、スクリプトでライブAPIレスポンスを抽出、ページング、再整形します。

「curlとjqを組み合わせたREST APIの利用」はCoddyKit上の無料Linux Command Line & Bash Scripting Masteryレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLinux Command Line & Bash Scripting Mastery学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Linux Command Line & Bash Scripting Masteryコースには全4レッスンが含まれています。

curl + jq が強力な組み合わせである理由

REST API は JSON を返します。curl は生のレスポンスを取得し、jq はそれを抽出、フィルタリング、組み替えします。すべてを 1 つのパイプラインで実行できるため、Python スクリプトも Postman も中間ファイルも必要ありません。

  • curl は HTTP を処理します。メソッド、ヘッダー、認証、リダイレクトなどです。
  • jq は JSON を処理します。フィルタリング、マッピング、変換、整形などです。
  • 両者をパイプでつなぐと、簡潔で組み合わせやすい API ワークフローを構築できます。

このレッスンでは、基本から始めて、実際のページネーションやスクリプトのパターンを通じてこのスキルを身につけます。

jq への基本的な curl パイプライン

最も単純なパターンは、curl の出力を直接 jq にパイプする方法です。-s(silent)を使うと curl の進捗メーターを抑制でき、JSON 本文だけが jq に渡されます。

  • -s — 進捗バーを表示しないサイレントモードです。
  • . — jq の identity フィルターです。レスポンス全体を整形して出力します。
  • jq の -r — raw 出力です(文字列を囲む引用符を付けません)。
#!/usr/bin/env bash
# Fetch a public endpoint and pretty-print the JSON
curl -s 'https://jsonplaceholder.typicode.com/todos/1' | jq '.'

# Extract just the title field as a plain string
curl -s 'https://jsonplaceholder.typicode.com/todos/1' | jq -r '.title'

リクエストヘッダーの設定と認証トークンの渡し方

多くの本番 API では、Authorization ヘッダーまたは API キーが必要です。-H でヘッダーを渡し、シークレットは環境変数に保存してください。コードに直接記述してはいけません。

  • -H 'Authorization: Bearer $TOKEN' — 認証ヘッダーを注入します。
  • -H 'Accept: application/json' — JSON を返すよう明示的に要求します。
  • 変数は二重引用符の中で展開されます。ヘッダー文字列は " で囲んでください。
#!/usr/bin/env bash
TOKEN="${GITHUB_TOKEN}"   # set in your shell environment
USER="octocat"

curl -s \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/vnd.github+json" \
  "https://api.github.com/users/${USER}" \
| jq '{login: .login, repos: .public_repos, followers: .followers}'

配列のフィルタリング — .[] と select()

API は配列を返すことがよくあります。.[] ですべての要素を反復処理し、続けて select() で条件に一致する項目だけを残します。

  • .[] — 配列をオブジェクトのストリームに展開します。
  • select(.field == value) — 一致するオブジェクトだけを残します。
  • | で複数のフィルターを連結できます。
#!/usr/bin/env bash
# Fetch all todos and keep only the completed ones
curl -s 'https://jsonplaceholder.typicode.com/todos' \
| jq '[.[] | select(.completed == true) | {id, title}]'

# Count how many are completed
curl -s 'https://jsonplaceholder.typicode.com/todos' \
| jq '[.[] | select(.completed == true)] | length'

map()で複数のフィールドを抽出する

map()は配列のすべての要素に変換を適用し、新しい配列を返します。[.[] | ...]と同等ですが、より読みやすい書き方です。

  • map({key: .field}) — すべてのオブジェクトの構造を変換します。
  • @csvまたは@tsvと組み合わせると、表形式の出力を生成できます。
  • @csv/@tsvでJSONの引用符を付けない生のテキストを取得するには、-rを使用します。
#!/usr/bin/env bash
# Reshape a posts list into id + title pairs
curl -s 'https://jsonplaceholder.typicode.com/posts' \
| jq 'map({id, title: .title[0:40]})'

# Output as CSV for import into a spreadsheet
curl -s 'https://jsonplaceholder.typicode.com/posts' \
| jq -r '.[] | [.id, .userId, .title] | @csv'

ページネーションのパターン — 空のページが返るまでループする

ほとんどのAPIでは、結果を複数のページに分けて返します。よく使われるパターンは、ページ番号を増やすwhileループを使い、返された配列が空になったら停止する方法です。

  • $(curl ...)を使って、curlのレスポンスを変数に格納します。
  • jq 'length'を使って、そのページに項目があるかどうかを確認します。
  • jq -s(slurp)で結果をまとめるか、ファイルに追記します。
#!/usr/bin/env bash
# Paginate through jsonplaceholder posts (simulated: page stops at page 2
# because the API returns the full list regardless of ?_page, but the
# pattern is correct for real paginated APIs)

PAGE=1
PER_PAGE=10
OUTPUT="all_posts.json"
echo '[]' > "$OUTPUT"

while true; do
  RESPONSE=$(curl -s "https://jsonplaceholder.typicode.com/posts?_page=${PAGE}&_limit=${PER_PAGE}")
  COUNT=$(echo "$RESPONSE" | jq 'length')

  if [ "$COUNT" -eq 0 ]; then
    echo "No more pages. Stopping at page $((PAGE - 1))."
    break
  fi

  # Merge new items into the accumulated JSON array
  CURRENT=$(cat "$OUTPUT")
  echo "$CURRENT" "$RESPONSE" | jq -s '.[0] + .[1]' > "$OUTPUT"
  echo "Page $PAGE: fetched $COUNT items."
  PAGE=$((PAGE + 1))
done

echo "Total collected: $(jq 'length' "$OUTPUT")"

Linkヘッダーによるページネーション(GitHub形式)

GitHubをはじめとする多くのAPIでは、次のページのURLをLinkレスポンスヘッダーで提供します。URLを推測するのではなく、ヘッダーを解析する必要があります。

  • curl -iを使うとレスポンスヘッダーが標準出力に含まれます。または-D -でヘッダーを標準出力に出力できます。
  • Link: <url>; rel="next"ヘッダーをgrepとsedで解析します。
  • rel="next"のリンクがなくなるまでループします。
#!/usr/bin/env bash
# Follow Link-header pagination (GitHub repos example)
# Requires GITHUB_TOKEN in environment
TOKEN="${GITHUB_TOKEN}"
NEXT_URL="https://api.github.com/users/torvalds/repos?per_page=5"
ALL_REPOS="[]"

while [ -n "$NEXT_URL" ]; do
  # Capture full response (headers + body) to a temp file
  TMPFILE=$(mktemp)
  curl -sD "$TMPFILE" \
    -H "Authorization: Bearer ${TOKEN}" \
    -H "Accept: application/vnd.github+json" \
    "$NEXT_URL" \
  | {
      BODY=$(cat)
      ALL_REPOS=$(echo "$ALL_REPOS" "$BODY" | jq -s '.[0] + .[1]')
      echo "$ALL_REPOS" > /tmp/repos_acc.json
    }

  # Extract next URL from Link header
  NEXT_URL=$(grep -i '^link:' "$TMPFILE" \
    | sed -E 's/.*<([^>]+)>; rel="next".*/\1/;t;d')
  rm -f "$TMPFILE"
done

echo "Total repos: $(jq 'length' /tmp/repos_acc.json)"

リクエストを連鎖させる — 1つの呼び出しの出力を別の呼び出しの入力に使う

よくあるワークフローは、一覧を取得し、IDを抽出してから、各IDの詳細を取得するというものです。中間値を$()のコマンド置換で保存し、次のURLに渡します。

  • jq -r '.field'で単一の値を抽出します。
  • while readループ内でjq -r '.[].id'を使い、複数のIDを処理します。
  • レート制限を守るため、リクエストの間にsleepを入れます。
#!/usr/bin/env bash
# Step 1: get all user IDs from the /users endpoint
# Step 2: for each user, fetch their posts and count them

curl -s 'https://jsonplaceholder.typicode.com/users' \
| jq -r '.[].id' \
| while read -r USER_ID; do
    POST_COUNT=$(curl -s "https://jsonplaceholder.typicode.com/posts?userId=${USER_ID}" \
                 | jq 'length')
    echo "User ${USER_ID}: ${POST_COUNT} posts"
    sleep 0.1   # be polite to the API
done

POSTリクエスト — JSONペイロードを送信する

リソースを作成または更新するには、JSONボディを付けてPOSTまたはPUTを送信します。-X POST、-H 'Content-Type: application/json'、そしてボディ用の-dを使用します。引用符に関する問題を避けるため、jq -nでペイロードを作成します。

  • jq -n --arg key value '{key: $key}' — jqで安全に変数を展開します。
  • 作成したJSONをcurlの-d @-(標準入力からボディを読み込む)に直接パイプします。
  • 別のjqフィルターでレスポンスをすぐに解析します。
#!/usr/bin/env bash
TITLE="My New Post"
BODY_TEXT="Written via curl and jq."
USER_ID=1

# Build the JSON payload safely and POST it
RESPONSE=$(jq -n \
  --arg title   "$TITLE" \
  --arg body    "$BODY_TEXT" \
  --argjson userId "$USER_ID" \
  '{title: $title, body: $body, userId: $userId}' \
| curl -s \
    -X POST \
    -H 'Content-Type: application/json' \
    -d @- \
    'https://jsonplaceholder.typicode.com/posts')

echo "Created post ID: $(echo "$RESPONSE" | jq '.id')"
echo "Full response:"
echo "$RESPONSE" | jq '.'

エラー処理 — HTTPステータスコードとAPIエラー

HTTP接続が成功しても、API呼び出しが成功したとは限りません。HTTPステータスコードとJSONのエラーフィールドを個別に確認してください。

  • curl -w '%{http_code}'はステータスコードを標準出力に追加します。-oを使うとボディをファイルに書き込めます。
  • スクリプト内でコードを比較し、4xxと5xxを異なる方法で処理します。
  • 多くのAPIはボディに{"error": "..."}を埋め込みます。jqのhas()またはtypeで確認します。
#!/usr/bin/env bash
API_URL='https://jsonplaceholder.typicode.com/todos/99999'
TMPBODY=$(mktemp)

HTTP_CODE=$(curl -s -o "$TMPBODY" -w '%{http_code}' "$API_URL")

if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
  echo "Success ($HTTP_CODE):"
  jq '.' "$TMPBODY"
elif [ "$HTTP_CODE" -eq 404 ]; then
  echo "Resource not found (404). Body:"
  jq '.' "$TMPBODY"
elif [ "$HTTP_CODE" -ge 500 ]; then
  echo "Server error ($HTTP_CODE). Retrying later."
else
  echo "Unexpected status: $HTTP_CODE"
  cat "$TMPBODY"
fi

rm -f "$TMPBODY"

再利用可能なAPIヘルパー関数を作成する

curlとエラーチェックの定型処理をシェル関数にまとめます。この関数が認証、ステータス確認、JSON抽出を処理するため、呼び出し側はエンドポイントとjqフィルターを渡すだけで済みます。

  • HTTPエラー時には0以外の終了コードを返し、呼び出し側で||やset -eを使えるようにします。
  • jqフィルターを引数として受け取り、同じ関数を多くのエンドポイントで使えるようにします。
  • APIを必要とする任意のスクリプトから、この関数ファイルをsourceします。
#!/usr/bin/env bash
# api_get <endpoint_path> <jq_filter>
# Returns filtered JSON or exits non-zero on error.
api_get() {
  local PATH_PART="$1"
  local JQ_FILTER="${2:-.}"
  local BASE_URL='https://jsonplaceholder.typicode.com'
  local TMPBODY
  TMPBODY=$(mktemp)

  local HTTP_CODE
  HTTP_CODE=$(curl -s \
    -o "$TMPBODY" \
    -w '%{http_code}' \
    "${BASE_URL}${PATH_PART}")

  if [ "$HTTP_CODE" -lt 200 ] || [ "$HTTP_CODE" -ge 300 ]; then
    echo "[ERROR] HTTP $HTTP_CODE for ${PATH_PART}" >&2
    rm -f "$TMPBODY"
    return 1
  fi

  jq -r "$JQ_FILTER" "$TMPBODY"
  rm -f "$TMPBODY"
}

# Usage examples
api_get '/todos/1' '.title'
api_get '/posts?userId=1' '[.[] | .title]'
api_get '/users' '.[] | "\(.id) \(.name) <\(.email)>"'

理解度チェック:ページネーション戦略

curlとjqを使って、Bashスクリプトでページ分割されたREST APIのレスポンスを処理する方法を理解しているか確認しましょう。

レッスンのまとめ:curl + jqによるAPIスクリプト作成

BashのコマンドラインからREST APIを利用するための、ひととおりのツールキットが身につきました。

  • 基本的なパイプライン:curl -s URL | jq 'filter' — すべての基盤となる方法です。
  • 認証ヘッダー:トークンは環境変数から-Hで渡し、ハードコードしないようにします。
  • 配列の処理:.[]、select()、map()でAPIレスポンスを抽出・変形します。
  • ページネーション:ページ番号(空配列を終了の目印にする)でループするか、次のURLを示すAPIのLinkヘッダーを解析します。
  • 連鎖:1つのレスポンスからIDを抽出し、while readループ内で次のリクエストに渡します。
  • 安全なペイロードでPOST:jq -n --argでJSONボディを作成し、curlの-d @-にパイプします。
  • エラー処理:HTTPステータス(-w '%{http_code}')と、ボディ内のAPIレベルのエラーを分けて処理します。
  • 再利用可能なヘルパー:定型処理をシェル関数にまとめ、スクリプトを簡潔かつDRYに保ちます。

これらのパターンを組み合わせれば、追加のランタイムなしに、あらゆるJSON APIのワークフローをシェルだけで自動化できます。

よくある質問

「curlとjqを組み合わせたREST APIの利用」レッスンは無料ですか?

はい。「curlとjqを組み合わせたREST APIの利用」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Linux Command Line & Bash Scripting Masteryコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Linux Command Line & Bash Scripting Masteryコースには全4レッスンが含まれています。

「curlとjqを組み合わせたREST APIの利用」で何を学びますか?

curlのリクエストをjqにつなぎ、スクリプトでライブAPIレスポンスを抽出、ページング、再整形します。 ブラウザで直接実行するハンズオンコードでLinux Command Line & Bash Scripting Masteryを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Linux Command Line & Bash Scripting Masteryを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのLinux Command Line & Bash Scripting Masteryは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「curlとjqを組み合わせたREST APIの利用」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このLinux Command Line & Bash Scripting Masteryレッスンでコードを書いて実行できますか?

はい。すべてのLinux Command Line & Bash Scripting Masteryレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. jqパイプラインによるJSONのフィルタリングと選択
  2. jqによるJSONオブジェクトの変換と構築
  3. curlとjqを組み合わせたREST APIの利用
  4. yqによるYAML設定ファイルの編集
← Linux Command Line & Bash Scripting Masteryに戻る