curlでHTTP PUTメソッドを実行する方法:詳細解説
はじめに:HTTPメソッドとPUTの役割
インターネット上のリソースと対話するための主要な手段であるHTTP(Hypertext Transfer Protocol)には、様々な「メソッド」が定義されています。これらのメソッドは、クライアント(ウェブブラウザやcurlなどのツール)がサーバーに対して行いたいアクションを示します。最もよく知られているのは、ウェブページを取得するためのGETメソッドや、フォームデータを送信するためのPOSTメソッドでしょう。
しかし、HTTPメソッドはこれだけではありません。PUTメソッドもその一つであり、特定のURI(Uniform Resource Identifier)で識別されるリソースを、リクエストボディに含まれるデータで作成または完全に置き換えるために使用されます。PUTメソッドは、既存のリソースを更新する際や、特定のURIに新しいリソースを作成する際に非常に役立ちます。その最大の特徴は「冪等性(Idempotence)」です。これは、同じPUTリクエストを複数回実行しても、一度だけ実行した場合と同じ最終的な状態になる、という性質を指します。これは、リクエストを繰り返すとリソースが複数回作成される可能性があるPOSTメソッドとは対照的です。
一方、curl
は、様々なプロトコル(HTTP, HTTPS, FTP, SFTPなど)を使ってデータを転送するための強力なコマンドラインツールです。開発者やシステム管理者がAPIのテスト、サーバーとの連携、デバッグなどを行う際に広く利用されています。HTTPリクエストの送信に関しては、GETやPOSTはもちろんのこと、PUT、DELETE、HEADなど、あらゆるHTTPメソッドを柔軟に実行することができます。
この記事では、この強力なツールであるcurl
を使って、HTTPのPUTメソッドをどのように実行するのかを、その基本的な方法から応用、そして関連する重要な概念まで、詳細かつ網羅的に解説します。約5000語という分量で、PUTメソッドの仕様、curlの関連オプション、具体的な使用例、そしてレスポンスの解釈に至るまで、深く掘り下げていきます。この記事を読めば、あなたは自信を持ってcurlでPUTリクエストを扱い、APIやサーバーとの連携をスムーズに進めることができるようになるでしょう。
PUTメソッドの基本を理解する
curlを使ってPUTメソッドを実行する前に、まずはPUTメソッドそのものについてもう少し深く理解しておくことが重要です。
PUTメソッドの定義と仕様
HTTP/1.1の仕様を定義するRFC 7231では、PUTメソッドについて以下のように述べられています(要約):
PUTメソッドは、リクエストペイロード(ボディ)に含まれる現在の状態を、リクエストURIによって識別されるターゲットリソースの格納された状態に置き換えるように要求します。
もしリクエストURIが既存のリソースを指している場合、サーバーは格納されているリソースの状態をペイロードの状態に置き換えるべきです。もしターゲットURIが既存のリソースを指していない場合、ユーザーエージェント(クライアント)がそのURIを定義し、サーバーがそのURIで新しいリソースを作成できる場合、サーバーは新しいリソースを作成し、ペイロードに含まれる状態をそのリソースの初期状態として格納すべきです。
この定義から、PUTメソッドの核となる機能が以下の2点であることがわかります。
- 既存リソースの完全な置き換え: 指定されたURIのリソースが存在する場合、そのリソースの内容全体をリクエストボディの内容で上書きします。
- 新しいリソースの作成: 指定されたURIのリソースが存在しない場合、サーバーが許可していれば、そのURIに新しいリソースを作成し、リクエストボディの内容を初期状態として格納します。
PUTとPOSTの違い:冪等性とURI指定
PUTとよく比較されるのがPOSTメソッドです。どちらもリクエストボディにデータを含めてサーバーに送信することができますが、その目的と性質は大きく異なります。
- POST: 指定されたリソース(典型的にはURIで示される親リソースやエンドポイント)に対して、リクエストボディのデータを「追加」または「処理」することを要求します。例えば、ブログ記事を新しく投稿したり、注文を送信したりする場合に使われます。POSTは冪等ではありません。同じPOSTリクエストを複数回送信すると、通常は同じアクションが複数回繰り返され、複数のリソースが作成されたり、同じ注文が複数回処理されたりする可能性があります。また、POSTでは新しいリソースのURIは通常サーバーが決定し、レスポンスの
Location
ヘッダーなどでクライアントに通知されます。 - PUT: 指定されたURIのリソースを、リクエストボディのデータで「完全に置き換え」または「作成」することを要求します。例えば、特定のIDを持つユーザーのプロフィール情報を更新したり、特定のパスに設定ファイルをアップロードしたりする場合に使われます。PUTは冪等です。同じPUTリクエストを複数回送信しても、サーバー上のリソースの状態は一度実行した場合と同じ最終状態になります(最初の実行でリソースが作成/更新され、以降の実行は同じ状態への更新を試みるだけになるため)。また、PUTではクライアントが作成/更新したいリソースのURIを事前に指定します。
PUTメソッドは、リソースがIDなどで明確に特定されており、その内容全体をクライアント側が提供するデータで上書きしたい場合に適しています。一方、POSTは、データの追加やサーバー側での複雑な処理をトリガーしたい場合に適しています。
PUTの一般的なユースケース
PUTメソッドは、以下のようなシナリオでよく使用されます。
- ファイルアップロード: 特定のディレクトリパス(URIに対応)にファイルをアップロードし、そのパスに既にファイルがあれば上書き、なければ新規作成する場合。
- リソースの更新: APIで、特定のID(URIの一部)を持つユーザー、製品、設定などのリソースのすべてのプロパティを、新しいデータで完全に置き換える場合。
- 設定の適用: 特定のURIで表現されるアプリケーションやサービスの構成設定を、新しい設定ファイルの内容で更新する場合。
PUTリクエストをサーバーがどのように処理するかは、サーバーの実装に依存します。サーバーはPUTリクエストを受け付けず、405 Method Not Allowedエラーを返すかもしれません。また、PUTで新しいリソースの作成を許可しないように設定されている場合もあります。APIドキュメントなどで、対象のURIがPUTをサポートしているか、また新規作成と更新のどちらの挙動をするかを確認することが重要です。
PUTリクエストの構造
HTTP PUTリクエストは、以下の主要な要素で構成されます。
- メソッド:
PUT
- リクエストURI: 対象となるリソースを特定するURI。例:
/users/123
,/files/document.txt
,/config/app.json
- ヘッダー: リクエストに関する追加情報を提供します。重要なヘッダーには以下のようなものがあります。
Host
: 対象サーバーのホスト名。Content-Type
: リクエストボディのデータのメディアタイプ(MIMEタイプ)を示します。例:application/json
,text/plain
,image/jpeg
。これはPUTリクエストでは特に重要です。Content-Length
: リクエストボディのバイト数。通常、curlが自動で計算して設定します。Authorization
: 認証情報(APIキー、トークン、Basic認証など)。If-Match
,If-Unmodified-Since
: 条件付き更新に使用されるヘッダー。競合を避けるためなどに使われます。
- リクエストボディ(ペイロード): PUTメソッドでは、対象リソースを置き換える、あるいは作成する際に使用されるデータ本体がここに格納されます。このボディの形式は
Content-Type
ヘッダーで指定されます。
curlコマンドの基本
curlでPUTリクエストを実行する前に、curlの基本的な使い方を理解しておきましょう。
curlのインストール
curlは多くのOSにプリインストールされていますが、ない場合は簡単にインストールできます。
- Linux (Debian/Ubuntu):
sudo apt update && sudo apt install curl
- Linux (Fedora/CentOS):
sudo dnf install curl
またはsudo yum install curl
- macOS:
brew install curl
(Homebrewを使用) またはプリインストールされている場合が多い。 - Windows: curl公式サイトからダウンロードするか、Windows 10/11ではコマンドプロンプトまたはPowerShellで利用可能。
インストール後、ターミナルでcurl --version
を実行し、バージョン情報が表示されれば準備完了です。
基本的なcurlコマンドの構文
curlコマンドの一般的な構文は以下のようになります。
bash
curl [オプション] [URL]
[オプション]
: HTTPメソッドの指定、ヘッダーの追加、データ送信方法の指定など、様々な動作を制御するためのオプションを指定します。オプションは単一のハイフン(-
)に続く一文字のショートオプション(例:-X
)または、二重ハイフン(--
)に続く単語のロングオプション(例:--request
)があります。[URL]
: リクエストのターゲットとなるURIを指定します。
HTTPメソッドを指定する方法 (-X
/ --request
)
curlはデフォルトではGETメソッドを使用します。PUTやPOSTなど、GET以外のメソッドを使用したい場合は、-X
または--request
オプションで明示的に指定する必要があります。
“`bash
curl -X PUT [URL]
または
curl –request PUT [URL]
“`
このオプションを省略すると、curlはGETリクエストを試みますが、通常PUTにはリクエストボディが含まれるため、サーバー側で適切に処理されないか、エラーになるでしょう。必ず-X PUT
を指定してください。
curlでPUTリクエストを送信する
いよいよcurlを使ってPUTリクエストを送信する具体的な方法を見ていきましょう。PUTリクエストでは、リクエストボディにデータを含めることがほとんどです。curlでリクエストボディを指定する方法はいくつかあります。
リクエストボディを指定する方法
PUTリクエストのボディを指定する主な方法は以下の通りです。
-d
または--data
オプション-T
または--upload-file
オプション
どちらの方法を使うかは、送信したいデータの性質や、それがファイルとして既に存在するかどうかによります。
1. -d
または --data
オプションの使用
-d
オプションは、POSTリクエストでよく使われますが、PUTリクエストでもリクエストボディのデータを指定するために使用できます。このオプションを使うと、curlはデフォルトでContent-Type: application/x-www-form-urlencoded
ヘッダーを自動的に追加しようとしますが、これは通常PUTリクエストでは望ましくありません。PUTでJSONやXML、プレーンテキストなどを送信する場合は、必ず別途-H "Content-Type: ..."
オプションで適切なメディアタイプを指定する必要があります。
-d
オプションには、文字列として直接データを指定することも、ファイルからデータを読み込むこともできます。
文字列としてデータを指定する:
bash
curl -X PUT -d '{"name": "New Name", "value": 123}' -H "Content-Type: application/json" http://example.com/api/resource/1
この例では、-X PUT
でメソッドをPUTに指定し、-d '{"name": "New Name", "value": 123}'
でJSON形式の文字列をリクエストボディとして指定しています。そして、-H "Content-Type: application/json"
でボディの形式がJSONであることをサーバーに伝えています。URLはターゲットリソースのURIです。
ファイルからデータを読み込む (-d @filename
):
-d
オプションの後に@
記号とファイル名を指定することで、指定したファイルの内容全体をリクエストボディとして使用できます。これは、大きなデータや整形済みのデータを送信する際に便利です。
例えば、update_data.json
というファイルに以下の内容が保存されているとします。
json
{
"name": "Updated Resource",
"status": "active",
"version": 2
}
このファイルの内容をPUTリクエストのボディとして送信するには、以下のようにします。
bash
curl -X PUT -d @update_data.json -H "Content-Type: application/json" http://example.com/api/resource/456
curlはupdate_data.json
ファイルを開き、その内容をリクエストボディに格納して送信します。この場合も、-H "Content-Type: application/json"
は忘れずに指定してください。-d
でファイル名を指定した場合でも、curlはContent-Type
を自動で推測しない(あるいはデフォルトのapplication/x-www-form-urlencoded
にしようとする)ためです。
2. -T
または --upload-file
オプションの使用
-T
オプションは、ローカルのファイルを指定したURLにアップロードするために設計されています。これは、ファイルシステム上のファイルをそのままPUTリクエストのボディとして送信する際に最も適したオプションです。-T
オプションを使用すると、curlはデフォルトでリクエストボディのContent-Type
をファイルの拡張子からある程度推測しようとします(ただし、正確なMIMEタイプが必要な場合は、やはり-H
オプションで明示的に指定するのが安全です)。
-T
オプションの後に、アップロードしたいファイル名を指定します。
例えば、document.txt
というテキストファイルを、サーバーの/files/mydoc.txt
というパス(URIに対応)にアップロードしたい場合、以下のようにします。
bash
curl -X PUT -T document.txt http://example.com/files/mydoc.txt
curlはdocument.txt
ファイルを開き、その内容をリクエストボディとしてhttp://example.com/files/mydoc.txt
に対してPUTリクエストとして送信します。サーバーはこのリクエストを受け取り、提供されたボディの内容で/files/mydoc.txt
というリソースを作成または更新します。
-T
オプションはバイナリファイル(画像、アーカイブなど)のアップロードにも適しています。例えば、image.jpg
という画像ファイルをアップロードする場合:
bash
curl -X PUT -T image.jpg -H "Content-Type: image/jpeg" http://example.com/images/photo.jpg
この場合、Content-Type
をimage/jpeg
と明示的に指定することで、サーバーがファイルの内容を正しく認識できるようにしています。
-d
vs -T
:
-d
: 文字列データや、JSON/XMLなどの構造化データファイルを送信する場合に適しています。Content-Type
の指定が必須なケースが多いです。-T
: バイナリファイルやテキストファイルなど、ファイルの内容そのものをアップロードする場合に適しています。URLがアップロード先のファイルパスに対応しているようなシナリオで特に有用です。
どちらのオプションを使うかは、APIの設計やサーバーの実装によって異なります。APIドキュメントを確認し、どちらの形式でデータを送信する必要があるかを確認してください。
PUTリクエストにおけるヘッダーの重要性
HTTPヘッダーは、クライアントとサーバーの間で、リクエストまたはレスポンスに関するメタデータを交換するために使用されます。PUTリクエストにおいては、特にリクエストボディの内容やサーバーでの処理方法を指定するために、いくつかのヘッダーが重要になります。curlでは、-H
または--header
オプションを使ってヘッダーを追加できます。
bash
curl -X PUT -H "Header-Name: Header Value" [URL]
複数のヘッダーを指定する場合は、-H
オプションを複数回使用します。
bash
curl -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer YOUR_TOKEN" [URL]
PUTリクエストでよく使われる、あるいは重要なヘッダーについて説明します。
Content-Type
これはPUTリクエストで最も重要なヘッダーの一つです。リクエストボディに含まれるデータのメディアタイプ(MIMEタイプ)をサーバーに伝えます。サーバーはContent-Type
を見て、ボディのデータをどのように解釈・処理すればよいかを判断します。
- JSONデータの場合:
-H "Content-Type: application/json"
- XMLデータの場合:
-H "Content-Type: application/xml"
- プレーンテキストの場合:
-H "Content-Type: text/plain"
- HTMLの場合:
-H "Content-Type: text/html"
- バイナリデータで不明な場合:
-H "Content-Type: application/octet-stream"
- 特定の画像フォーマット:
-H "Content-Type: image/jpeg"
,-H "Content-Type: image/png"
など
このヘッダーが正しく指定されていないと、サーバーはボディの内容を適切に処理できず、415 Unsupported Media Typeなどのエラーを返す可能性があります。-d
オプションでデータを送信する場合は、特に意識して指定するようにしましょう。-T
オプションの場合、curlはある程度推測しますが、明示的な指定がより安全です。
Authorization
APIなどで認証が必要な場合、このヘッダーを使って認証情報(APIキー、ベアラートークン、ユーザー名/パスワードなど)をサーバーに送信します。PUTリクエストはリソースを変更する操作であるため、認証・認可が必要となるケースが非常に多いです。
“`bash
ベアラートークンを使用する場合
curl -X PUT -H “Authorization: Bearer YOUR_ACCESS_TOKEN” … [URL]
Basic認証を使用する場合 (ユーザー名:パスワードをBase64エンコードして送信)
curlには -u オプションがあり、Basic認証を簡略化できます
curl -X PUT -u “username:password” … [URL]
“`
-u
オプションは自動的にAuthorization: Basic ...
ヘッダーを生成してくれます。
If-Match
/ If-Unmodified-Since
:条件付き更新
これらのヘッダーは「条件付きリクエスト」に使用されます。PUTリクエストでは、特に複数のクライアントが同じリソースを同時に更新しようとする「競合」を防ぐために役立ちます。
If-Match
: 指定したETag(リソースの特定バージョンを表す識別子、サーバーがETag
レスポンスヘッダーで返す)が現在のリソースのETagと一致する場合にのみリクエストを処理します。一致しない場合は412 Precondition Failedを返します。If-Unmodified-Since
: 指定した日時以降にリソースが変更されていない場合にのみリクエストを処理します。変更されている場合は412 Precondition Failedを返します。
これらのヘッダーを使用することで、「私が読み込んだ時のバージョンのリソースがまだ変更されていなければ更新する」というロジックを実装できます。
例:特定のETagを持つリソースのみを更新する場合
“`bash
まずGETリクエストなどでリソースを取得し、ETagヘッダーの値を確認する
curl -i http://example.com/api/resource/123
レスポンスヘッダー: ETag: “abcdef123456”
そのETagを指定してPUTリクエストを送信
curl -X PUT -d ‘{“status”: “processed”}’ -H “Content-Type: application/json” -H “If-Match: \”abcdef123456\”” http://example.com/api/resource/123
“`
ETagの値には二重引用符が含まれる場合があるため、シェルのエスケープに注意が必要です。
その他の一般的なヘッダー
Accept
: クライアントが受け付け可能なメディアタイプ。サーバーはレスポンスボディのContent-Type
を決定する際にこれを参考にします。User-Agent
: クライアント(この場合はcurlのバージョンなど)を識別する情報。Connection
: 接続の管理(例:close
でリクエスト処理後に接続を閉じる)。
これらのヘッダーはPUTに限定されるものではありませんが、必要に応じて-H
オプションで追加できます。
具体的なPUTのユースケースとcurlでの実践
ここでは、いくつかの具体的なユースケースを想定し、curlコマンドの実行例と、想定されるレスポンスについて解説します。
ユースケース1:既存リソースの更新(JSONデータ)
APIを通じて、IDが123
のユーザー情報を更新することを考えます。更新データはJSON形式で送信します。
シナリオ: ユーザーID 123のメールアドレスとステータスを更新する。
送信データ(JSON):
json
{
"email": "[email protected]",
"status": "active"
}
curlコマンド:
update_user.json
というファイルに上記のJSONデータが保存されていると仮定します。APIのエンドポイントはhttp://api.example.com/users/123
とします。認証としてベアラートークンYOUR_TOKEN
が必要とします。
bash
curl -X PUT \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d @update_user.json \
http://api.example.com/users/123
-X PUT
: PUTメソッドを指定。-H "Content-Type: application/json"
: ボディがJSON形式であることを指定。-H "Authorization: Bearer YOUR_TOKEN"
: 認証トークンを指定。-d @update_user.json
:update_user.json
ファイルの内容をボディとして送信。http://api.example.com/users/123
: 更新対象のリソースURI。
想定されるサーバーの処理:
サーバーはhttp://api.example.com/users/123
というリソースを探します。リソースが存在すれば、提供されたJSONデータでそのリソースの内容を完全に置き換えます。もしこのURIのリソースが存在しない場合、サーバーがPUTでの新規作成を許可していれば、ID 123を持つ新しいユーザーリソースを作成し、提供されたJSONをその初期状態とします(ただし、多くのRESTful APIでは、特定IDのリソースのPUTは更新にのみ使用され、新規作成はPOSTでリソースコレクションに対して行われることが多いです)。
想定されるレスポンス:
- 成功:
200 OK
: 更新が成功し、レスポンスボディに更新後のリソース表現が含まれる場合など。204 No Content
: 更新は成功したが、レスポンスボディが不要な場合(PUTによる更新でレスポンスボディがないのは一般的)。
- エラー:
400 Bad Request
: 送信したJSONデータの形式が不正など。401 Unauthorized
: 認証トークンが無効。403 Forbidden
: 認証は通ったが、更新権限がない。404 Not Found
: 指定されたURI(/users/123
)のリソースが存在しない(かつ新規作成も許可されていない)。405 Method Not Allowed
:/users/123
に対してPUTメソッドが許可されていない。415 Unsupported Media Type
:Content-Type: application/json
が受け付けられない。
レスポンスの確認には、curlに-v
(verbose) または-i
(include headers) オプションを追加すると便利です。
bash
curl -v -X PUT \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d @update_user.json \
http://api.example.com/users/123
-v
オプションは、リクエストとレスポンスの詳細(メソッド、ヘッダー、接続情報など)を表示してくれるため、デバッグに非常に役立ちます。
ユースケース2:新しいリソースの作成(PUTによる)
PUTメソッドは、クライアントがURIを決定して新しいリソースを作成するためにも使用されます。これは、ファイルシステムのような階層構造を持つリソースや、クライアント側でユニークなIDを生成できる場合に適しています。
シナリオ: /config/settings.yaml
というパスに新しい設定ファイルを作成する。
送信データ(YAML):
yaml
database:
host: localhost
port: 5432
name: myapp_db
curlコマンド:
settings.yaml
というファイルに上記のYAMLデータが保存されていると仮定します。ターゲットURIはhttp://config.example.com/config/settings.yaml
とします。
bash
curl -X PUT \
-H "Content-Type: application/x-yaml" \
-T settings.yaml \
http://config.example.com/config/settings.yaml
-X PUT
: PUTメソッドを指定。-H "Content-Type: application/x-yaml"
: ボディがYAML形式であることを指定(YAMLの標準MIMEタイプはapplication/x-yaml
またはtext/yaml
など、状況による)。-T settings.yaml
:settings.yaml
ファイルの内容をボディとして送信。-T
はファイルアップロードに適しており、このシナリオに合います。http://config.example.com/config/settings.yaml
: 作成または更新対象のリソースURI。
想定されるサーバーの処理:
サーバーはhttp://config.example.com/config/settings.yaml
というリソースを探します。リソースが存在しない場合、サーバーがそのURIでの新規作成を許可していれば、新しいリソースを作成し、提供されたYAMLデータで初期化します。リソースが既に存在する場合、提供されたYAMLデータでその内容を完全に置き換えます。
想定されるレスポンス:
- 成功:
201 Created
: 新しいリソースが作成された場合。通常、Location
ヘッダーに作成されたリソースのURIが含まれます(ただし、PUTの場合はリクエストURIと同じ)。200 OK
または204 No Content
: 既存のリソースが更新された場合。
- エラー:
400 Bad Request
: YAMLデータの形式が不正など。404 Not Found
: 指定されたパスの一部(例:/config/
ディレクトリ)が存在しないなど、URIの構造が無効な場合。405 Method Not Allowed
: 指定されたURIに対してPUTメソッドが許可されていない。409 Conflict
: リソースの作成や更新が、現在のリソースの状態と競合する場合(例: 既に存在するが、別のタイプのファイルであるなど)。415 Unsupported Media Type
:Content-Type: application/x-yaml
が受け付けられない。
PUTによる新規作成は、リソースのURIがクライアントによって事前に決定される必要があるという点で、サーバーがURIを生成するPOSTとは異なります。
ユースケース3:バイナリファイルのアップロード
PUTメソッドは、バイナリファイルを直接サーバー上の特定のパスにアップロードするためによく使用されます。
シナリオ: ローカルの画像ファイルphoto.jpg
を、サーバーの/images/users/user1/profile.jpg
というパスにアップロードする。
curlコマンド:
bash
curl -X PUT \
-H "Content-Type: image/jpeg" \
-T photo.jpg \
http://storage.example.com/images/users/user1/profile.jpg
-X PUT
: PUTメソッドを指定。-H "Content-Type: image/jpeg"
: アップロードするファイルがJPEG画像であることを指定。バイナリファイルの場合でも、可能な限り正確なContent-Type
を指定するのが良い習慣です。-T photo.jpg
:photo.jpg
ファイルの内容をボディとして送信。-T
オプションはバイナリファイルの扱いにも適しています。http://storage.example.com/images/users/user1/profile.jpg
: アップロード先のターゲットURI。
想定されるサーバーの処理:
サーバーはhttp://storage.example.com/images/users/user1/profile.jpg
というURIで指定される場所に、提供されたphoto.jpg
の内容を格納します。リソースが既に存在すれば上書き、存在しなければ新規作成となります。
想定されるレスポンス:
- 成功:
201 Created
: 新しいファイルが作成された場合。200 OK
または204 No Content
: 既存のファイルが上書きされた場合。
- エラー:
400 Bad Request
: リクエストが不正(例: ボディが空など)。401 Unauthorized
/403 Forbidden
: 認証・認可エラー。404 Not Found
: 指定されたパスの一部が存在しない。405 Method Not Allowed
: 指定されたURIに対してPUTが許可されていない。409 Conflict
: パスは存在するが、ファイルタイプなどが競合する。413 Payload Too Large
: アップロードしようとしたファイルがサーバーの制限を超えている。415 Unsupported Media Type
:Content-Type: image/jpeg
が受け付けられない。
-T
オプションは、ストリーミングアップロードもサポートしています。例えば、標準入力から読み込んだデータをPUTリクエストのボディとして送信したい場合は、ファイル名の代わりに-
を指定します。
bash
cat local_file.bin | curl -X PUT -T - http://example.com/upload/remote_file.bin
このコマンドは、local_file.bin
の内容をcat
コマンドで標準出力に出力し、それをパイプ(|
)でcurlの標準入力に渡しています。curlは-T -
によって標準入力を読み込み、その内容をPUTリクエストのボディとして送信します。
ユースケース4:条件付き更新(ETagを使用)
複数のクライアントが同じリソースをほぼ同時に更新しようとする場合、最後に更新したクライアントの変更だけが有効になり、他のクライアントの変更は失われてしまう可能性があります(Lost Update問題)。これを避けるために、条件付き更新が使用できます。
シナリオ: ユーザー情報を更新する際に、その情報が自分が読み込んだ時から変更されていないことを確認する。
手順:
- まず、GETリクエストでユーザー情報を取得し、レスポンスヘッダーの
ETag
の値を確認します。 - 取得した
ETag
の値をIf-Match
ヘッダーに含めてPUTリクエストを送信します。
curlコマンド:
-
GETリクエストでETagを取得:
http://api.example.com/users/123
から情報を取得し、ヘッダーを表示します (-i
オプションを使用)。bash
curl -i http://api.example.com/users/123レスポンスヘッダーに以下のような行が含まれているとします。
HTTP/1.1 200 OK
Content-Type: application/json
ETag: "v-abcde12345"
Last-Modified: Tue, 01 Nov 2023 10:00:00 GMT
...
ETagの値は"v-abcde12345"
です。 -
PUTリクエストで条件付き更新を実行:
このETagを使用して、ユーザー情報を更新します。更新データは先ほどと同様、update_user.json
ファイルの内容とします。bash
curl -X PUT \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "If-Match: \"v-abcde12345\"" \
-d @update_user.json \
http://api.example.com/users/123-H "If-Match: \"v-abcde12345\""
: 取得したETagをIf-Match
ヘッダーに指定します。ETagの値に含まれる可能性のある二重引用符を、シェルのルールに従ってエスケープする必要があることに注意してください(多くの場合、バックスラッシュ\
でエスケープするか、ヘッダー全体をシングルクォートで囲みます)。
想定されるサーバーの処理とレスポンス:
- サーバーは
http://api.example.com/users/123
リソースの現在のETagを確認します。 - 現在のETagが指定した
"v-abcde12345"
と一致する場合: 更新処理を実行します。成功すれば200 OK
または204 No Content
を返します。 - 現在のETagが指定したETagと一致しない場合(つまり、自分がGETした後に別のクライアントがこのリソースを変更した場合): 更新処理は実行せず、
412 Precondition Failed
エラーを返します。
412 Precondition Failed
を受け取ったクライアントは、通常、リソースを再取得して最新の状態を確認し、必要に応じて再度更新処理を行う、といった対応をとります。
If-Unmodified-Since
ヘッダーも同様に機能しますが、ETagの代わりに日付/時刻(通常はLast-Modifiedヘッダーの値)を使用します。
“`bash
If-Unmodified-Since ヘッダーの例
curl -X PUT … -H “If-Unmodified-Since: Tue, 01 Nov 2023 10:00:00 GMT” … http://api.example.com/users/123
“`
PUTリクエストのレスポンスを理解する
curlでPUTリクエストを送信した後、サーバーからのレスポンスを正しく理解することが重要です。レスポンスは、ステータスライン(HTTPバージョン、ステータスコード、フレーズ)、レスポンスヘッダー、そしてレスポンスボディで構成されます。
curlはデフォルトではレスポンスボディのみを標準出力に表示します。ステータスラインやヘッダーも確認したい場合は、-i
または-v
オプションを使用します。
一般的な成功レスポンス
200 OK
: リクエストが成功し、リソースが更新されました。レスポンスボディに更新後のリソースの表現が含まれることがあります。201 Created
: リクエストが成功し、新しいリソースが作成されました(PUTで新規作成が許可されている場合)。レスポンスボディに作成されたリソースの表現が含まれることがあり、Location
ヘッダーにリソースのURIが含まれるべきです。204 No Content
: リクエストは成功し、リソースは更新されましたが、レスポンスボディには情報がありません。これはPUTによる更新の一般的な成功レスポンスの一つです。
一般的なエラーレスポンス
PUTリクエストで発生しうるエラーレスポンスは多岐にわたります。主要なものをいくつか示します。
400 Bad Request
: リクエストの形式が不正です。例えば、送信したJSONやXMLの構文エラー、必須パラメーターの欠落など。401 Unauthorized
: 認証が必要です。リクエストに有効な認証情報(トークン、ID/パスワードなど)が含まれていないか、無効です。403 Forbidden
: 認証は成功しましたが、リクエストされたアクション(PUT)を実行する権限がありません。404 Not Found
: 指定されたリクエストURIのリソースが存在しません。PUTで新規作成が許可されていないエンドポイントに対して、存在しないリソースのURIを指定した場合など。405 Method Not Allowed
: リクエストURIに対してPUTメソッドが許可されていません。そのURIはGETやPOSTのみをサポートしているかもしれません。Allow
レスポンスヘッダーに許可されているメソッドがリストされている場合があります。409 Conflict
: リクエストが現在のリソースの状態と競合しています。PUTで新規作成しようとしたが、そのURIが既に存在し、かつ上書きが許可されていない、あるいはリソースの状態が更新を妨げている場合など。412 Precondition Failed
: 条件付き更新(If-Match
やIf-Unmodified-Since
)の前提条件が満たされませんでした。指定したETagがリソースの現在のETagと一致しない場合など。413 Payload Too Large
: リクエストボディ(送信データ)のサイズがサーバーの制限を超えています。415 Unsupported Media Type
: リクエストヘッダーで指定したContent-Type
(例:application/json
)が、サーバーまたは特定のリソースで受け入れられない形式です。500 Internal Server Error
: サーバー内部で予期しないエラーが発生しました。サーバー側の問題であり、クライアントのリクエスト自体に問題がない場合でも発生し得ます。501 Not Implemented
: サーバーがPUTメソッドを実装していません。503 Service Unavailable
: サーバーが一時的に過負荷またはメンテナンス中です。
エラーレスポンスを受け取った際は、ステータスコードと、可能であればレスポンスボディに含まれるエラーメッセージを確認して、原因を特定することが重要です。-v
オプションを使用すると、リクエストとレスポンスの詳細なやり取りが見られるため、デバッグの第一歩として非常に有効です。
高度なcurlテクニック
curlは非常に多機能なツールであり、PUTリクエストの実行においても様々な高度なテクニックを利用できます。
HTTPS通信
curlはデフォルトでHTTPSをサポートしており、証明書の検証も行います。URLをhttps://...
で始めれば、安全なHTTPS接続を使用してPUTリクエストを送信できます。自己署名証明書などで証明書の検証をスキップしたい場合は、-k
または--insecure
オプションを使用しますが、セキュリティリスクを伴うため注意が必要です。
bash
curl -X PUT -H "Content-Type: application/json" -d '...' https://secure.example.com/api/resource/123
認証(-u
/ --user
)
Basic認証やDigest認証が必要な場合、-u
または--user
オプションを使うと便利です。
bash
curl -X PUT -u "username:password" -H "Content-Type: application/json" -d '...' http://example.com/api/resource/123
curlは指定されたユーザー名とパスワードを使って、必要なAuthorization
ヘッダーを自動的に生成し、サーバーからの認証チャレンジ(401 Unauthorized
レスポンスとWWW-Authenticate
ヘッダー)にも適切に応答しようとします。
プロキシ経由でのリクエスト(-x
/ --proxy
)
HTTPプロキシ経由でリクエストを送信したい場合は、-x
または--proxy
オプションを使用します。
bash
curl -X PUT -x "http://proxy.example.com:8080" -H "Content-Type: application/json" -d '...' http://example.com/api/resource/123
プロキシが認証を必要とする場合は、-U
または--proxy-user
オプションでプロキシ用のユーザー名とパスワードを指定できます。
冗長出力(-v
/ --verbose
)
既に何度か触れましたが、-v
オプションはデバッグにおいて非常に強力です。リクエストを送信する際、curlが内部で何をしているのか、どのヘッダーを送信しているのか、サーバーからどのようなレスポンスヘッダーやデータが返ってきているのかを詳細に確認できます。
bash
curl -v -X PUT -H "Content-Type: application/json" -d '...' http://example.com/api/resource/123
出力には、接続試行、SSL/TLSハンドシェイク(HTTPSの場合)、送信ヘッダー(>
で始まる行)、受信ヘッダー(<
で始まる行)、そしてボディデータなどが含まれます。エラーが発生した場合、この冗長出力を見ることで、問題がクライアント側にあるのか、サーバー側にあるのか、どのステップで失敗しているのかなどを特定する手がかりが得られます。
リダイレクトの処理(-L
/ --location
)
サーバーがリクエストに対してリダイレクト応答(3xx系ステータスコード)を返した場合、デフォルトではcurlはリダイレクト先には追従しません。リダイレクト先に自動的に追従させたい場合は、-L
または--location
オプションを指定します。
bash
curl -L -X PUT -H "Content-Type: application/json" -d '...' http://example.com/old/resource
サーバーがhttp://example.com/old/resource
へのPUTリクエストに対して301 Moved Permanently
などのリダイレクトを返した場合、curlは-L
オプションがあればリダイレクト先のURIに改めてリクエストを送信します。ただし、リダイレクト時にPUTメソッドがGETに変わってしまう挙動(HTTP/1.1の仕様)に注意が必要です。リダイレクト後もPUTを維持したい場合は、--post301
, --post302
, --post303
などのオプションを状況に応じて使用する必要があります(PUTの場合は--request-target
オプションや、カスタムロジックが必要な場合もありますが、一般的にはPUTに対するリダイレクトは稀です)。
タイムアウトの設定
大きなファイルをアップロードしたり、サーバーの応答が遅い場合に、リクエストが無限に待機しないようにタイムアウトを設定できます。
--connect-timeout <seconds>
: サーバーへの接続確立のタイムアウト(秒)。--max-time <seconds>
: リクエスト全体の最大許容時間(秒)。
bash
curl --max-time 30 -X PUT -T large_file.bin http://example.com/upload/large_file.bin
Cookieの送信/受信
PUTリクエストにおいて、セッション管理のためにCookieの送受信が必要な場合があります。
-b <file>
または--cookie <file>
: 指定したファイルからCookieを読み込み、リクエストに含めます。または、"NAME=VALUE"
形式で直接Cookie文字列を指定します。-c <file>
または--cookie-jar <file>
: レスポンスで受け取ったCookieをファイルに保存します。
“`bash
session.txtからCookieを読み込み、受け取ったCookieをsession.txtに保存
curl -b session.txt -c session.txt -X PUT -H “Content-Type: application/json” -d ‘…’ http://example.com/api/resource/123
“`
セキュリティに関する考慮事項
PUTメソッドはサーバー上のリソースを変更または作成するため、セキュリティには十分な注意が必要です。curlを使ってPUTリクエストを送信する際も、以下の点を意識するべきです。
- 認証と認可: 重要なリソースに対するPUT操作は、必ず認証によってリクエスト元の身元を確認し、認可によってそのユーザーがそのリソースを操作する権限を持っているかを確認する必要があります。公開されているAPIでも、PUTエンドポイントには通常、何らかの認証が必要です。curlで認証情報を送信する際は、HTTPSを使用し、
-u
や-H "Authorization"
オプションを適切に使用します。 - HTTPSの使用: 機密性の高いデータ(例えばユーザー情報や設定データ)をリクエストボディとして送信する場合、必ずHTTPSを使用して通信を暗号化してください。これにより、通信経路での盗聴や改ざんを防ぎます。curlはデフォルトでHTTPSをサポートしています。
- 入力値の検証: PUTリクエストでサーバーに送信するデータは、サーバー側で厳密に検証されるべきです。悪意のあるデータや不正な形式のデータが格納されることを防ぎます。curlを使う側としては、送信するデータがサーバーの期待する形式や制約を満たしていることを確認する必要があります。
- APIキーやトークンの安全な扱い:
-H "Authorization"
などでAPIキーやトークンを指定する場合、コマンド履歴に残らないように注意したり、環境変数から読み込むなどの工夫をすることが望ましいです。また、これらの認証情報を安易に共有したり、公開されているコードに埋め込んだりしないでください。 - 冗長出力(
-v
)の使用時の注意:-v
オプションはデバッグに便利ですが、認証情報やCookieなど、機密情報がコンソールに出力されてしまう可能性があります。本番環境の認証情報を使って-v
を実行する際は特に注意し、出力をログファイルにリダイレクトするなどの対策を検討してください。
まとめ
HTTP PUTメソッドは、特定のURIのリソースをクライアントが提供するデータで完全に置き換える、あるいは新規作成するためのHTTPメソッドです。その最大の特徴は冪等性であり、同じリクエストを何度実行しても結果が同じになるという点です。
curl
は、このPUTメソッドを含むあらゆるHTTPリクエストをコマンドラインから柔軟に実行できる非常に強力なツールです。この記事では、curlを使ってPUTリクエストを送信するための基本的な方法から、具体的なユースケース、関連するヘッダーの役割、レスポンスの解釈、そして高度なテクニックまでを詳細に解説しました。
PUTリクエストをcurlで実行する際の主なポイントは以下の通りです。
- 必ず
-X PUT
オプションを指定して、HTTPメソッドをPUTに設定します。 - リソースを置き換える(または作成する)ためのデータは、
-d
または-T
オプションを使ってリクエストボディに含めます。-d
: 文字列データや、JSON/XMLファイルの内容を送信する場合に使用。Content-Type
ヘッダーの明示的な指定が強く推奨されます。-T
: ファイルの内容全体をアップロードする場合に使用。
-H
オプションを使って、Content-Type
、Authorization
、条件付き更新のためのIf-Match
などの重要なヘッダーを指定します。Content-Type
はPUTリクエストでは特に重要です。- レスポンスを確認する際は、
-i
や-v
オプションを使用して、ステータスコードやヘッダー、詳細な通信内容を確認すると、成功/失敗の原因把握やデバッグに役立ちます。 - 認証、HTTPSの使用、入力検証など、PUT操作に伴うセキュリティ上の考慮事項を理解し、適切に対応することが重要です。
curlは単にHTTPリクエストを送信するだけでなく、認証、プロキシ、Cookie、タイムアウト、リダイレクト処理など、HTTP通信に関する様々な側面を制御できます。これらのオプションを組み合わせることで、複雑なシナリオにも対応可能です。
この記事で解説した内容を参考に、ぜひ実際にcurlを使って様々なPUTリクエストを試してみてください。APIドキュメントを参照しながら、対象のエンドポイントがPUTをどのようにサポートしているか、どのような形式のデータを期待しているか、どのようなレスポンスを返すかなどをcurlで確認することで、理解が深まるでしょう。特に-v
オプションを活用したデバッグは、API連携開発の強力な助けとなります。
HTTPとcurlの世界は広大ですが、PUTメソッドを効果的に使いこなすことは、現代のウェブ開発やシステム連携において非常に重要なスキルです。この記事が、そのスキル習得の一助となれば幸いです。