curl の POST オプション -d と -F の違いから、改めて MIME type を学ぶ

## -d (--data) と -F (--Form)

### curl -X POST -d

curl の POST オプションを -d (--data) とした場合、MIME type は `application/x-www-form-urlencoded` になります。

```shell
curl -X POST -d ‘name=taro’
```

### curl -X POST -F

続いて -F (--Form) オプションを使う場合、MIME type は `multipart/form-data` になります。

```shell
curl -X POST -F ‘name=taro’
```

これら２つの MIME type が使われるシーンは主に `HTML フォーム <form>` を使う時です。

```html
<form enctype="application/x-www-form-urlencoded"/>
<form enctype="multipart/form-data"/>
```

では、違いは何でしょうか？

## MIME

MIME とは `Multipurpose Internet Mail Extension` の略です。
`Mail Extension` は Mail に当初、唯一記載することができた ASCII 英数字以外のデータ (各国語、添付ファイルとか) を取り扱うことができる拡張仕様だったというところから来ているようです。 

## MIME type

送信先に伝える送信データの種類です。
MIME type の型はこのようになっています。

```
type/subtype; parameter (ex. text/plain; charset=UTF-8 [デフォルトでは ASCII (US-ASCII) になってます。] )
```

代表的な MIME type はこのあたりです。

```
- text/plain（プレーンテキスト）
- text/html（HTML）
- application/xhtml+xml（XHTML）
- image/gif（GIF）
- image/png（PNG）
- video/mpeg（MPEG）
- application/octet-stream（任意のバイナリデータ）
- message/rfc822（RFC 822形式）
```

## 個別型 (discrete) とマルチパート型 (multipart)

### 個別型 (discrete)

実は、上に書いた代表的な MIME type は全て個別型と言われる type です。
個別型は単一の種類の ファイル、メディアを表す type です。

上にも書きましたが代表的な個別型の type は以下です。

- application: type が明確ではない、あらゆる種類の binary data 。
`application/octet-stream (汎用的な binary data)`, `application/pdf`, `application/pkcs8`, `application/zip` など。

- text: テキストのみのデータ。人間が読める。
- audio: 音声データ。
- image: 画像データ。
- video: 動画データ。
- model: 三次元オブジェクトデータ。

### マルチパート型 (multipart)

マルチパート型とは、複数の種類のデータを含む type です。
典型的なところだと、`multipart/alternative` で、HTMLメールで HTML とプレーンテキストという異なる種類のデータを送る時に使います。

## curl の POST オプション -d と -F の違い

知識が揃ったのでタイトルに戻ります。

`curl -X POST -d` を使った時、MIME type は `application/x-www-form-urlencoded` になります。
`application` は `個別型` の type ですので、単一のデータを送りたい時に使います。 
送信されるデータは `key1=value2&key2=value2` という形式で、渡す `value` は URL encoding (percent-encoding) されていることが期待されます。
送信データが `name=taro%25&age=10` だとすると、受け取るデータは `name: taro!, age: 10` のような感じです。

`curl -X POST -F` を使った時、MIME type は `multipart/form-data` になります。
`multipart` は `マルチパート型` の type ですので、複数種類のデータを送りたい時に使います。
具体的に言うと、`ファイルなどの binary data とテキストを同時に送る時`などです。
ドキュメント形式は複数の部分から成り、boundary と呼ばれる `--` で始まる文字列によって区切られます。それぞれの部分は固有になっていて、固有の HTTP ヘッダーとして `Content-Disposition` やファイルアップロードのフィールドには `Content-Type` を持ちます。
送信データは以下のようなイメージです。

```
Content-Type: multipart/form-data; boundary=-----boundary

-----boundary
Content-Disposition: form-data; name="TestTextField"

Test
-----boundary
Content-Disposition: form-data; name="sampleFile"; filename="sample.txt"
Content-Type: text/plain

Sample file.
-----boundary
```

## まとめ
- `curl -X POST -d` の MIME type は `application/x-www-form-urlencoded`
- `application/x-www-form-urlencoded` は `個別型` の MIME type で、短い文字列などの単一の種類のデータを POST したい時はこちらを使った方がいい。
- `curl -X POST -F` の MIME type は `multipart/form-data`
- `multipart/form-data` は `マルチパート型` の MIME type で、文字列とファイルなどの複数種類のデータを同時に POST したい時はこちらを使った方がいい。

## おまけ①
書いていて `Content-type` と `MIME type` の違いって何だっけ...？ となったのですが、

- MIME type：データの種類
- Content-Type：データの種類を指定するヘッダーの項目
 
Content-Type は、あくまでヘッダー項目名で、中に書くのが MIME type と考えれば良さそうでした。

```
Content-Type: text/plain;
```

## おまけ②
個別型の `discrete` って記憶に定着しにくそうだなあ...と思っていたら、`離散の` という意味も含んでいました。
`「アナログは連続的、デジタルは離散的。(Analog is continuous, Digital is discrete.)」`というので覚えやすくなったはず。

## おまけ③
`curl -X POST -F (--Form)` で `@` から始まる文字列をファイルとして認識するのやめてくれ〜と困っている方はこんな記事を書いてみたのでチェックしてみて下さい。
https://qiita.com/att55/items/d216458524ab9a1839d2