cURLからコードへ
cURLからコードへは、curlコマンドをブラウザ内でfetch、axios、Python requests、Go、PHP、Rubyのコードへ変換します。コマンドはシェルとして解析され、シングルクォート、ダブルクォート、ANSI-Cエスケープ、行継続、連結フラグを処理するため、スペースやアポストロフィを含むペイロードも壊れません。
cURLからコードへはどう動きますか?
変換は単純に見えて単純ではありません。curlコマンドはデータ形式ではなくシェルだからです。素朴な実装を壊す要素は3つあり、その3つすべてが、ブラウザの開発者ツールからコピーしたコマンドにありがちです。
クォート処理が最大の難所
-d '{"name":"Ada Lovelace"}'は、スペースを1つ含む単一の引数です。-H "Authorization: Bearer $TOKEN"には、シェルがすでに展開した(あるいは展開していない)変数が含まれます。--data $'line\nbreak'はANSI-Cクォーティングで、\nは実際の改行になります。同じ文字も、普通のシングルクォート内ではリテラルのバックスラッシュとnです。エスケープのルールはクォートの形式ごとに異なるため、正規表現ではこれを解きほぐせません。そこでコマンドは、今どのクォートの中にいるかを追跡する小さなステートマシンでトークン化され、出力部に渡されるのは完成した引数だけになります。
連結フラグには3つのパターンがある
-sSLは3つの独立したフラグです。-XPOSTは値を伴う1つのフラグです。-H'X-Trace: 1'は値を取るフラグで、その値に記号とスペースが含まれています。これらは文字を順にたどり、値を取る最初の文字で止まることで区別されます。これはcurl自身のパーサーと同じやり方で、-sSXPOSTが6つのフラグではなくPOSTとして出力される理由でもあります。
生成コードがでっち上げないもの
-d @payload.jsonは実行時にファイルを読み込みます。ファイルの中身はコマンド内にないため、ボディはインライン化できません。生成コードはファイル名を示し、読み込みはユーザーに委ねます。推測すれば、誤ったペイロードを黙って送信するコードが生まれるからです。-kはもう1つの意図的な省略です。生成コードは証明書検証を有効のまま保ち、その旨をコメントで伝えます。安全でないフラグをコードベースにコピーすることが、まさに本番環境へ至る経路だからです。
それ以外はそのまま変換されます。-uは実際に送信されるAuthorization: Basicヘッダーに、-bはCookieヘッダーに、-FはboundaryをHTTPクライアントに任せるマルチパートフォームに、-Gはcurlが置く場所と同じクエリ文字列へデータを移して変換されます。
curl
curl -X POST 'https://api.example.com/v1/orders' \
-H 'Content-Type: application/json' \
-d '{"total":148.5}'fetch
const response = await fetch("https://api.example.com/v1/orders", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"total": 148.5
}, null, 2),
});
const data = await response.json();curl → fetch
curl
curl -X POST 'https://api.example.com/v1/orders' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_API_TOKEN_HERE' \
-d '{"total":148.5}'fetch
const response = await fetch("https://api.example.com/v1/orders", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_API_TOKEN_HERE",
},
body: JSON.stringify({
"total": 148.5
}, null, 2),
});
const data = await response.json();
cURLからコードへが対応するオプションとエッジケースは?
| パラメータ | 型 | デフォルト | 動作とエッジケース |
|---|---|---|---|
| -X, --request | メソッド | ボディがあればPOST | HTTPメソッドを指定します。省略時は、コマンドにボディ、フォームフィールド、-IのいずれかがあればPOST、それ以外はGETになります。これはcurl自身のルールとまったく同じです。 |
| -H, --header | ヘッダー | なし | ヘッダーごとに1回ずつ指定します。-H "Name;"の形式はヘッダーを設定するのではなく削除するもので、生成コードは単にそのヘッダーを送信せず、値をでっち上げる代わりにその旨を明示します。 |
| -d, --data* | ボディ | なし | 複数の-dフラグは&で連結されます。これはcurlと同じ挙動です。-d @fileはコマンド内にファイルの中身が存在しないためインライン化できず、生成コードはファイル名を示すのみで、読み込みはユーザーに委ねられます。 |
| --data-urlencode | ボディ | フォームエンコード | 値はボディになる前にパーセントエンコードされるため、値にスペースや&が含まれていても安全です。これがこのフラグの存在意義です。 |
| -F, --form | マルチパート | なし | マルチパートフォームになります。-F name=@fileはファイルパートを添付し、-F name=valueはテキストパートを送信します。boundaryはHTTPクライアントに任せます。手動で設定するとmultipartリクエストが不正になる元だからです。 |
| -u, --user | Basic認証 | なし | curlが実際に送信するAuthorization: Basicヘッダーになり、資格情報はbase64でエンコードされます。コマンドの中で見えていた情報だからこそ、生成コードにもそのまま現れます。 |
| -b, --cookie | Cookieヘッダー | なし | セミコロン区切りのCookie文字列は1つのCookieヘッダーになり、名前と値のペアとして解析されます。生成コードが魔法の文字列ではなくデータとして読めるようにするためです。 |
| -G, --get | クエリ文字列 | オフ | -dと--data-urlencodeの各フィールドをURLのクエリ文字列へ移し、ボディを空にします。curlが長いパラメータ一覧でGETを発行するときの方法と同じです。 |
| -k, --insecure | 注意 | オフ | 再現しません。生成コードは証明書検証を有効のまま保ち、元のコマンドでは無効化されていたことをコメントで伝えます。安全でないフラグをコードベースにコピーしてしまうことが、それが本番環境まで生き残る経路です。 |
| --json | ボディ+ヘッダー | なし | ボディ、Content-Type: application/json、Accept: application/jsonをまとめて設定します。curlが7.82で追加した省略記法と同じ挙動です。 |
| -o, -m, --retry, --proxy | 無視 | — | ローカルの出力パス、タイムアウト、リトライ回数、プロキシ設定には生成されるリクエストでの対応物がないため、誤って変換する代わりに受け取って破棄します。 |
| 出力サイズ | バイト | 256 KB | コマンドはもともと短いものです。この上限は、貼り付けられたファイルをトークン化するのではなく拒否するために設けています。 |
よくある質問
ChromeやFirefoxのDevToolsからコピーしたコマンドにも対応していますか?
はい。このツールに持ち込まれるコマンドの主な発生源です。DevToolsはシングルクォートで囲まれた引数、その間のバックスラッシュ+改行による行継続、そして多くの場合`--compressed`フラグと長いCookieヘッダーを出力します。3つとも処理されます。行継続は内容ではなく改行として扱い、--compressedはここで扱うどのクライアントも自身で圧縮をネゴシエートするため記録のうえ破棄し、-bはCookieヘッダーになります。
-d @payload.jsonはどうなりますか?
生成コードはファイル名を示すだけで、読み込みの完了はユーザーに委ねられます。インライン化は不可能です。ファイルの中身はコマンド内に存在せず、プレースホルダーのボディをでっち上げると、誤ったペイロードを黙って送信するコードになります。このバグは実際のAPIに対してのみ顕在化します。このツールは推測ではなく、検出したファイルをその名前で伝えます。
-kが引き継がれないのはなぜですか?
安全でないフラグをコピーしてしまうことが、それが本番環境へ到達する経路だからです。生成コードは証明書検証を有効のまま保ち、元のコマンドで無効化されていた旨をコメントで示します。判断が可視化され、意図的なもののままでいるためです。本当に必要な場合は、コメントが変更箇所を案内します。Nodeであれば環境変数1つで対応でき、コードの変更は不要です。
シェル変数やエスケープされた文字はどう処理されますか?
変数は書かれたまま残ります。コマンドを貼り付ける時点でシェルによる展開はすんでおり、テキスト中に$TOKENという文字が残っているなら展開されなかったことを意味するため、目に見えるプレースホルダーとして保たれます。エスケープは正しく解釈されます。ダブルクォート内ではバックスラッシュがエスケープするのはPOSIXが定める5文字だけで、シングルクォート内では何もエスケープされず、$'…'はANSI-Cクォーティングで\nは実際の改行になります。
どの変換先を選べばよいですか?
コードの行き先がブラウザかNode 18+ならfetchです。現在はこのケースが大半です。プロジェクトがすでにaxiosを使っているならaxiosを選びます。JSONのシリアライズとエラーステータスの処理を任せられるためです。スクリプトにはPython requests、サービスにはGo、コードベースがそうであればPHPやRubyが適します。6つとも同じリクエストを生成し、異なるのは言語ごとに必要な記述の量だけです。
入力したコマンドはどこかに送信されますか?
いいえ。解析も生成も、このタブの中で実行されます。curlコマンドには有効なAPIキー、セッションCookie、ベアラートークンが含まれていることが珍しくないため、これは重要です。上のサンプルにあるAuthorizationヘッダーがまさにそれです。送信されるデータは何もなく、送信先となるAPIルートも存在しません。