最近の学びのエントリです(挨拶省略した簡略版)
目次
- 目次
- nikkieはhttpxを使いたい
- まとめ:data引数とjson引数
- HTTPメソッドのdata引数とjson引数
- 互換なAPIのrequestsのドキュメントも確認
- mdn「フォームデータの送信」
- P.S. httpxのソースコードを覗く
- httpx関連エントリ
nikkieはhttpxを使いたい
PythonのHTTPクライアントライブラリとして使用者が多いのはrequestsだと思います。
しかしながら私としては2024年となってはあまりrequestsを採用したくなく、いまはhttpxを選んでいます(一石を投じていきたい!)
httpxはrequestsのAPIを踏襲しつつ1、(requestsにはできない2)イベントループによる非同期処理も書けるのです!
PythonでHTTP通信したいときのライブラリ選定、かつては初手requestsだったのかもですが、今の私からすると疑問手の感。
— nikkie / にっきー 技書博 け-04 Python型ヒント本 (@ftnext) 2024年5月27日
requestsのAPIを踏襲し、なおかつイベントループによる非同期 (async / await) をサポートしたライブラリ(例:httpx)を採用していきたい派ですhttps://t.co/WONuVuXHlx
そんなhttpxを使っていての学びのアウトプットです。
Web APIにJSON(Pythonのコード中では辞書)を送りたかったのですが、data
引数なのかjson
引数なのかがパッと分かりませんでした。
まとめ:data引数とjson引数
※httpxのドキュメントは記載が少なめだったので、同一のAPIのrequestsのドキュメントも参照しました。
httpxのソースコードも簡単に確認し、httpxにも当てはまると考えて記載していますが、誤解がありましたらお知らせください。
どちらも辞書を渡しますが、
data
引数はform-encoded dataとして送る- 単純な辞書(
dict[str, str]
)を渡す - 辞書を
json.dumps
した文字列も渡せる - Content-Typeヘッダは
application/x-www-form-urlencoded
に設定
- 単純な辞書(
json
引数はJSON-encoded dataとして送る- 込み入った辞書を渡す(辞書の値が、数値や真理値、配列)
- Content-Typeヘッダは
application/json
に設定
今回利用するWeb APIはapplication/json
のリクエストを受け付けたため、json
引数を使って事なきを得ました。
HTTPメソッドのdata引数とjson引数
httpxのドキュメント QuickStartより
Sending Form Encoded Data
One common way of including that is as form-encoded data, which is used for HTML forms.
r = httpx.post("https://httpbin.org/post", data={'key1': 'value1', 'key2': 'value2'})
POSTやPUTリクエストでリクエストボディにデータを含めるやり方の一つが、form-encoded data。
data
引数を使います。
辞書を渡していますね
Sending JSON Encoded Data
For more complicated data structures you'll often want to use JSON encoding instead.
r = httpx.post("https://httpbin.org/post", json={'integer': 123, 'boolean': True, 'list': ['a', 'b', 'c']})
POSTやPUTリクエストのボディにデータを含める別のやり方がJSON encoded data。
先のform-encoded dataと比べて、込み入ったデータが送れるそうです。
文字列以外の値や、配列が含まれていますね
互換なAPIのrequestsのドキュメントも確認
Quickstartの「More complicated POST requests」
data引数
Typically, you want to send some form-encoded data — much like an HTML form. To do this, simply pass a dictionary to the data argument.
r = requests.post('https://httpbin.org/post', data={'key1': 'value1', 'key2': 'value2'})
There are times that you may want to send data that is not form-encoded. If you pass in a string instead of a dict, that data will be posted directly.
r = requests.post(url, data=json.dumps({'some': 'data'}))
json.dumps()で辞書はJSON形式の文字列となります。
>>> import json >>> json.dumps({'some': 'data'}) '{"some": "data"}'
data引数に辞書の代わりに文字列を渡すと、その文字列がそのままPOSTされると記載されています。
json引数
If you need that header set and you don’t want to encode the dict yourself, you can also pass it directly using the json parameter (added in version 2.4.2) and it will be encoded automatically:
r = requests.post(url, json={'some': 'data'})
json
引数を指定したとき、Content-Type
ヘッダをapplication/json
に設定data
引数ではヘッダは設定されない
json
引数には辞書を渡すdata
引数には辞書、または自身でエンコード(json.dumps(辞書)
)した文字列を渡す
mdn「フォームデータの送信」
「form-encodedって説明できないかも」と手を伸ばしました。
クライアント側の「POST メソッド」より
フォームをが POST メソッドで送信されると、URL にはデータが追加されず、HTTP リクエストは次のように、リクエスト本文にデータが含まれた形になります。(引用ママ)
say=Hi&to=Mom
深く理解した感覚はないのですが、この形式は明らかにJSONではないですし、JSONとは別の形式があると認識しました(宿題事項)
P.S. httpxのソースコードを覗く
https://github.com/encode/httpx/blob/0.27.0/httpx/_content.py#L182-L214
if data is not None and not isinstance(data, Mapping): return encode_content(data) if content is not None: return encode_content(content) elif files: return encode_multipart_data(data or {}, files, boundary) elif data: return encode_urlencoded_data(data) elif json is not None: return encode_json(json)
data
引数に辞書を指定した時のencode_urlencoded_data()
関数
https://github.com/encode/httpx/blob/0.27.0/httpx/_content.py#L134-L147
urllib.parse.urlencode()
呼び出し。2要素のタプルからなるリストを渡している- https://docs.python.org/ja/3/library/urllib.parse.html#urllib.parse.urlencode
パーセントエンコードされた ASCII 文字列に変換します
Content-Type
をapplication/x-www-form-urlencoded
に指定
json
引数を指定した時のencode_json()
関数
https://github.com/encode/httpx/blob/0.27.0/httpx/_content.py#L174-L179
json.dumps()
で辞書を文字列にしてからencode()
でbytesに変換Content-Type
をapplication/json
に指定
httpx関連エントリ
- 「A broadly requests-compatible API.」 ref: https://www.python-httpx.org/#features↩
- 見逃していたらお知らせください。requestsの拡張ライブラリでは対応しているようです。ref: https://requests.readthedocs.io/en/latest/community/recommended/#requests-threads↩