Web APIとやり取りするとき、まず押さえるべきはHTTPのGETとPOSTの役割と違いです。
この記事では、両者の基本と考え方を丁寧に整理し、Pythonのrequestsライブラリでの具体的な書き方までを一気に学べるように構成しました。
初心者の方でも、この記事を読み終える頃には使い分けの判断ができるようになります。
HTTPのGETとPOSTの基本
何をするメソッドか
まず、GETは「取得」、POSTは「送信(作成・登録)」です。
この一言が土台になります。
GETは読み取り専用の要求
GETはサーバにあるリソース(データ)を読み取るためのメソッドです。
原則としてサーバ側の状態を変えないことが期待されます。
ニュース一覧の取得やユーザ情報の参照などが該当します。
繰り返し同じGETを送っても結果や副作用は変わらないのが理想です。
POSTは何かを新しく送る要求
POSTはサーバに新しい情報を送って処理してもらうメソッドです。
典型的には新規登録、作成、問い合わせ送信などです。
同じPOSTを繰り返すと重複作成につながることがあるため、扱いに注意します。
URLとボディ(送る場所)
GETは主にURLの「クエリ文字列」に、POSTは「リクエストボディ」にデータを入れます。
GETはURLにパラメータを付ける
GETでは次のようにURL末尾に?key=value&...の形でパラメータを付けます。
例: https://api.example.com/search?q=python&page=2
POSTはボディにデータを入れる
POSTではURLはエンドポイントを示すだけで、送るデータ本体はリクエストボディに入れます。
ボディの形式はapplication/jsonやapplication/x-www-form-urlencodedなどContent-Typeで指定します。
見えるデータと隠れるデータ
URLはブラウザやログに残りやすく、ボディはURLほど目につきませんが「完全に隠れる」わけではありません。
URLは目に見えて残る
GETのクエリはアドレスバーや履歴に露出します。
アクセスログにも残りやすく、共有もしやすいです。
ボディはURLには出ないが安全とは限らない
POSTのボディはURLに出ませんが、開発者ツールやサーバ側では見えます。
「POSTだから安全」ではありません。
機密は必ずHTTPSで送信し、クエリに秘密情報を入れないのが基本です。
以下は露出の違いの概要です。
| 観点 | GET | POST |
|---|---|---|
| データの位置 | URLのクエリ | リクエストボディ |
| ブラウザのアドレスバー | 露出する | 露出しない |
| ブラウザ履歴・ブックマーク | 残りやすい | 基本的に残らない |
| サーバアクセスログ | URLとして残る | ヘッダのみ、ボディは通常ログに残さない(設定次第) |
データ量と形式(ざっくり)
GETは短いクエリ向き、POSTは大きなデータや複雑な構造向きです。
おおまかな上限感覚
GETのURL長は仕様で厳密には定義されませんが、ブラウザやサーバの制限で約2KB〜8KB程度が実用限界になることが多いです。
一方、POSTのボディはより大きなデータを扱えます(ただしサーバ設定に依存します)。
よく使うデータ形式
- JSON送信:
application/json(構造的なデータに向く) - フォーム送信:
application/x-www-form-urlencoded(HTMLフォームの標準) - ファイル含むフォーム:
multipart/form-data
Python(requests)でGETとPOST
GETの書き方(クエリ)
Pythonのrequests.getではparamsに辞書を渡すのが基本です。
ライブラリが自動でクエリ文字列に組み立ててURLエンコードしてくれます。
サンプルコード(クエリで検索条件を渡す)
# requestsを使ったGETリクエストの基本例
import requests
def fetch_search_results():
# デモ用のHTTPエコーサービス(httpbin)のGETエンドポイント
url = "https://httpbin.org/get"
# URLに付与したいクエリパラメータを辞書で指定
params = {
"q": "python", # 検索キーワード
"page": 2 # ページ番号
}
# GETにparams=を渡すと、?q=python&page=2 のようなクエリ文字列を自動生成
response = requests.get(url, params=params)
# ステータスとJSONを確認(実運用ではエラーハンドリングを追加すると良い)
print("Status:", response.status_code)
data = response.json() # JSONとしてパース
# サーバが受け取ったクエリは "args" に反映される(httpbinの仕様)
print("Args:", data.get("args"))
print("URL:", data.get("url"))
if __name__ == "__main__":
fetch_search_results()
Status: 200
Args: {'page': '2', 'q': 'python'}
URL: https://httpbin.org/get?page=2&q=python
POSTの書き方(JSON)
JSONを送るときはjson=引数を使うのが簡単で確実です。
requestsがContent-Type: application/jsonを自動設定し、辞書をJSON文字列に変換してボディへ入れます。
サンプルコード(JSONで新規作成リクエスト)
# JSONボディをPOSTする基本例
import requests
def create_user():
url = "https://httpbin.org/post"
# 送信したいJSONペイロード(辞書でOK)
payload = {
"username": "alice",
"email": "alice@example.com",
"roles": ["reader", "contributor"]
}
# json= を使うと自動でJSON化&適切なContent-Typeを付与
response = requests.post(url, json=payload)
print("Status:", response.status_code)
data = response.json()
# httpbinでは受け取ったJSONが "json" にそのまま返る
print("JSON echoed:", data.get("json"))
if __name__ == "__main__":
create_user()
Status: 200
JSON echoed: {'email': 'alice@example.com', 'roles': ['reader', 'contributor'], 'username': 'alice'}
フォーム送信の例(data)
HTMLフォームと同等の形式で送りたいときはdata=を使います。
requestsはapplication/x-www-form-urlencodedとしてボディを組み立てます。
サンプルコード(ログインフォームを想定)
# フォーム形式でPOSTする例(application/x-www-form-urlencoded)
import requests
def login_form():
url = "https://httpbin.org/post"
# 典型的なフォームのフィールド
form = {
"username": "alice",
"password": "s3cr3t" # 実運用ではHTTPS必須。ログにも残さないこと。
}
# data= でフォームエンコードしてボディに入る
response = requests.post(url, data=form)
print("Status:", response.status_code)
data = response.json()
# httpbinではフォーム値は "form" に反映される
print("Form echoed:", data.get("form"))
if __name__ == "__main__":
login_form()
Status: 200
Form echoed: {'password': 's3cr3t', 'username': 'alice'}
注意: パスワードなど機密はクエリに入れないでください。
必ずHTTPSを使い、ログ出力にも細心の注意を払いましょう。
使い分けの基準と注意点
取得はGET(状態を変えない)
「読むだけ」はGETです。
検索、一覧、詳細の参照など、サーバのデータや状態を変えない操作に使います。
例として、ユーザ一覧の取得はGET /users?limit=20のように表現します。
繰り返し実行しても副作用が起きないように設計します。
GETでやらない方がよいこと
データの新規作成や削除、更新などサーバの状態を変える処理はGETでは行いません。
ブックマークやクローラがアクセスしても安全であることが理想です。
追加や登録はPOST(状態が変わる)
「何かを増やす・登録する」はPOSTです。
新規ユーザ作成ならPOST /usersにボディでデータを送ります。
同じPOSTを繰り返すと重複が生じやすいため、クライアント側で送信の二重実行に注意し、必要に応じて<b>重複防止のトークン</b>や<b>リトライ方針</b>を設計します。
POSTのURLは操作対象、ボディは内容
慣れるまでのコツは、URLは「どこに」、ボディは「何を」という役割と考えることです。
URLでリソースやコレクションを示し、ボディで作成・処理に必要なデータを渡します。
キャッシュとブックマーク
GETはキャッシュやブックマークとの相性が良く、POSTは基本的にそれらに向きません。
GETはキャッシュされやすい
GETはブラウザや中継のキャッシュ対象になりやすく、URL単位で再現可能です。
検索結果ページの共有や、同じ条件での再取得が容易です。
POSTは履歴やブックマークに残しづらい
POSTはボディが履歴に残らないため、URLだけでは再現できません。
「アクションの再送」や「確認のダイアログ」が必要になるのはこのためです。
セキュリティの基本(パスワード)
秘密はURLに載せない、必ずHTTPSを使う。
これが最重要です。
守るべき原則
- パスワードやトークンを
GETのクエリに載せない。URLは履歴・ログ・共有で漏れやすいです。 - HTTPSを必ず使う。
POSTでも平文のHTTPでは盗聴されます。 - リクエストやエラーログに機密を出力しない。サンプル出力にも注意します。
クイックリファレンス(チェックリスト)
GETのチェック項目
- 処理は「参照のみ」になっているか(サーバ側の状態を変えないか)
- パラメータは
paramsでURLクエリに渡しているか - 機密情報をクエリに含めていないか
- ブックマークや共有を想定したURLになっているか
- クエリが長くなり過ぎていないか(必要ならPOSTを検討)
POSTのチェック項目
- 処理は「作成・送信・登録」など状態変化を伴うものか
- ボディ形式は目的に合っているか(
json=ordata=) - 重複送信の対策や再送時の挙動を決めているか
- 機密はボディに入れ、必ずHTTPSを使っているか
- エンドポイントURLは「どこに」送るかが明確か(内容はボディへ)
まとめ
GETは「読む」、POSTは「送る」—この役割をまず確実に押さえ、データの置き場所(URLかボディか)、露出の度合い、キャッシュやブックマークとの相性を理解することが肝心です。
Pythonではrequestsを使い、GETはparams=、POSTはjson=やdata=を使い分ければ、実装は自然と正しい方向に揃います。
機密をURLに載せない、HTTPSを必ず使うという基本を守りつつ、小さなサンプルから手を動かして理解を深めていきましょう。
