WebAPIリクエスト仕様書としてcurlコマンドのご提案

WebAPIの仕様を記述する方法はいくつかあると思う。

- 普通に日本語で記述する
- JSON Hyper-Schema、WADL、RAML、Swaggerなどを使う
- 仕様書の代わりにプログラムを書く
- HTTPメッセージそのものを記述しておく

でも、文法にばらつきがあったり、読みにくかったり、ツールのセットアップが面倒だったり、どれもイマイチな所があって、手軽な方法が欲しいと思っていた。

何気なくcurlコマンドのオプションを調べていたら、「もうこれでAPIドキュメント扱いにしちゃえばいいんじゃね？」と思えてきたのでメモしておく。

# curlコマンドのおさらい

curlコマンドはlibcurlの付属コマンドで、最近のUnix系OSなら大抵最初から入っていると思う。コマンドの詳細はmanを読んでいただければ。
[cURL - How To Use （マニュアルページ日本語訳）](http://archive.fo/ZjQfk)

curlコマンドのオプションは、短いもの(`-X`など)と長いもの(`--request`など)がある。
短い方のオプションは、命名規則に脈絡がなくて覚えにくい。
大文字小文字を間違えると全然違う意味になったりする。まずは長い方のオプションで覚えるとよい。

単にURLを指定すると、そこへGETリクエストを投げ、結果を標準出力に出力する。

```bash
$ curl 'http://packagist.jp/packages.json'
```

## --verbose (-v)

通信中のHTTPヘッダなどを詳細に表示するオプション。出力先はstderrなのでパイプに影響しないし、とりあえずつけておくとよい。

```bash
$ curl 'http://packagist.jp/packages.json' \
--verbose 
```

## --get + --data / --data-urlencode
GETで、URLのクエリ部にパラメータを渡す形式はよくあると思う。
`http://example.com/search?q=webapi&page=25`
このURLを前もって作ってcurlに渡してもよいのだが、日本語や半角スペースのURLエンコードを考えると、手書きしやすい形式ではない。
curlのオプションを活用した方が読みやすいと思う。

```bash
$ curl 'http://example.com/search' \
--verbose \
--get \
--data-urlencode 'q=ウェッブサービス' \
--data 'page=25'
```

--dataや--data-urlencodeは複数回指定することができる。
--data-urlencodeは値の部分をURLエンコードしてから送信してくれる。便利。

## --request POST + --data / --data-urlencode
POSTで、application/x-www-form-urlencoded形式でデータを送る場合にも、同じようにパラメータを指定できる。

```bash
$ curl 'http://example.com/entries' \
--verbose \
--request POST \
--data-urlencode 'title=特報記事' \
--data-urlencode 'description=ブログ記事です' 
```

ちなみに--data系オプションをいきなり指定すると、勝手にPOSTだと判断してくれるので`--request POST`は省略可能だ。わかりやすくするために明示してもよい。
`--request`は短く書くと`-X`になる。

## --data-binaryでapplication/jsonの送信

POSTやPUT、PATCHでapplication/x-www-form-urlencoded以外の形式を使いたい場合は、--data-binaryを使う。この際、--headerでContent-Typeを指定するのを忘れずに。

```bash
$ curl 'http://example.com/entries' \
--verbose \
--request POST \
--header 'Content-Type: application/json' \
--data-binary '{"title":"hoge","description":"fuga"}'
```

他のファイルを直接送信したい場合は、「@」の後ろにファイル名で指定する。

```bash
$ curl 'http://example.com/entries' \
--verbose \
--request POST \
--header 'Content-Type: application/json' \
--data-binary @example.json
```

## --header (-H)
任意のHTTPヘッダを追加したい場合に使う。複数回指定可能。いくつかよく使われるヘッダは専用オプションが用意されている。

```bash
$ curl 'http://packagist.jp/packages.json' \
--verbose \
--header 'DNT:　1'
```

### --cookie (-b)
リクエスト時に送るCookieヘッダを指定する。文字列で`A=...; B=...;`みたいに書いてもよいし、ファイル名を指定することもできる。

### --cookie-jar (-c)
Set-Cookieヘッダで返された内容をファイルに書き込む。
イメージだけど、こんな感じでログインして、cookie.txtにセッションCookieを書きこんでおき、

```bash
$ curl 'http://example.com/login' \
--verbose \
--data user=MyName \
--data pass=pAssw0rd \
--cookie-jar cookie.txt
```

保存されたCookieを--cookieオプションで流用して別のリクエストを試したりできる。

```bash
$ curl 'http://example.com/myprofile' \
--verbose \
--cookie cookie.txt
```

### --user-agent (-A)
リクエスト時に送るUser-Agentヘッダを指定する。

### --referer (-e)
リクエスト時に送るRefererヘッダを指定する。

## --resolveで/etc/hostsをべた書きする
WebAPIのサーバー設定がバーチャルホストになっていて、開発環境へのアクセスも本番のドメインを使わないとうまく動かない、なんてパターンもよくあると思う。curlには--resolveというオプションがあって特定のホスト名を強制的に特定のIPアドレスに解決させることができる。
要するに/etc/hostsをオプションにべた書きしていくことができるのだ。

```bash
$ curl 'http://example.com/api/data' \
--verbose \
--request POST \
--data 'hoge=fuga' \
--resolve 'example.com:80:127.0.0.1'
```

`<domain>:<port>:<ip>`という形式で指定する。
特にhttpsの場合にも使えるので便利。複数回指定することもでき、リダイレクト後のURLにも適用したい場合などには使える。

だいたいこんな感じだろうか。
冒頭でも書いたけど詳細はmanにすべて書いてある。
[cURL - How To Use （マニュアルページ日本語訳）](http://archive.fo/ZjQfk)

# curlのconf構文をWebAPIリクエストのドキュメントにしてしまおう
以上のコマンドそのものを、簡易的なドキュメント扱いしてもよいけれど、改行を「\」でエスケープしたり、変数を使ったりはbashの機能なので、このままではWindowsから使えず不評だと思う。

シェルコマンド形式以外に、curl自身に組み込まれたconf形式を使うこともできる。こちらはcurlコマンドさえあれば環境を問わず動くので、より好ましい。

conf形式といっても、コマンドラインオプションから「--」を取って、オプション名と値の間に「=」を加え、そのまま並べたような感じで単純。

```ini:searchapi.conf
#!/usr/bin/curl --config
# vim: set ft=dosini:
#
# 検索API(GET)リクエスト仕様
#
verbose
get

url = http://example.com/search

# リクエストパラメータの定義

## qは検索したい文字列を指定します。UTF-8です。
data-urlencode = "q=検索API"

## pageは先頭から何ページ目かを表すパラメータです。
data = "page=1"

# ステージング環境の定義
# (本番環境を試す場合は以下をコメントアウトして下さい)
resolve = example.com:80:xxx.xxx.xxx.xxx
```

実行するときは--config (-K)オプションでconfファイルを渡せばよい。

```bash
$ curl --config searchapi.conf
```

「#」でコメントを書くこともできるので、JSON系の仕様記述よりも便利だ。

curlという限られたことしかできないプログラムへの指示書なので、汎用的なスクリプト言語よりも表記ゆれが少なく、しかも主要な環境で実際にリクエストを試すことができる。
そして何より手軽だ。

WebAPIへのリクエストする方法のドキュメントとして使える気がする。
(レスポンス仕様は書けないので、別途JSON SchemaやRELAX NGなどがあるといいだろう）

# 補足

## Windowsでcurlコマンドを使う方法
curlが何となく敬遠されるのはWindowsで最初から入ってないからだと思う（偏見）。

実は公式サイトには、有志がビルドしたバイナリの案内が出ている。
http://curl.haxx.se/download.html
↑下の方にいくつかあるので、好きなのを使うとよい。ダウンロードしたcurl.exeをどこかパスの通った場所に置けば、コマンドプロンプトやPowerShellでcurlコマンドが使えるようになる。CygwinやMinGWは不要である。

ただし、PowerShellは「curl」がInvoke-WebRequestコマンドレットのエイリアス(別名)として組み込まれてしまっているので、うまく動かない。リネームしておくか、curl.exe と拡張子込みで指定すると動いてくれる。

```ps1
> curl.exe 'http://packagist.jp/packages.json' `
--verbose
```

## --libcurlオプションがすごい
--libcurlオプションを付けると、それと同じことを行うC言語のソースコードを出力してくれる。すごい。

```bash
$ curl 'http://packagist.jp/packages.json' --libcurl get-packages-json.c
```

```bash
# コンパイルして実行
$ gcc -lcurl get-packages-json.c
$ ./a.out
```