curlとjqを用いたREST API自動検証の堅牢化:エラーハンドリングと再試行戦略

Tech

{ “system_role”: “SRE / DevOps Engineer”, “technical_stack”: [“curl”, “jq”, “Bash”, “systemd”], “objective”: “Design a robust API validation workflow with error handling.”, “style”: “Professional, Tactical, Practical” }

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

curlとjqを用いたREST API自動検証の堅牢化:エラーハンドリングと再試行戦略

【導入と前提】

curlで取得したJSONをjqでパースし、再試行と異常検知を組み込んだ堅牢なAPI自動検証の仕組みを構築します。

  • OS: GNU/Linux (Ubuntu 22.04 LTS / RHEL 9 等)

  • ツール: curl (7.64+), jq (1.6+), bash (4.0+)

【処理フローと設計】

graph TD
A["開始"] --> B{"curl実行"}
B -->|失敗/タイムアウト| C["再試行ロジック"]
C -->|上限到達| D["エラー終了/通知"]
B -->|成功| E["HTTPステータス確認"]
E -->|200以外| D
E -->|200 OK| F["jqによるスキーマ/値検証"]
F -->|不正データ| D
F -->|正常データ| G["成功処理/クリーンアップ"]
G --> H["終了"]
  1. 取得フェーズ: curl の組み込みリトライ機能とタイムアウト設定を活用し、一時的なネットワーク断に対応。

  2. 検証フェーズ: jq の終了コード (-e) を利用し、特定のフィールドの存在や期待される値を厳密にチェック。

  3. 終了フェーズ: 一時ファイルの確実な削除と、標準エラー出力へのログ集約。

【実装:堅牢な自動化スクリプト】

#!/usr/bin/env bash

# set -e: エラー発生時に即座に終了


# set -u: 未定義変数の参照時にエラー


# set -o pipefail: パイプライン途中のエラーも検知

set -euo pipefail

# ---------------------------------------------------------


# 設定・変数定義


# ---------------------------------------------------------

readonly API_URL="https://api.example.com/v1/health"
readonly EXPECTED_VERSION="1.2.0"
readonly TEMP_FILE=$(mktemp /tmp/api_res.XXXXXX.json)

# 終了時に必ず一時ファイルを削除

trap 'rm -f "${TEMP_FILE}"' EXIT

echo "[INFO] API検証開始: ${API_URL}"

# ---------------------------------------------------------


# 1. APIリクエスト実行 (curl)


# ---------------------------------------------------------


# -s: 進捗表示非表示


# -S: エラー時はメッセージ出力


# -L: リダイレクト追従


# --retry: 通信失敗時の再試行回数


# --retry-delay: 再試行の間隔(秒)


# --max-time: 全体のタイムアウト(秒)


# -w: レスポンスコードのみを変数に格納

HTTP_STATUS=$(curl -sSL \
    --retry 3 \
    --retry-delay 2 \
    --max-time 10 \
    -o "${TEMP_FILE}" \
    -w "%{http_code}" \
    "${API_URL}")

# ステータスコードが200かチェック

if [ "$HTTP_STATUS" -ne 200 ]; then
    echo "[ERROR] APIリクエスト失敗 ステータスコード: ${HTTP_STATUS}" >&2
    exit 1
fi

# ---------------------------------------------------------


# 2. JSON構造・値の検証 (jq)


# ---------------------------------------------------------


# -e: 抽出結果が null または false の場合に終了コード 1 を返す


# .status == "ok" かつ .version が期待値か確認

if ! jq -e ".status == \"ok\" and .version == \"${EXPECTED_VERSION}\"" "${TEMP_FILE}" > /dev/null; then
    echo "[ERROR] レスポンス内容が不正です" >&2
    echo "内容: $(cat "${TEMP_FILE}")" >&2
    exit 1
fi

echo "[SUCCESS] API検証正常終了 (Version: ${EXPECTED_VERSION})"

補足:systemdによる定期実行の構成例

API監視をデーモン化または定期実行する場合、以下のユニットファイルを /etc/systemd/system/api-check.service として配置します。

[Unit]
Description=API Health Checker
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/api-check.sh
User=monitoring-user

# 環境変数の漏洩を防ぐため、認証情報はファイルから読み込む

EnvironmentFile=-/etc/default/api-check

[Install]
WantedBy=multi-user.target

【検証と運用】

正常系の確認

スクリプトを実行し、終了コードを確認します。

bash api-check.sh
echo $?  # 0 であれば成功

エラー時の確認

systemd 経由で実行している場合、journalctl を使用して原因を特定します。

# 失敗した直近のログを確認

journalctl -u api-check.service -n 50 --no-pager

【トラブルシューティングと落とし穴】

  • 権限問題: mktemp で作成するディレクトリに実行ユーザーの書込権限があるか確認してください。sudo で実行する場合は trap による削除が適切に行われるよう注意が必要です。

  • 環境変数の漏洩: APIキーなどの機密情報はスクリプト内にハードコードせず、EnvironmentFileexport 済みの変数から読み込み、set -x(デバッグ実行)を使用する際は機密情報が出力されないよう保護してください。

  • jqの互換性: 古いディストリビューション(CentOS 7等)では jq 1.5 が使われている場合があり、一部の関数(any, all等)の挙動が異なる可能性があります。

【まとめ】

運用の冪等性と堅牢性を維持するためのポイント:

  1. 異常終了の早期化: set -euo pipefail により、予期せぬ挙動を未然に防ぐ。

  2. 再試行の標準化: curl 自体のリトライ機能を使い、シェル側で複雑なループを書かない。

  3. 状態の局所化: trapmktemp を活用し、実行環境にゴミ(一時ファイル)を残さない。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

タイトルとURLをコピーしました