🐈

curl でステータスコードとBodyを一緒に返す

2023/02/06に公開

curl コマンドで WebAPI を呼び出すときにリクエストの Body だけでなくステータスコード(201, 403 など)も利用したいことがある。そのような時は、 curl コマンド実行時に -w "\n%{response_code}" を付けて、 HTTP リクエストのステータスコードをコマンドの出力に追加する。

参考: https://everything.curl.dev/usingcurl/verbose/writeout

これを後で分割することでレスポンスの Body とステータスコードを両方利用できる。

サンプル:

RESULT=$(curl --url "https://goweather.herokuapp.com/weather/Sapporo" -w "\n%{response_code}")

RESULT_BODY=$(echo "${RESULT}" | sed "$ d")
RESULT_STATUS=$(echo "${RESULT}" | tail -n 1)

echo "Status: ${RESULT_STATUS}"
echo "Body: ${RESULT_BODY}"

実行結果:

Status: 200
Body: {"temperature":"-3 °C","wind":"4 km/h","description":"Light snow shower","forecast":[{"day":"1","temperature":"-4 °C","wind":"21 km/h"},{"day":"2","temperature":"-7 °C","wind":"7 km/h"},{"day":"3","temperature":"-4 °C","wind":"2 km/h"}]}

Bash では、 WebAPI を呼び出してリクエストの Body とステータスコードの両方を返す関数を以下のように定義できる。

ACCESS_TOKEN=XXXXXXXXXX

# WebAPI を呼び出し、その結果のステータスコードと Body を返す。
# @param $1: メソッド名(GET, POST, ...)
# @param $2: API パス(e.g., /users/<user_id>)
# @param $3: 結果を受け取るための変数名。ここで指定した名前の末尾に _BODY と _STATUS を付けた変数が作成される。
# @param $4: [optional] POST や PATCH のリクエスト時に送るデータ
function invoke_web_api {
  local API_METHOD=$1
  local API_PATH=$2
  local VARIABLE_PREFIX=$3

  local COMMAND="curl \
    --header \"Content-Type: application/json\" \
    --header \"Authorization: Bearer ${ACCESS_TOKEN}\" \
    --request ${API_METHOD} \"https://example.com/v1${API_PATH}\" \
    "

  if [ $# -eq 4 ]; then
    local DATA_PARAM=$(echo $4 | sed -e s/\\\"/\\\\\"/g)
    COMMAND="${COMMAND} --data \"${DATA_PARAM}\""
  fi

  COMMAND="${COMMAND} -w \"\\n%{response_code}\""

  local RESULT=$(eval "${COMMAND}")

  if [ $? -ne 0 ]; then
    echo "Failed to invoke."
    exit 1
  fi

  local RESULT_BODY=$(echo "${RESULT}" | sed "$ d")
  local RESULT_STATUS=$(echo "${RESULT}" | tail -n 1)

  printf -v "${VARIABLE_PREFIX}_BODY" "%s" "${RESULT_BODY}"
  printf -v "${VARIABLE_PREFIX}_STATUS" "%s" "${RESULT_STATUS}"
}

# ユーザーの一覧を取得
invoke_web_api GET "/users" GET_USERS

echo "GET_USERS_STATUS: ${GET_USERS_STATUS}"
echo "GET_USERS_BODY: ${GET_USERS_BODY}"

# 新しいユーザーを追加
invoke_web_api POST "/users" CREATE_USER \
  "{ \"name\": \"John Lennon\", \"age\": 30 }"

echo "CREATE_USER_STATUS: ${CREATE_USER_STATUS}"
echo "CREATE_USER_BODY: ${CREATE_USER_BODY}"

Bash の printf コマンドは printf -v "変数名" のようにして指定した名前の変数を定義できるため、上の関数でその機能を利用している。

Discussion