curlコマンドを試しながら学んでみる

## はじめに
業務でcurlコマンドを使用する必要があるため、その学習メモになります。
実際にコマンドを叩きながらまとめましたので、同じような境遇の方の参考になれば幸いです。

## curlとは
正式名称：**cURL (Client for URL)**
>cURL （client for URL）とは、 Linux などの UNIX系OS でよく利用される コマンドラインツール の一つで、 URL で示される ネットワーク 上の場所に対して様々な プロトコル (通信手順)を用いて アクセス できるもの。 MITライセンス に基づき オープンソースソフトウェア として公開されている。

HTTPやFTPなどのプロトコルを使用して、サーバに対してデータの送受信を行うコマンドということがわかります。
curlの使用用途としては、APIを叩いたり、サーバに対してリクエストを行いレスポンスを確認することが多いです。

## 準備
:::note info
macOSで実行していきます。
:::
### version確認
curlコマンドがインストールされているか確認できます。
```bash
curl --version
```
バージョンが確認できれば準備完了です。
```bash
curl 8.7.1 (x86_64-apple-darwin22.0) libcurl/8.7.1 (SecureTransport) LibreSSL/3.3.6 zlib/1.2.11 nghttp2/1.51.0
Release-Date: 2024-03-27
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps mqtt pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS GSS-API HSTS HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz MultiSSL NTLM SPNEGO SSL threadsafe UnixSockets
```
---
今回の記事では以下のサイトを使用してGET・POSTを試します。
https://httpbin.org/

上記サイトのURLに対してリクエストを行うと、レスポンスを返してくれます。
自分でAPIサーバを作る必要がないので、コマンドを試す際に便利です。


## 構文とオプション
### 基本構文
```
curl [オプション] [URL]
```

改行したい場合は以下のように`\`を入れます。
```bash
curl -X GET \
> -I 'https://httpbin.org/get'
```
### `-X`：HTTPリクエストの指定
#### GET
```bash
# デフォルトがGETなので、-Xをつけなくてもいい
curl 'https://httpbin.org/get'

curl -X GET 'https://httpbin.org/get' 
```

<details><summary>レスポンス</summary>

```bash
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c90df3-6d2591cb23f7596d5d7dcffe"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/get"
}
```
</details>

#### POST
```bash
curl -X POST 'https://httpbin.org/post'
```
<details><summary>レスポンス</summary>

```bash
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c90ce4-42e4398a0e790f263dbeb372"
  }, 
  "json": null, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/post"
}
```
</details>

### `-H`：ヘッダーの追加
#### GET
```bash
curl -H "content-type: application/json" 'https://httpbin.org/get'
```
<details><summary>レスポンス</summary>

```bash
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c94239-6725112e266c77be1904a9f8"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/get"
}
```
</details>

#### POST
```bash
curl -X POST -H "content-type: application/json" 'https://httpbin.org/post'
```
<details><summary>レスポンス</summary>

```bash
# レスポンス
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c94239-6725112e266c77be1904a9f8"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/get"
}
```
</details>

### `-d`：データの送信
#### POST
```bash
curl -X POST \
> -H "content-type: application/json" \
> -d '{"first_name":"Tarou","last_name":"Yamada","age":"20"}' \
> 'https://httpbin.org/post'
```
ver7.82.0以降なら以下のように`--json`で`-H`と`-d`を使用せずにjsonデータを送信できるようです。`-X`もいらないのでかなりスッキリして見やすいです。
今回は昔からある上記のコマンドで試していきます。
```bash
curl --json '{"first_name":"Tarou","last_name":"Yamada","age":"20"}' \
> 'https://httpbin.org/post'
```

https://qiita.com/ko1nksm/items/30982a5f357f26ae166f#restful-api-%E3%81%AE%E8%A9%B1
<details><summary>レスポンス</summary>

```bash
{
  "args": {}, 
  "data": "{\"first_name\":\"Tarou\",\"last_name\":\"Yamada\",\"age\":\"20\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "54", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c944bc-33471697605a48e957157a5c"
  }, 
  "json": {
    "age": "20", 
    "first_name": "Tarou", 
    "last_name": "Yamada"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/post"
}
```
</details>

### `-I`：レスポンスヘッダーのみを出力
#### GET
```bash
curl -I 'https://httpbin.org/get'
```
<details><summary>レスポンス</summary>

```bash
HTTP/2 200 
date: Thu, 06 Mar 2025 06:48:50 GMT
content-type: application/json
content-length: 254
server: gunicorn/19.9.0
access-control-allow-origin: *
access-control-allow-credentials: true
```
</details>

#### POST
```bash
curl -X POST -I 'https://httpbin.org/post' 
```
<details><summary>レスポンス</summary>

```bash
HTTP/2 200 
date: Thu, 06 Mar 2025 06:51:45 GMT
content-type: application/json
content-length: 318
server: gunicorn/19.9.0
access-control-allow-origin: *
access-control-allow-credentials: true
```
</details>

### `-i`：レスポンスヘッダー・ボディーを出力
#### GET
```bash
curl -i 'https://httpbin.org/get'
```
<details><summary>レスポンス</summary>

```bash
HTTP/2 200 
date: Thu, 06 Mar 2025 06:53:35 GMT
content-type: application/json
content-length: 254
server: gunicorn/19.9.0
access-control-allow-origin: *
access-control-allow-credentials: true

{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c9466f-1a0dd9443a036c5e472e9fbe"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/get"
}
```
</details>

#### POST
```bash
curl -X POST \
> -H "content-type: application.json" \
> -d '{"first_name":"Tarou","last_name":"Yamada","age":"20"}' \
> -i 'https://httpbin.org/post' 
```
<details><summary>レスポンス</summary>

```bash
HTTP/2 200 
date: Thu, 06 Mar 2025 07:10:58 GMT
content-type: application/json
content-length: 527
server: gunicorn/19.9.0
access-control-allow-origin: *
access-control-allow-credentials: true

{
  "args": {}, 
  "data": "{\"first_name\":\"Tarou\",\"last_name\":\"Yamada\",\"age\":\"20\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "54", 
    "Content-Type": "application.json", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c94a82-42f3c8850c0b5edb7ce8a7b3"
  }, 
  "json": {
    "age": "20", 
    "first_name": "Tarou", 
    "last_name": "Yamada"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/post"
}
```
</details>

### `-v`：HTTP通信の詳細を出力
#### GET
```bash
curl -v 'https://httpbin.org/get'
```
<details><summary>レスポンス</summary>

```bash
* Host httpbin.org:443 was resolved.
* IPv6: (none)
* IPv4: 44.205.219.248, 44.196.147.43, 54.144.47.213, 34.205.201.49
*   Trying 44.205.219.248:443...
* Connected to httpbin.org (44.205.219.248) port 443
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=httpbin.org
*  start date: Aug 20 00:00:00 2024 GMT
*  expire date: Sep 17 23:59:59 2025 GMT
*  subjectAltName: host "httpbin.org" matched cert's "httpbin.org"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
*  SSL certificate verify ok.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://httpbin.org/get
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: httpbin.org]
* [HTTP/2] [1] [:path: /get]
* [HTTP/2] [1] [user-agent: curl/8.7.1]
* [HTTP/2] [1] [accept: */*]
> GET /get HTTP/2
> Host: httpbin.org
> User-Agent: curl/8.7.1
> Accept: */*
> 
* Request completely sent off
< HTTP/2 200 
< date: Thu, 06 Mar 2025 07:14:09 GMT
< content-type: application/json
< content-length: 254
< server: gunicorn/19.9.0
< access-control-allow-origin: *
< access-control-allow-credentials: true
< 
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c94b41-65631b3f2d6d993c00a431bc"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/get"
}
```
</details>

#### POST
```bash
curl -X POST \                   
-H "content-type: application.json" \
-d '{"first_name":"Tarou","last_name":"Yamada","age":"20"}' \
-v 'https://httpbin.org/post'
```
<details><summary>レスポンス</summary>

```bash
* Host httpbin.org:443 was resolved.
* IPv6: (none)
* IPv4: 44.205.219.248, 54.144.47.213, 34.205.201.49, 44.196.147.43
*   Trying 44.205.219.248:443...
* Connected to httpbin.org (44.205.219.248) port 443
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 / [blank] / UNDEF
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=httpbin.org
*  start date: Aug 20 00:00:00 2024 GMT
*  expire date: Sep 17 23:59:59 2025 GMT
*  subjectAltName: host "httpbin.org" matched cert's "httpbin.org"
*  issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
*  SSL certificate verify ok.
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://httpbin.org/post
* [HTTP/2] [1] [:method: POST]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: httpbin.org]
* [HTTP/2] [1] [:path: /post]
* [HTTP/2] [1] [user-agent: curl/8.7.1]
* [HTTP/2] [1] [accept: */*]
* [HTTP/2] [1] [content-type: application.json]
* [HTTP/2] [1] [content-length: 54]
> POST /post HTTP/2
> Host: httpbin.org
> User-Agent: curl/8.7.1
> Accept: */*
> content-type: application.json
> Content-Length: 54
> 
* upload completely sent off: 54 bytes
< HTTP/2 200 
< date: Thu, 06 Mar 2025 07:17:56 GMT
< content-type: application/json
< content-length: 527
< server: gunicorn/19.9.0
< access-control-allow-origin: *
< access-control-allow-credentials: true
< 
{
  "args": {}, 
  "data": "{\"first_name\":\"Tarou\",\"last_name\":\"Yamada\",\"age\":\"20\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "54", 
    "Content-Type": "application.json", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c94c23-11076a6c5a5dea02243fce96"
  }, 
  "json": {
    "age": "20", 
    "first_name": "Tarou", 
    "last_name": "Yamada"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/post"
}
```
</details>

### `-o`：指定したファイルに出力
#### GET
```bash
curl -o curltest.txt 'https://httpbin.org/get'
```
<details><summary>レスポンス</summary>

```bash
cat curltest.txt # ファイル確認
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c94fd3-0fe7cd3e1eb8b21b7342af3a"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/get"
}
```
</details>

#### POST
```bash
curl -X POST \                   
-H "content-type: application.json" \
-d '{"first_name":"Tarou","last_name":"Yamada","age":"20"}' \
-o curl_post_test.txt 'https://httpbin.org/post'
```

<details><summary>レスポンス</summary>

```bash
cat curl_post_test.txt # ファイル確認
{
  "args": {}, 
  "data": "{\"first_name\":\"Tarou\",\"last_name\":\"Yamada\",\"age\":\"20\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "application/json", 
    "Content-Length": "54", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c95240-33b6eb2f1fe2ad677c58d801"
  }, 
  "json": {
    "age": "20", 
    "first_name": "Tarou", 
    "last_name": "Yamada"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/post"
}
```
</details>


### `-O`：リクエスト先の名前のファイルに出力
```bash
curl -O 'https://httpbin.org/get'
```
<details><summary>レスポンス</summary>

```bash
cat get # ファイル確認
{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c950b7-2631a9ab63e41c67359a222f"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/get"
}
```
</details>

#### POST
```bash
curl -X POST \                   
-H "content-type: application.json" \
-d '{"first_name":"Tarou","last_name":"Yamada","age":"20"}' \
-O 'https://httpbin.org/post'
```
<details><summary>レスポンス</summary>

```bash
cat post # ファイル確認
{
  "args": {}, 
  "data": "{\"first_name\":\"Tarou\",\"last_name\":\"Yamada\",\"age\":\"20\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "application/json", 
    "Content-Length": "54", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/8.7.1", 
    "X-Amzn-Trace-Id": "Root=1-67c95344-62b75b132391d41b78563221"
  }, 
  "json": {
    "age": "20", 
    "first_name": "Tarou", 
    "last_name": "Yamada"
  }, 
  "origin": "***.***.***.***", 
  "url": "https://httpbin.org/post"
}
```
</details>




### `-s`：進行状況・エラー・警告を非表示
#### GET
```bash
# 間違ったURL
curl -s 'https://httpbin/get';  
```
<details><summary>レスポンス</summary>

```
# レスポンス
# 出力は空になる。
```
</details>

#### POST
```bash
# 間違ったURL
curl -X POST \                   
-H "content-type: application.json" \
-d '{"first_name":"Tarou","last_name":"Yamada","age":"20"}' \
-s 'https://httpbin/post'
```
<details><summary>レスポンス</summary>

```
# レスポンス
# 出力は空になる。
```

</details>

### `-f`：400以上のレスポンスコードを返す
curlでは400以上のエラーが返されても表示してくれません。
`-f`オプションを使用すれば、表示されます。
#### GET
```bash
curl -f 'https://httpbin.org/status/404'
```
<details><summary>レスポンス</summary>

```bash
curl: (56) The requested URL returned error: 404
```
</details>

#### POST
```bash
curl -X POST \                   
-H "content-type: application.json" \
-d '{"first_name":"Tarou","last_name":"Yamada","age":"20"}' \
-f 'https://httpbin.org/status/505'
```
<details><summary>レスポンス</summary>

```bash
curl: (56) The requested URL returned error: 505
```
</details>

## おわりに
実際にコマンドを叩いてみると、どんなデータがリクエストとして送られ、レスポンスとして返ってくるのかわかりやすかったです。
curlには今回紹介したオプション以外にも、大量のオプションが存在しています。
今後の業務では認証周りを触ることになりそうなので、そのあたりのコマンドも学習していこうと思います。

## 参考資料
https://qiita.com/kojiro30/items/5ead563c44ad6086ad41


https://qiita.com/ist-a-k/items/34b408336f4ec372b139

https://qiita.com/ko1nksm/items/30982a5f357f26ae166f
 
https://e-words.jp/w/cURL.html

https://httpbin.org/#/

https://curl.se/docs/manpage.html#-f