curlコマンドでapiを叩く

# はじめに
curlコマンドを使ってapiを叩いたりするのですが、curlコマンドってただapiを叩くためのコマンドなの？みたいなレベル感でした。
業務で使ったコマンドを簡略化すると下記になるのですが、オプションの意味とかよくわからなかったので勉強がてらまとめてメモしました。

```bash
curl -k -v -A "アプリのユーザーエージェント" "uri" | jq
```

参考にしたサイトは下記のマニュアル
https://curl.haxx.se/docs/manpage.html

# curlコマンドとは
curlコマンドとは**サーバから、もしくはサーバへデータ転送を行うコマンド**です。
curlコマンド自体はapiを叩くためだけに存在しているわけではないです。

httpリクエストができるコマンドなのかなーって思ってたのですが、実際には
HTTPやHTTPSといったプロトコルに対応しているため、GETでAPIを叩いたりすることができるというだけで、
curlコマンド自体はFTP,SFTP,LDAP,TELNETなど多くのプロトコルに対応しています。

下記の書式でコマンドが実行できます。

```bash
curl [options] [URL]
```

# jqコマンド
curlとは関係ないが、curlでapiを叩く時に一緒に使うと便利です。
jqコマンドは入力を受け取り、出力を生成するフィルタの役割を果たします。

特定のデータを抽出したり整形したりできるのですが、今回は整形して見やすくするためだけに使用します。

インストールはhomebrewでできます。

```bash
brew install jq
```

実際に何が違うかというと
jqコマンドなし

```bash
echo '{"message": null, "results": [{"address1": "高知県", "address2": "南国市"}], "status": 200}';

{"message": null, "results": [{"address1": "高知県", "address2": "南国市"}], "status": 200}
```

jqコマンドあり

```bash
echo '{"message": null, "results": [{"address1": "高知県", "address2": "南国市"}], "status": 200}' | jq;

{
  "message": null,
  "results": [
    {
      "address1": "高知県",
      "address2": "南国市"
    }
  ],
  "status": 200
}
```

もう少し詳しい内容についてはこちらに書きましたのでよければ合わせてご確認ください。
[jqコマンドでjsonから必要なデータのみを取得する](https://qiita.com/bunty/items/a769ebabbdd324ff0d6f)

# 便利なオプション
## HTTPヘッダを出力させる
「-i」 HTTP ヘッダを出力に含めます。
「-I」 HTTP ヘッダのみを取得します。

```bash
curl -I "http://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060"

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
X-Cloud-Trace-Context: f49b7a1f7109801bca6e70de691430a3
Date: Sat, 17 Dec 2016 05:37:51 GMT
Server: Google Frontend
Content-Length: 290
```

### ちなみにjqコマンドとの併用はできない

```bash
curl -I "http://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060" | jq 

parse error: Invalid numeric literal at line 1, column 9
```

jqコマンドで扱える形式はjsonだからです。

## リクエストのヘッダとレスポンスのヘッダを表示する
「-v」を指定することで、リクエストとレスポンスのヘッダを表示できます。

## ユーザーエージェントを指定
「-A」 "ユーザーエージェント"　を指定することで、特定のユーザーエージェントでのリクエストであると認識されます。
例えばアプリからAPIを叩く挙動を確認したい時に使用できます。

```bash
curl -A "ユーザーエージェント" "http://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060"
```

## SSL/TLSのエラーをスキップする
「-k」を指定するとSSL/TLSのエラーをスキップできます。（安全でないSSL/TLS接続を行う）
オレオレ証明書なんかを使用している時に「-k」オプションをつけます。

### オレオレ証明書とは
正式には自己署名証明書と呼ばれています。
公開鍵に署名をする際に、その公開鍵に対応した秘密鍵で署名を行った公開鍵証明書のことです。
通常はサーバ証明書は「信頼できる認証機関」が署名を行うのですが、それを自分で署名を行っているため、オレオレ証明書と呼ばれています。

## POST
APIに対してPOSTでリクエストを行う場合には```-X POST```を指定する。
パラメータをつけてPOSTでリクエストを行う場合には、```-d```でパラメータを指定する。

```bash
curl -X POST [url] -d "name=hoge"
curl -X POST [url] -d "name=hoge&age=20"
```

## 結果に応じてコマンドを実行
Software Designでcurlコマンドの使い方が紹介されていたのですが、特定の結果が返ってきた場合に何かコマンドを実行させる(再起動など)という使い方もあるそうです。

```bash
$ curl --silent "http://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060"
{
	"message": null,
	"results": [
		{
			"address1": "高知県",
			"address2": "南国市",
			"address3": "蛍が丘",
			"kana1": "ｺｳﾁｹﾝ",
			"kana2": "ﾅﾝｺｸｼ",
			"kana3": "ﾎﾀﾙｶﾞｵｶ",
			"prefcode": "39",
			"zipcode": "7830060"
		}
	],
	"status": 200
}
$ curl --silent "http://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060" | grep "北海道" >/dev/null 2>&1 && echo "hoge"
$ curl --silent "http://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060" | grep "高知県" >/dev/null 2>&1 && echo "hoge"
hoge
```

# その他
関連するものをいろいろと
## 改行
curlに限ったことではありませんし、なにを当たり前のことをと言われそうですが、昔の自分は知らなかったので
オプションをいくつかつけていると、長くなってしまうため `\` で改行するとわかりやすいです。

```bash
$ curl -s -X GET "url" \
	-H "accept: application/json" \
	-H "toke: *****" \
	-H "id: *****" | jq
```

## jqコマンドで必要なデータのみを取得する
先ほどのzipcodeのレスポンスから、address1だけを抜き出したい場合は下記のように書くことができます。
APIのレスポンスで一部のデータのみ知りたい場合はうまく使えると見やすくなりますね！

```bash
$ curl --silent "http://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060" \
  | jq -c '.results[] | [.address1]'
["高知県"]
```

詳細はこちらが参考になるかなと思います！
[jqを活用してAPIレスポンス等から欲しい情報だけを抽出する【中級編】](https://dev.classmethod.jp/tool/road-to-jq-master-apprentice/)

## 下位10％のダメなエンジニアにだけ解けないパズル
前に話題になったらしい問題です。[こちら](http://challenge-your-limits.herokuapp.com/)から試せます。
最低限のcurlの知識があればできるのでやってみてください。
正解が欲しい方は下位10％の〜で検索してもらえればいろいろと出てくると思います。


## Postman
Chromeの拡張機能として提供されています。
[Postman](https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop/related?hl=ja)

json形式で記載されている仕様書があり、それをコマンドにするよりも、そのままコピペしたかったのでこちらを使用していました。
登録もできるので、よく使うものはこちらに登録するのも良いと思います。

<img width="1272" alt="スクリーンショット 2018-02-01 19.45.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/144753/11b98325-8309-6754-2e60-a0369be711c5.png">

## IDEのHTTPクライアント
PhpStormを使っているのでPhpStormのHTTPクライアントを使っています。
コード補完もしてくれるので便利です。詳細は下記のドキュメントを確認してください。
[PhpStormコードエディタのHTTPクライアント](https://pleiades.io/help/phpstorm/http-client-in-product-code-editor.html#creating-an-http-request-file)
[![Image from Gyazo](https://i.gyazo.com/044865d757dcee631b86c67aca3dfa79.gif)](https://gyazo.com/044865d757dcee631b86c67aca3dfa79)

## ブラウザからcurlコマンドをコピー
デベロッパーツールのネットワークから、一番上のリクエストを選択して右クリックをします。(chrome)
copy as curlを選択するとcookie情報等もオプションで指定されたcurlコマンドを生成してくれます。

![Screen Shot 2020-09-19 at 10.57.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144753/5d08add1-d8aa-d207-f6f5-ee22a90ae21e.png)


```bash
curl 'https://qiita.com/' \
  -H 'Upgrade-Insecure-Requests: 1' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36' \
  --compressed
```


## スニペットツール
apiを作るときに自分で開発期間中に何度かapiを叩くことがあります。
その都度書くのはめんどくさいので、Clipyというスニペットツールに登録をしていつでもすぐにapiを叩けるようにしていました。(最近はHTTPクライアント使ってます)
[【参考】クリップボード拡張Macアプリ「Clipy」を公開しました](https://qiita.com/econa77/items/1848bf3fdfb7127ca9b8)

# まとめ
オプション数はかなり多いので、使うときは色々と調べながらやると良いですね。
これに限った話ではありません、同じコマンドをなんども書かないようなツールの選定や工夫も必要だなと書いてて改めて思いました。