PowerShellでcurlを使う:REST APIのGET・JSON POSTとエラーの確認
作成日:2026.11.03
WindowsのPowerShellからcurlでREST APIを試す方法を紹介します。GETのクエリ指定、JSONファイルのPOST、Bearer認証ヘッダーの付け方に加え、レスポンスの保存やHTTPステータス・終了コードによるエラーの切り分けを解説します。
目次
REST APIを使うとき、いきなりアプリケーションへ組み込むより、まずはリクエストだけを送って確認したいことがあります。URLや送信データが違うのか、PHPなどの実装に問題があるのかを分けて調べたいときにも便利です。
今回は、WindowsのPowerShellからコマンドライン版curlを使い、GETとJSON POSTを試してみます。レスポンスの本文だけでなく、HTTPステータスとcurlの終了コードも確認します。
PowerShellから使うcurlを確認する
curlは、URLを指定してデータを送受信するコマンドラインツールです。PHPのcURL拡張とは別に実行するプログラムなので、PHPのコードを書かずにHTTPリクエストを送れます。
PowerShellでは、コマンドの別名と外部プログラムを区別します。例えばWindows PowerShell 5.1では、curlがInvoke-WebRequestの別名になっています。この記事では、外部プログラムを呼び出すことが分かるようにcurl.exeと書きます。
$PSVersionTable.PSVersion
Get-Command curl -All
Get-Command curl.exe
curl.exe --version
今回確認した環境は、WindowsのOSビルド10.0.26300、PowerShell 7.6.9、curl 8.21.0です。curlのTLSバックエンドはSchannelでした。
以下で使う--jsonはcurl 7.82.0以降のオプションです。古いcurlでは使えないため、手元のバージョンも確認してください。
GETでAPIへリクエストを送る
ここからは、商品を扱う説明用APIを例にします。以下のサンプルコード内のhttps://api.example.comは実行可能なサンプルAPIではありません。接続先、パス、パラメーターは、利用するAPIの仕様へ置き換えてください。
POSTはデータを登録する場合があるので、まずは自分で操作してよいテスト環境を使いましょう。後ほどファイルも保存するため、空の作業用フォルダーで試してください。
$baseUrl = 'https://api.example.com'
例えば、商品の一覧を取得するGET /productsなら、次の形です。
curl.exe --silent --show-error --connect-timeout 5 --max-time 15 "$baseUrl/products"
データ送信用のオプションなどを付けなければ、HTTPでは基本的にGETになります。返された本文は画面へ出力されますが、curlが自動でJSONを整形するわけではありません。
| 指定 | 意味 |
|---|---|
--silent | 進捗やエラーメッセージなどの表示を抑える。本文は出力する |
--show-error | --silentを使っていてもエラーメッセージを表示する |
--connect-timeout 5 | 接続を確立するまでの時間を最大5秒にする |
--max-time 15 | 今回の転送全体を最大15秒にする |
進捗だけ消したつもりでエラーまで見えなくならないよう、ここでは--silentと--show-errorをセットで指定しています。
クエリパラメーターとヘッダーを付ける
検索語や件数を指定する例です。--getと--data-urlencodeを組み合わせると、値をURLエンコードしてクエリへ追加できます。
curl.exe --silent --show-error `
--connect-timeout 5 --max-time 15 `
--get `
--data-urlencode 'q=入門 PHP' `
--data-urlencode 'limit=2' `
--header 'Accept: application/json' `
"$baseUrl/products"
この例では、qに「入門 PHP」、limitに「2」を渡します。--getを外すと、このデータ指定はPOSTになるので注意してください。Acceptは、レスポンスとしてJSONを受け取りたいという指定です。実際の応答はAPIの仕様によります。
PowerShellでコマンドを複数行に分けるときは、上の例のように行末へバッククォート`を置けます。バッククォートの後ろに空白を入れると、行の継続になりません。実行できないときは、いったん1行に戻してみると切り分けやすいです。
本文・ヘッダー・HTTPステータスを分けて確認する
本文だけでは、成功したのか、APIのエラーメッセージなのか判断しにくい場合があります。本文とレスポンスヘッダーを別ファイルへ保存し、画面にはHTTPステータスを表示してみます。
curl.exe --silent --show-error `
--connect-timeout 5 --max-time 15 `
--dump-header '.\response-headers.txt' `
--output '.\response.json' `
--write-out 'HTTP=%{http_code}\n' `
"$baseUrl/products"
$curlExitCode = $LASTEXITCODE
"curl exit=$curlExitCode"
--dump-headerは受信ヘッダー、--outputは本文の保存先です。--write-outは転送後に情報を出力する指定で、%{http_code}がHTTPステータス、\nが改行になります。
$LASTEXITCODEには最後に実行した外部プログラムの終了コードが入ります。別のプログラムを動かす前に、curlの実行直後で保存します。
Get-Content -LiteralPath '.\response-headers.txt'
Get-Content -LiteralPath '.\response.json' -Raw -Encoding utf8
ここではJSONの応答を想定したファイル名にしていますが、保存しただけでは内容がJSONかどうかは検証されません。通信に失敗した場合は、保存ファイルが今回の完全な応答とは限らないので、先に終了コードを確認してください。同名の保存ファイルは上書きされます。
JSONファイルをPOSTする
JSONをコマンドへ直接書くと、JSONのダブルクォートとシェルの引用符が重なります。まずはファイルへ保存して送る方が、送信内容を確認しやすいかと思います。
例えば、nameとpriceを受け取るAPIなら、次のようにJSONを作れます。PowerShell 7系で、BOMなしのUTF-8として保存します。
$requestBody = @{
name = 'テスト商品'
price = 1200
}
$requestBody | ConvertTo-Json | Set-Content -LiteralPath '.\request.json' -Encoding utf8NoBOM
このファイルを、商品登録のPOST /productsへ送ります。
curl.exe --silent --show-error `
--connect-timeout 5 --max-time 15 `
--json '@request.json' `
--output '.\post-response.json' `
--write-out 'HTTP=%{http_code}\n' `
"$baseUrl/products"
$curlExitCode = $LASTEXITCODE
"curl exit=$curlExitCode"
Get-Content -LiteralPath '.\post-response.json' -Raw -Encoding utf8
@request.jsonの@は、curlへファイルから読み込むよう指示する記号です。PowerShell側の解釈と混ざらないよう、引数全体を引用符で囲んでいます。空白を含むパスでも、'@.\request files\request.json'のように全体を囲みます。
--jsonは、ファイルなどのデータをPOSTし、Content-Type: application/jsonとAccept: application/jsonを指定するためのオプションです。この例では-X POSTを追加する必要はありません。ただし、JSON構文の検証は行わないので、ファイルを手で編集した場合などは内容も確認してください。
Content-Typeは送る本文の形式、Acceptは受け取りたい形式です。名前は似た場面で登場しますが、役割は別です。
Bearerトークンを付ける場合
Bearer認証を使うAPIでは、Authorizationヘッダーを追加します。次の例は、利用するAPIのテスト用トークンが環境変数API_TOKENへ設定されている前提です。
if ([string]::IsNullOrWhiteSpace($env:API_TOKEN)) {
throw 'API_TOKENが設定されていません。'
}
curl.exe --silent --show-error `
--connect-timeout 5 --max-time 15 `
--header "Authorization: Bearer $env:API_TOKEN" `
--json '@request.json' `
"$baseUrl/products"
実トークンをコマンドへ直接書くと、履歴に残る可能性があります。ただ、環境変数を使っても、展開された値がプロセスの引数へ渡る点は変わりません。共有端末での扱いや、詳細ログ・画面・レスポンスを共有するときの漏えいにも注意してください。今回の検証ではダミー文字列だけを送っています。
HTTPエラーとcurlの失敗を分ける
HTTP 404や500が返っても、通常のcurlは終了コード0になることがあります。サーバーから応答を受け取れたことと、APIの処理が成功したことは別だからです。
HTTP 400以上をcurlの失敗としても扱い、エラー本文を残したい場合は、--fail-with-bodyを付けます。例えば、存在しない商品へアクセスして404を返すAPIなら、次のように確認できます。
curl.exe --silent --show-error `
--connect-timeout 5 --max-time 15 `
--fail-with-body `
--output '.\error-response.json' `
--write-out 'HTTP=%{http_code}\n' `
"$baseUrl/products/999999"
$curlExitCode = $LASTEXITCODE
"curl exit=$curlExitCode"
ローカルのテスト用APIで404を返した場合、画面にはHTTPステータス404と終了コード22が表示され、本文はerror-response.jsonへ保存されました。curlのエラーメッセージは標準エラーへ出ます。
--failでもHTTPエラーを失敗扱いにできますが、エラー本文の出力は抑えられます。APIが返した理由を調べたい場合は、本文を残す--fail-with-bodyが便利です。こちらはcurl 7.76.0以降で使えます。
| ローカルで確認した条件 | HTTPステータス | curlの終了コード |
|---|---|---|
| 通常のGET | 200 | 0 |
| JSON POST | 201 | 0 |
HTTPエラー、--fail-with-bodyなし | 400/404/500 | 0 |
同じHTTPエラー、--fail-with-bodyあり | 400/404/500 | 22 |
| 応答前にタイムアウト | 000 | 28 |
| 待ち受けのないローカルポートへ接続 | 000 | 7 |
表の000はサーバーが返したHTTPステータスではなく、HTTP応答コードを取得できなかった場合の表示です。また、curlの終了コード0でも、API独自の成功条件は本文や仕様を見て判断します。
タイムアウトも同じように、実行直後の終了コードで確認できます。
curl.exe --silent --show-error `
--connect-timeout 1 --max-time 1 `
--output '.\timeout-response.txt' `
--write-out 'HTTP=%{http_code}\n' `
"$baseUrl/products"
$curlExitCode = $LASTEXITCODE
"curl exit=$curlExitCode"
このコマンドが必ずタイムアウトするわけではありません。検証では、ローカルサーバーが応答を返す前に2秒待つようにして、終了コード28を確認しました。特にPOSTのタイムアウトでは、サーバー側の登録処理は完了している場合もあるので、結果を確認せず繰り返し送らないようにしましょう。
接続できない場合は、URL、ネットワーク、プロキシ、証明書などをエラーメッセージから切り分けます。HTTPSの証明書エラーを消すために--insecure(-k)を付けるのは避け、原因を確認します。
なお、CLI版curlで成功しても、PHPのcURLが同じTLSバックエンドやCAを使っているとは限りません。PHP側の証明書エラーは、証明書検証とCAバンドルの設定を扱う記事も参考にしてください。
補足:Bashの例をPowerShellへ持ってくるとき
Bashで同じJSONファイルを送るなら、例えば次の形です。これはBash用の記法で、今回の実行検証の対象はPowerShell側です。
curl --silent --show-error \
--connect-timeout 5 --max-time 15 \
--json '@request.json' \
'https://api.example.com/products'
Bashの行末の\を、そのままPowerShellの行継続には使えません。PowerShellではバッククォートを使うか、コマンドを1行にまとめます。変数の書き方や引用符の扱いも同一ではないため、Web上の例は「どのシェルで実行するものか」を確認しましょう。
今回のPowerShellの例は、URLをローカルのテスト用APIへ差し替えて確認しました。日本語を含むクエリ、JSONの内容、ヘッダーの受信と、表にあるHTTPエラー・タイムアウトを検証しています。実サービスの認証、HTTPS接続、プロキシ環境での動作は今回の検証には含めていません。
まずはGETで疎通を確認し、送信内容を増やしていくと、APIとのやり取りを追いやすくなります。リクエスト単体で確認できたら、PHPのcURLによる外部API連携など、アプリケーション側の実装へ進めばOKです。
参考資料
奈良市を拠点に、27年以上の経験を持つフリーランスWebエンジニア、阿部辰也です。
これまで、ECサイトのバックエンド開発や業務効率化システム、公共施設の予約システムなど、多彩なプロジェクトを手がけ、企業様や制作会社様のパートナーとして信頼を築いてまいりました。
【制作会社・企業様向けサポート】
Webシステムの開発やサイト改善でお困りの際は、どうぞお気軽にご相談ください。小さな疑問から大規模プロジェクトまで、最適なご提案を心を込めてさせていただきます。
ぜひ、プロフィールやWeb制作会社様向け業務案内、一般企業様向け業務案内もご覧くださいね。
php -rの使い方:PowerShellでPHPを手軽に試す
2026.11.04
PHPファイルを作らずにコードを実行できる「php -r」の基本的な使い方を紹介します。PowerShellで変数や関数を試す例と、引用符による変数展開でエラーになる原因・対処法を説明し、Bashとの違いやPHPファイルへ切り出す目安も補足します。
PHP cURLの証明書エラー:VERIFYPEERを無効にする危険性とCAバンドルの設定方法
2026.11.02
PHPのcURLで「unable to get local issuer certificate」が出たとき、CURLOPT_SSL_VERIFYPEERをfalseにする対処が危険な理由を解説します。証明書の信頼性検証とホスト名照合の違いを整理し、WindowsでのCAバンドルの取得、curl.cainfoの設定、反映確認までを紹介します。
PowerShellコマンド入門:cmd.exe・Unix系コマンドとの対応と基本の使い方
2026.10.27
cmd.exe(DOSコマンド)やUnix系コマンドに慣れた人向けに、PowerShellの基本操作を対応表付きで解説します。cd・dir・grep・tailなどに相当する操作から、別名と外部コマンドの違い、圧縮・展開、オブジェクトを扱うパイプラインまで、具体例で紹介します。
PowerShell 7.6.6が起動しない:totalWidthエラーの原因と対処法
2026.10.21
PowerShell 7.6.6が起動直後にtotalWidthエラーで終了する問題について、更新通知を無効にして復旧した手順を紹介します。多言語メッセージの整形処理にある不具合と、更新・通知を戻す際の注意点も説明します。