cUrlの基礎

# まえがき
SwiftUIで個人開発をしています。
サーバーの情報変更などにたいする即時通知について、従量課金となるFirebaseを使わずなんとかならないものかと調べるうちに、MacのPCから直接Apple提供のAPNsを叩けそうだと気づきました。ところが、じゃぁリクエストを送りましょうとなっても、最も手軽なcUrlをいまいち理解しておりません。
cUrlについては、初歩的なところから説明している記事が少なく、いきなり枝葉末節のドキュメントから入ると全く理解が進まずハタと困りました。

そこで、Bearerのトークン込みでAPIを叩く過程で、cUrlの使い方とコードを体系的にChatGPTに説明させたので、後で別な機会に使うときのために、Qiitaにざっくりまとめます。
◎ApplePushNotifications(APNs)について気になる方は、**cUrlの説明よりも「おわりに」から読むと色々と早いと思います！**

# 目次
[1.cUrlの概要(ざっくり)](#1curlの概要ざっくり)
[2.HTTPリクエストの送信](#2httpリクエストの送信)
[3.ヘッダーの追加](#3ヘッダーの追加)
[4.cUrlのレスポンス制御(ステータスコードの確認、レスポンスの保存など)](#4curlのレスポンス制御ステータスコードの確認レスポンスの保存など)
[5.JSONデータの送信](#5jsonデータの送信)
[6.cUrlでの認証の方法](#6curlでの認証の方法)
[Tips.トークンや認証情報を設定ファイルに置いて呼び出す](#tipsトークンや認証情報を設定ファイルに置いて呼び出す)
[7.cUrlの応用テクニック](#7curlの応用テクニック)
[おわりに](#おわりに)


## 1.cUrlの概要(ざっくり)
まずcURL（Client URL）とは、コマンドラインからHTTPリクエストを送るためのツール。
リモートのサーバーとデータをやり取りするのに使われ、特にAPIのテストや自動化でよく利用される。
今回は認証付きのAppleサーバーへのリクエストを、とりあえずサーバー側の実装とかはさておきUI側だけ作って試したいので、cUrlを使いたい。

### 主な用途
- Webページの取得（GETリクエスト）
- データの送信（POST, PUT, DELETEリクエスト）
- APIのテスト
- ファイルのダウンロード・アップロード
- 認証付きのリクエスト（Basic Auth, Bearer Token）
- JSONデータのやり取り


### cUrlのメリット
- OSに依存せず動作（Windows, macOS, Linuxで利用可能）
- シンプルなコマンドでHTTPリクエストを実行できる
- 自動化スクリプトで利用しやすい

### cUrlの基本系
cURLはターミナルやコマンドプロンプトで次のように使う。
```zsh
curl https://example.com
```
これが基本形で、ここに後述のオプションをつける。
なんだカンタンじゃん！



## 2.HTTPリクエストの送信
もちろん、先ほどの基本形のコマンドだけではなく、以下のように`POST`などのメソッドを、オプションをつけることで表現することが可能。
`-X` 以外にも、よく使われるメソッドを表にまとめる。
### 主要メソッドの書き方
-Xに続けてPOSTなどのメソッドを追記する。
| メソッド | 説明 | コード例 | 備考 |
|-----------|------|----------|-----------------------------|
| **GET**    | データを取得する（デフォルト） | `curl -X GET http://example.com` | `GET` はデフォルトのため `-X GET` は不要 |
| **POST**   | 新しいデータを作成（登録） | `curl -X POST -H "Content-Type: application/json" -d '{"key": "value"}' http://example.com` | `-d` でデータを送信。Content-Type の指定が必要。|
| **PUT**    | 既存データを完全に更新（全フィールド書き換え） | `curl -X PUT -H "Content-Type: application/json" -d '{"key": "newValue"}' http://example.com` | 送信したJSONデータで完全に置き換え。Content-Type の指定が必要。 |
| **PATCH**  | 既存データを部分的に更新（指定したフィールドのみ変更） | `curl -X PATCH -H "Content-Type: application/json" -d '{"key": "newValue"}' http://example.com` | 指定したフィールドのみ変更 |
| **DELETE** | データを削除 | `curl -X DELETE https://example.com/posts/1` | idが1のデータを削除するリクエストを送信 |

<details>
  <summary>POSTとPUTの違い</summary>

- `POST` は **新規データの登録** に使われ、サーバーが新しいIDを生成する場合が多い。
- `PUT` は **既存データの完全更新** に使用され、指定したリソースを完全に上書きする。
- 例えば、`PUT /users/123` のようにIDを指定すると、そのリソース全体が置き換えられる。

</details>

### よく使われるオプション
以下のようなオプションがよく使われます。
| オプション | 説明 | コード例 | 備考 |
|----------|------|----------|------|
| `-X` | HTTPメソッドの指定（GET, POST など） | `curl -X POST http://example.com` | 上記のとおりHTTPメソッドを指定 |
| `-H` | ヘッダー情報を指定 | `curl -H "Authorization: Bearer token" http://example.com` | 複数のヘッダーを指定可能 |
| `-d` | リクエストボディ（データ）を指定 | `curl -X POST -d '{"key":"value"}' http://example.com` | `POST`, `PUT`, `PATCH` でよく使用 |
| `-o` | レスポンスをファイルに保存 | `curl -o output.json http://example.com` | `-O`（大文字）を使うとURLのファイル名で保存 |
| `-s` | サイレントモード（不要な出力を抑える） | `curl -s http://example.com` | `-sS` を使うとエラー時のみ表示 |
| `-i` | レスポンスのヘッダーを表示 | `curl -i http://example.com` | ボディと一緒にヘッダーを表示 |
| `-v` | 詳細な通信ログを表示 | `curl -v http://example.com` | デバッグ用途に便利 |



## 3.ヘッダーの追加
cURLでは`-H`オプションを使ってHTTPリクエストのヘッダーを追加することが多い。
特に、今回使いたいAPIの認証やリクエスト形式の指定などでよく使う。

### cURLで追加するヘッダーの一覧

| オプション | 説明 | コード例 | 備考 |
|-----------|------|----------|------|
| `-H "ヘッダー名: 値"` | リクエストにヘッダーを追加 | `curl -H "Accept: application/json" https://jsonplaceholder.typicode.com/posts/1` | サーバーに「JSONを返してほしい」と伝える |
| `-H "Content-Type: application/json"` | 送信データの形式を JSON に指定 | `curl -X POST -H "Content-Type: application/json" -d '{"title": "Test"}' https://jsonplaceholder.typicode.com/posts` | `POST` や `PUT` でデータ送信時に必要 |
| `-u ユーザー名:パスワード` | ベーシック認証を使用 | `curl -u user:pass https://example.com` | `-H "Authorization: Basic XXX"` でも認証可能（XXX は Base64） |
| `-H "Authorization: Bearer TOKEN"` | OAuth 認証 (Bearer Token) | `curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" https://example.com` | API での認証によく使う |
| `-H "Authorization: Bearer TOKEN"` | OAuth 認証 (Bearer Token) | `curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" https://example.com` | API での認証によく使う |
| `-H "User-Agent: 値"` | User-Agent を変更 | `curl -H "User-Agent: Mozilla/5.0" https://example.com` | ブラウザのように偽装する |
| `-H "Referer: 値"` | Referer を指定 | `curl -H "Referer: https://example.com" https://target.com` | アクセス元を偽装する |
| `-v` | 送信ヘッダーを確認 | `curl -v -H "Accept: application/json" https://example.com` | 送信ヘッダーとレスポンス詳細を表示 |

### 補足
以下のように、ヘッダーを複数追加することもよくある。
```zsh
 curl -X POST
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer TOKEN" \
      -d '{"title": "New Post"}' https://example.com/api/posts`
```

また、Authorization(認証)についてはBearerTokenを使うOAuth認証の他に、以下のようなBasic認証のケースもある。
```zsh
-H "Authorization: Basic xXxXxxxxX" https://example.com
```
蛇足だが、上記「ユーザー名:パスワード」をBase64でエンコードしたものをBasicとスペースに書かず、以下のように記載する方法の方がわかりやすい。
```zsh
curl -u ユーザー名:パスワード https://example.com
```

<details><summary>セキュリティを意識したサイトのリクエスト</summary>

トークンを直接書くと、履歴などから情報が流出する恐れもある。これは環境変数や別途設定ファイルを作成することでふせぐが、この方法は後述する。
また、なぜReferヘッダーが必要かだが、主に以下の用途でRefererをチェックしてアクセス制限などが行われる。このため、テスト時にはReferヘッダーを設定して、アクセス拒否などが起きないようにする必要が生じることがある。

#### (1)Webサイトのアクセス元を知らせる
サーバーは Refererを使って、どこからリクエストが来たのかを判別していることがある。
例えば、AサイトのリンクをクリックしてBサイトにアクセスすると、Bサイトのサーバーは Referer: https://Aサイト.com という情報を受け取る。。

```zsh
curl -H "Referer: https://example.com" https://target.com
```
✔ https://example.com からリクエストが来たように見せる。

#### (2)CSRF (クロスサイトリクエストフォージェリ) 対策
Referer を使って、正規のサイトからのリクエストかどうかをチェックすることがある。
例えば、フォームの送信時に Referer がサイト内でなければ、不正リクエストとみなす。

#### (3)画像やファイルのホットリンク対策
Referer をチェックして、外部サイトからの画像直リンクを防ぐことができます。
例えば、example.com の画像を 他のサイトで直リンクされた場合、そのリクエストのReferer を見て「自分のサイト以外なら拒否」する。

### (4)Web スクレイピングで制限回避
一部のサイトは Referer をチェックして、外部ツールからのアクセスをブロック することがあります。
Referer を 適切なURLに偽装 すれば、ブラウザからのアクセスに見せかけることが可能。

```zsh
curl -H "Referer: https://google.com" https://example.com
```
これで Google 経由のアクセスに見せかけられる。

</details>

# 4.cUrlのレスポンス制御(ステータスコードの確認、レスポンスの保存など)
cURLでリクエストを送信すると、通常は標準出力(ターミナル)にレスポンスが表示される。
ただ実際の開発やAPIテストでは、追加情報としてレスポンスの保存やステータスコードの確認などが必要になることが多いため、ここでは、レスポンスを制御するための方法を紹介する。

## 4.1ステータスコードの確認
レスポンスのHTTPステータスコード（200, 404, 500 など）を確認する方法。

### ① -i: レスポンスヘッダーごと表示
```zsh
curl -i http://example.com
```
出力例
```html
HTTP/1.1 200 OK
Date: Fri, 28 Feb 2025 12:00:00 GMT
Content-Type: text/html; charset=UTF-8
...
<html>...</html>
```
⇒ステータスコード (200 OK) やレスポンスヘッダーを含めた出力となる。

### ② -w: --write-outの略で、オプションを指定
```zsh
curl -o /dev/null -w "%{http_code}\n\" http://mulwatch.com 
```
出力例
```
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   138  100   138    0     0   1763      0 --:--:-- --:--:-- --:--:--  1792
302
```
ステータスコード(302)にも、時間などいろいろな情報が出てくる。
なおこの「%{http_code}」の部分を「%{json}」などに変えることも可能
　→https://zenn.dev/taxin/articles/curl-time-measure

## 4.2.レスポンスの保存
レスポンスのデータをファイルに保存する方法は以下の通り

### ① -o: 出力先を指定
```zsh
curl -o response.html http://example.com
```
レスポンスを response.html に保存し、標準出力には何も表示されない

### ② -O:ファイル名を自動決定
```zsh
curl -O http://example.com/index.html
```
サーバー上のファイル名 (index.html) をそのまま保存する

### ③ -s: サイレントモードでエラー出力を制御
```zsh
curl -s http://example.com
```
通常のエラーメッセージを非表示にする
レスポンスの本文のみを表示
◎ -s は -o と組み合わせて、ログ不要のスクリプト処理をする際に便利！

### ④ -v: 詳細ログ出力でデバッグ
```zsh
curl -v http://example.com
```
リクエストとレスポンスの詳細情報を表示するので、デバッグ時に役立つ

### ⑤ --fail: エラー時に何も出力しない
```zsh
curl --fail -o response.json http://example.com/api
```
404や500エラー時は、出力を無視してエラー扱いにする
成功時のみ response.json に保存する

# 5.JSONデータの送信
APIを使う際、特にPOST/PUTのリクエストでは、一般的にJSONデータを合わせて送信する。
ここでは、cURLを使ってJSONデータを含むリクエストを送信する方法を記載する。

### ① JSONデータ送信の基本形
```zsh
curl -X POST http://example.com/api -H "Content-Type: application/json" -d '{"key":"value"}'
```
解説:
-X POST → POSTメソッドを指定
-H "Content-Type: application/json" → JSONデータを送るためのヘッダー
-d '{"key":"value"}' → 送信するJSONデータ

### ② -d のJSONデータは複数行にできる
```zsh
curl -X POST http://example.com/api -H "Content-Type: application/json" -d'{
      "username": "testuser",
      "password": "securepass"
    }'
```
シェルの解釈ミスを防ぐため、JSONのキーや値はシングルクォート (') で囲むのが一般的。
ただし、Windowsのcmdからダブルクォート (") を使う必要がある。

### ③ JSONデータをファイルから送る
JSONデータを直接書くのではなく、ファイルから読み込んで送信することもできる。

```zsh
curl -X POST http://example.com/api
    -H "Content-Type: application/json"
    -d @data.json
```
data.json の中身
```json
{
  "username": "testuser",
  "password": "securepass"
}
```
-d @data.json → JSONデータをファイルから読み込む
スクリプトや自動化の際に便利！

### ④ 認証トークンを付けて送信
認証が必要なAPIでは、Authorization ヘッダーを追加することが一般的。

```zsh
curl -X POST http://example.com/api 
    -H "Content-Type: application/json"
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
    -d @data.json
```
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" → 認証トークンを追加

#### ④の補足：認証トークンを環境変数 ($TOKEN) から取得する方法

```
curl -X POST http://example.com/api 
    -H "Content-Type: application/json"
    -H "Authorization: Bearer $TOKEN" -d @data.json
```
この方法で、トークンをコマンド履歴に残さず安全に使うことができる。

### ⑤JSONの整形
JSONは、以下のようにjqコマンドで整形できる。
jqコマンドは、JSONの構文エラーがあれば教えてくれるらしい。
```zsh
curl -X POST 
    -H "Content-Type: application/json"
    -d @data.json https://jsonplaceholder.typicode.com/posts | jq .
```
受信したJSONについても、jqコマンドで整形して表示してくれる。
```zsh
curl -s http://example.com/api | jq .
```

### 追記: cURLからJSON送信時のエラー対応
ヒントとして、エラーの内容と原因・対応方法は以下の通り。
| エラー内容 | 原因 & 対応方法 |
|----------| -------------|
|415 Unsupported Media Type |	-H "Content-Type: application/json" をつけ忘れていないか確認 |
| 400 Bad Request | JSONのフォーマットが正しいかチェック (jq . data.json で確認可能) |
|401 Unauthorized | Authorization ヘッダーが正しいか確認 (Bearer のスペルミス注意)

上記エラー内容については、また別途章を立てて記載する。

### まとめ
JSONデータを送信する方法については、一旦以上とする。
その他の原因や対処は、冗長になるので折りたたみとして以下にまとめる。

<details><summary>①HTTPステータスコード別のエラー一覧</summary>

| ステータスコード         | 意味                                   | 原因 & 対策                                                                                   |
|--------------------------|----------------------------------------|----------------------------------------------------------------------------------------------|
| 400 Bad Request          | クライアントのリクエストが不正         | - JSON の構文ミスがないか確認（`jq . data.json` でチェック）<br>- 必須フィールドが不足していないか確認（API ドキュメント参照） |
| 401 Unauthorized         | 認証が必要                             | - Authorization ヘッダーを正しく指定しているか確認<br>- Bearer TOKEN のスペルミスに注意 (Bearer の後にスペース必要) |
| 403 Forbidden            | 権限が不足している                     | - API の権限設定を確認（管理者権限が必要な場合あり）                                           |
| 404 Not Found            | API エンドポイントが存在しない         | - URL が正しいか確認<br>- API のバージョン (v1, v2) が正しいか確認                            |
| 405 Method Not Allowed   | 許可されていない HTTP メソッドを使用 | - `-X POST` / `-X PUT` / `-X DELETE` の指定ミスを確認                                        |
| 406 Not Acceptable       | クライアントが要求した形式をサーバーがサポートしていない | - `-H "Accept: application/json"` を追加してみる                                             |
| 409 Conflict             | 競合エラー                             | - 同じデータを二重に登録しようとしていないか確認                                              |
| 415 Unsupported Media Type | 送信データの形式がサポートされていない | - `-H "Content-Type: application/json"` を忘れていないか確認                                  |
| 429 Too Many Requests    | リクエストの送信回数が制限を超えた     | - 一定時間待ってから再試行する<br>- API のレートリミット（制限値）を確認する                   |
| 500 Internal Server Error| サーバー側のエラー                     | - クライアント側で問題ない場合、API サーバーの不具合の可能性（運営側に問い合わせ）              |
| 502 Bad Gateway          | API サーバーが別のサーバーへリクエストし、そのレスポンスが不正 | - API の障害の可能性あり（時間を置いて再試行）                                               |
| 503 Service Unavailable  | API サーバーが過負荷・メンテナンス中   | - 一定時間後に再試行する                                                                      |
| 504 Gateway Timeout      | API サーバーがタイムアウト             | - サーバーが処理に時間をかけすぎている可能性（リクエストを軽量化してみる）                      |

</details>

<details><summary>②cURLのオプションミス</summary>

| エラーメッセージ                        | 原因 & 対応策                                                                 |
|----------------------------------------|------------------------------------------------------------------------------|
| curl: (3) bad URL                      | URL のスペルミス・`http://` や `https://` の抜けを確認                       |
| curl: (6) Could not resolve host       | ドメイン名のタイプミス or インターネット接続問題                             |
| curl: (7) Failed to connect            | サーバーがダウンしている or 接続がブロックされている                         |
| curl: (22) The requested URL returned error: 404 | API のエンドポイントが存在しない                                            |
| curl: (35) SSL connect error           | HTTPS の証明書エラー → `--insecure` オプションで回避可能（非推奨）           |
| curl: (52) Empty reply from server     | API サーバーが応答しない → リクエスト内容を確認                              |
| curl: (56) Recv failure                | ネットワークの不安定・接続が途中で切れた                                     |
| curl: (60) SSL certificate problem     | 証明書が正しくない（自己署名証明書の可能性）                                 |

</details>

<details><summary>③JSON送信時の構文エラー</summary>

| 問題                          | 修正例                                                                      |
|------------------------------|----------------------------------------------------------------------------|
| Unexpected token             | `-d '{"key":value}'` → `-d '{"key":"value"}'`（値を文字列にする）          |
| Unexpected end of JSON input | `-d '{"username":"testuser",}'` → 末尾のカンマ (`,`) を削除                |
| Invalid character            | `-d "{username:'testuser'}"` → シングルクォート (`'`) は JSON では NG → ダブルクォート (`"`) に変更 |
| Missing required field       | API の仕様を確認し、必須項目を追加                                          |
| Invalid Content-Type         | `-H "Content-Type: application/json"` を付け忘れていないか確認             |

</details>


# 6.cUrlでの認証の方法
APIにリクエストを送る際、多くの場合認証(Authentication)が必要となる。
cUrlでは、APIの認証方式に応じて適切な方法でユーザー情報やトークンを送信することができる。

主な方法は以下表の通りで、このあと一つずつ具体的なコードも交えて解説する。

| **認証方式** | **書き方 (cURL)** | **適用例** |
|-------------|-------------------------------|------------------|
| **Basic 認証** | `-u "user:pass"` | シンプルな API |
| **Bearer 認証** | `-H "Authorization: Bearer {TOKEN}"` | OAuth 2.0, JWT |
| **API キー** | `?api_key=KEY` または `-H "x-api-key: KEY"` | API のアクセス制御 |
| **OAuth 2.0** | `-H "Authorization: Bearer {TOKEN}"` | Google, GitHub API |
| **Cookie** | `-b cookies.txt` | ログイン後の API |




### ①Basic認証
HTTPのBasic認証では、ユーザー名とパスワードを送信して認証を行う。
cUrlでは -u "username:password" を指定すると、自動でBase64エンコードして送信してくれる。

```zsh
curl -u "myuser:mypassword" -X GET https://example.com/api
```
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ= ヘッダーが自動で追加される

◎パスワードを隠したい場合
```zsh
curl -u myuser -X GET https://example.com/api
```
実行後にパスワード入力を求められ、こちらの方が安全

### ②Bearerトークン認証
OAuthやAPIの認証では、Bearerトークンを使用するのが一般的。
cUrlではAuthorization: Bearer{TOKEN}を手動でヘッダー追加する。

```zsh
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" -X GET https://api.example.com/data
```
環境変数にトークンを保存して使う方法もある
```zsh
TOKEN="YOUR_ACCESS_TOKEN"
curl -H "Authorization: Bearer $TOKEN" -X GET https://api.example.com/data
```
トークンを直接コマンドに書かないため、セキュリティ向上につながる。

### ③APIキー認証
APIキーを使う認証方式では、URLパラメータまたはHTTPヘッダーにキーを追加する。

URLパラメータで送信 ※シンプルだがURLにキーが残るためセキュリティ上のリスクあり
```zsh
curl -X GET "https://api.example.com/data?api_key=YOUR_API_KEY"
```

ヘッダーで送信 ※セキュリティ面から、パラメータでよりもヘッダーで送るほうが望ましい
```zsh
curl -H "x-api-key: YOUR_API_KEY" -X GET https://api.example.com/data
```


### ④OAuth2.0の認証
OAuth 2.0 では、通常アクセストークン (Access Token) を取得し、これをBearerで送信する。
このため、まず一旦トークン取得のためのPOSTリクエストをする必要がある。

#### 1.アクセストークンの取得
```zsh
curl -X POST "https://auth.example.com/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET"
```
成功すると、以下のようにJSONレスポンスでトークンが返ってくる

```json
{
  "access_token": "abcdefg1234567",
  "token_type": "Bearer",
  "expires_in": 3600
}
```
#### 2.取得したトークンを使用してAPIリクエスト送信
```zsh
TOKEN="abcdefg1234567"
curl -H "Authorization: Bearer $TOKEN" -X GET https://api.example.com/data
```

### ⑤Cookie 認証
ログイン後のCookieを使って認証する場合、cUurでは -b を使う。

#### 1.ログインしてCookieを取得
```zsh
curl -c cookies.txt -X POST
    -d "username=myuser&password=mypass" https://example.com/login
```
cookies.txtにセッション情報が保存される

#### 2. Cookie を使って API にアクセス
```zsh
curl -b cookies.txt -X GET https://example.com/api/data
```
ログイン済みの状態でAPIにアクセスできる。

### まとめ
ここまでで、認証の方法をまとめた。
以前TwitterのAPIを叩くアプリを作ろうと思った時に、OAuth2.0も機能が限定的なBearerトークンすらも、どこから手をつけたら良いか全くわからず断念したことがあった。
そのときに、この記事があればよかったと切に思う。

なお、もし上記の認証方法でエラーが出ときのヒントとして、簡単な以下の表を載せておく。
| **エラーメッセージ** | **原因 & 解決策** |
|----------------------|------------------|
| **401 Unauthorized** | - 認証情報が間違っている <br> - トークンの有効期限切れ |
| **403 Forbidden** | - 権限が不足している <br> - API キーにアクセス制限がある |
| **`{"error": "invalid_client"}`** | - クライアント ID またはシークレットが誤っている |
| **`{"error": "invalid_token"}`** | - `Authorization: Bearer` のトークンが間違っている |

近い将来iPhoneと連携したWebシステム開発を考えているので、その際にあった発見や得られた実践ノウハウを本記事に反映できたらと思う。

## Tips.トークンや認証情報を設定ファイルに置いて呼び出す
環境変数に直接トークンや認証情報を書き込むのではなく、設定ファイルに保存し、スクリプトからそれを参照する方法をChatGPTに聞いてみた。
これによりセキュリティの向上や管理のしやすさが実現できるが、理解の本筋から少し外れるので、以下折りたたみで書いておく。

<details><summary>details</summary>

APIにリクエストを送る際、多くの場合認証(Authentication)が必要となる。  
cUrlでは、APIの認証方式に応じて適切な方法でユーザー情報やトークンを送信することができる。

主な方法は以下の通りで、このあと一つずつ具体的なコードも交えて解説する。

| **方法** | **メリット** | **デメリット** |
|----------|------------|--------------|
| `.env` ファイル | シンプルで安全。`source` で読み込める | `source .env` を手動で実行する必要あり |
| スクリプト内で `.env` を自動読み込み | `fetch_data.sh` で自動化できる | `.env` をGitに含めないよう注意 |
| `config.json` を使う | JSON形式で管理しやすい | `jq` のインストールが必要 |
| `~/.bashrc` や `~/.zshrc` に設定 | システム全体で利用可能 | APIキーを変更しづらい |

## ①.envファイルを使う
.envファイルに認証情報を保存し、シェルスクリプトやcUrlコマンドで参照する方法。

### .envファイルを作成
まず、~/.env やプロジェクトフォルダ内に.envファイルを作成し、以下のように記述する。

```sh
API_TOKEN="abcdefg1234567"
API_URL="https://api.example.com/data"
USERNAME="myuser"
PASSWORD="mypassword"
```
.envファイルは.gitignoreに追加し、Gitにアップロードしないようにする。

```zsh
echo ".env" >> .gitignore
```
.env を読み込んでcUrlを実行、
ターミナルで.envをsourceコマンドで読み込み、環境変数として適用する。

```zsh
source .env
curl -H "Authorization: Bearer $API_TOKEN" -X GET "$API_URL"
```
または、一行で .env を読み込んで実行することも可能。

```zsh
set -a; source .env; set +a;　curl -H "Authorization: Bearer $API_TOKEN" -X GET "$API_URL"
```
set -a; source .env; set +a; を使うと、.env 内のすべての変数を export した状態にできる


### ②スクリプト内で.envを自動読み込み
毎回 source .env を実行するのは面倒なため、スクリプト内で自動的に読み込む。

#### fetch_data.sh スクリプトを作成
 ```zsh
#!/bin/bash
# .env ファイルを読み込む
if [ -f .env ]; then
  export $(grep -v '^#' .env | xargs)
fi

# cUrl でリクエスト
curl -H "Authorization: Bearer $API_TOKEN" -X GET "$API_URL"
```
◎スクリプトを実行するには以下を実行しておく。

 ```zsh
chmod +x fetch_data.sh
./fetch_data.sh
```

### ③config.jsonを利用
.env の代わりに config.json 形式で管理する方法。

config.jsonを以下のように作成して保存
```json
{
  "API_TOKEN": "abcdefg1234567",
  "API_URL": "https://api.example.com/data"
}
```
jq コマンドを使って JSON から値を取得
 ```zsh
API_TOKEN=$(jq -r '.API_TOKEN' config.json)
API_URL=$(jq -r '.API_URL' config.json)

curl -H "Authorization: Bearer $API_TOKEN" -X GET "$API_URL"
```
◎jq は JSON を扱うコマンドラインツールで、インストールは以下のコマンドで可能。

 ```zsh
sudo apt install jq  # Linux(Debian/Ubuntu)の場合
brew install jq  # macOSの場合
```

### ④~/.bashrcや~/.zshrcに環境変数を設定
頻繁に使うAPIの認証情報を設定ファイルなしで保存する場合、~/.bashrc または ~/.zshrc に書き込む方法もある。

.bashrc や .zshrc に追記
 ```zsh
export API_TOKEN="abcdefg1234567"
export API_URL="https://api.example.com/data"
```
適用するために以下を実行。

 ```zsh
source ~/.bashrc  # bash の場合
source ~/.zshrc   # zsh の場合
```
その後、cUrlで環境変数を利用。

 ```zsh
curl -H "Authorization: Bearer $API_TOKEN" -X GET "$API_URL"
```
ただし、この方法はすべてのシェルで環境変数が適用されるため、APIキーを頻繁に変更する場合には向かない。

### Tipsのまとめ
以上の通り、環境変数や設定情報を直接コンソールに書かない方法をまとめた。
コンソールでは「↑」を押すと入力したコマンドが出てきてしまったり、注意して扱いたい。

| **エラーの種類**                 | **主な原因**                           | **解決策**                                           |
|---------------------------------|---------------------------------|------------------------------------------------|
| **Could not resolve host**     | URL が間違っている、DNS 解決不可 | URL を確認し、`ping` や `nslookup` を実行      |
| **403 Forbidden**              | 認証情報不足                      | `Authorization` ヘッダーを適切に設定           |
| **404 Not Found**              | URL 間違い                        | API のエンドポイントを確認                     |
| **415 Unsupported Media Type** | `Content-Type` ヘッダー不足       | `-H "Content-Type: application/json"` を追加  |
| **400 Bad Request**            | JSON フォーマットミス             | `jq` で JSON 構文をチェック                    |
| **SSL certificate problem**    | 証明書エラー                      | `-k` または `--cacert` を利用                   |


</details>


# 7.cUrlの応用テクニック
cUrlをより効果的に使うための高度なオプション・テクニックを以下にまとめる。

###  1. ファイルのアップロード
cUrlを使ってファイルをアップロードするには、-F オプションを使用する。
#### シンプルなファイルアップロード
 ```zsh
curl -X POST -F "file=@sample.jpg" https://api.example.com/upload
``` 
* -F "file=@sample.jpg" → ＠の後にファイル名を指定
* fileはAPI側で受け取るキー名
#### 複数ファイルをアップロード
 ```zsh
curl -X POST -F "file1=@sample1.jpg" -F "file2=@sample2.jpg" https://api.example.com/upload
```
#### ファイルと追加データを一緒に送る
 ```zsh
curl -X POST -F "file=@sample.jpg" -F "user_id=1234" https://api.example.com/upload
```

###  2. cURL のリクエストをファイルから読み込む
複雑なリクエストをファイルに保存し、cURLで読み込むことができる。
#### リクエストデータをJSONファイルに保存
request.json:
```json
{
  "name": "John",
  "email": "john@example.com"
}
```

#### cUrlでJSONデータを送信
 ```zsh
curl -X POST -H "Content-Type: application/json" -d @request.json https://api.example.com
```
* -d @request.json でファイルの内容を読み込む

###  3. 環境変数を利用して認証情報を隠す
APIキーや認証情報を環境変数に格納し、cUrlで使用するとセキュリティが向上する。

#### .env に認証情報を保存
~/.bashrc または ~/.zshrc に以下を追加:
 ```zsh
export API_KEY="your_secret_key"
```
適用するには…
```zsh
source ~/.bashrc  # または source ~/.zshrc
```
#### 環境変数を使ってリクエスト
 ```zsh
curl -H "Authorization: Bearer $API_KEY" https://api.example.com
```
###  4.設定ファイル(.curlrc)を利用する
頻繁に使うオプションを設定ファイルにまとめることで、毎回の入力を省略できる。
#### .curlrc の設定
~/.curlrc を作成し、以下を記述:
```sql
user-agent = "Mozilla/5.0"
header = "Authorization: Bearer your_api_token"
silent
```
* user-agent → デフォルトの User-Agent を変更
* header → 毎回 Authorization ヘッダーを追加
* silent → 進捗バーなどの表示を無効化
#### cURL 実行時に .curlrc の設定を自動適用
 ```zsh
curl https://api.example.com
特定の設定を無視したい場合:
 ```zsh
curl --config /dev/null https://api.example.com
```

###  5. cURL の並列リクエスト
大量のリクエストを送る場合、xargsやGNU Parallelを利用すると並列処理が可能となる。
#### xargs を使った並列リクエスト
 ```zsh
echo "https://api.example.com/user1
https://api.example.com/user2
https://api.example.com/user3" | xargs -n 1 -P 3 curl -O
```
* -n 1 → 1 行ずつ処理
* -P 3 → 3 並列リクエスト
#### GNU Parallel を使った並列リクエスト
 ```zsh
cat urls.txt | parallel -j 5 curl -O
```
* -j 5 → 5 並列リクエスト

###  6. HTTP ヘッダーだけ取得
レスポンスのHTTPヘッダー情報だけを取得したい場合は -I を使用する。
 ```zsh
curl -I https://api.example.com
```
出力例
```yaml
HTTP/1.1 200 OK
Date: Fri, 01 Mar 2025 10:00:00 GMT
Content-Type: application/json
Content-Length: 1234
```
###  7. レスポンスをログに保存
リクエスト・レスポンスをログファイルに記録すると、デバッグしやすくなる。
 ```zsh
curl -X GET https://api.example.com -o response.json
```
response.jsonにレスポンスの内容が保存される。
さらに詳細なログを取得するには…
 ```zsh
curl -v -X GET https://api.example.com 2>&1 | tee curl.log
```
* -v → デバッグ情報を表示
* tee curl.log → ログファイルに保存

###  8. 進捗を非表示にする
ダウンロード時の進捗バーを 非表示 にするには -s または --silent を使用する。
 ```zsh
curl -s -X GET https://api.example.com
```
エラーのみを表示したい場合
 ```zsh
curl -sS -X GET https://api.example.com
```
* -s → すべての出力を抑制
* -S → エラー発生時のみエラーメッセージを表示

###  9. タイムアウトを設定
リクエストが 長時間かかるのを防ぐ ため、タイムアウトを設定できる。
 ```zsh
curl --connect-timeout 5 --max-time 10 -X GET https://api.example.com
```
* --connect-timeout 5 → サーバーへの接続を5秒でタイムアウト
* --max-time 10 → 全体のリクエスト時間を10秒に制限

###  10. cURL をスクリプト化
シェルスクリプトを使うことで、cUrlのリクエストを自動化できる。
#### api_request.sh
 ```zsh
#!/bin/bash
API_URL="https://api.example.com"
API_KEY="your_api_key"

response=$(curl -s -H "Authorization: Bearer $API_KEY" -X GET $API_URL)
echo "API Response: $response"
```
実行権限を付与:
 ```zsh
chmod +x api_request.sh
./api_request.sh
```

# おわりに
サーバー側の実装をしなくても、PCの端末でAPIを叩けるcUrlはとても便利に感じます。
たとえばもしURIが不正だったとき、SwiftでURIの生成ミスっていたのか、そもそも叩くURIの認識が誤っていたのかなども、コンソールから叩いて-vとかで情報を得れば、切り分けが早くなるのはとてもありがたい(ホットペッパーのAPIを叩くアプリを作った時に、ここがとてもツラかった記憶がある)です。
もうしばらくして、個人開発でWebシステムに手を出す時、これは積極的に使ってみたいと思います！

※一生懸命学んだあとで気づきましたが、Appleの即時通知のAPIは、cUrlを使わなくとも
　AppleDevelopersの「CloudKit Console」を使うと簡単に発行できるのでした。
　つまり、このコンソールで通知内容を作成すると、cUrlなんて一生懸命学ばなくても、
　ターミナルで言うべき呪文を右上の「cUrl」ボタンで試せる、というオチでした。
　　→https://icloud.developer.apple.com/

　日本の記事もどの生成AIさんもFirebaseのFCNばかり案内するので非常に遠回りをしましたが、
　Swiftエンジニアの方は、この「おわりに」から読んでもらえたら幸いです。
　またAPNsに関して、[Appleの日本語ドキュメント](https://developer.apple.com/jp/help/account/configure-app-capabilities/communicate-with-apns-using-a-tls-certificate)は、古いp12を経由する方式で使えません。
　※参照先英語ドキュメントがアーカイブとなり、「Retired Document」と表示されている。
 直近のドキュメントは、このRetired DocumentにLatestとして参照されている[こちらのページ](https://developer.apple.com/documentation/usernotifications)を確認してください。
　ChatGPT、glock、Claude3.7、wrtnのいずれもハルシネーション起こして適切な回答を出してくれなかったので、Swiftエンジニアの皆様はぜひお気をつけください