Node.jsで組んだプログラムにcurlコマンドでJSONデータをPOSTしようとしてハマった

Node.js(Express)で組んだプログラムにcurlを使ってJSONデータをPOSTしようとしました。
結果どハマりしたのでメモ。

# 結論
解決してない。なんたる出オチ。
もし同じようにハマってる人がいたら俺の屍を越えてゆけ・・・！
僕は他の方法でJSONデータをPOSTする事にしました。

##### 環境
Win10+VSC@1.68+Node.js@16.14.2+Express@4.18.1
VSCのターミナルはPowerShell使用

##### やろうとしたこと
- expressで書いたプログラムにJSONデータをPOSTしてJSONデータを返す
- VSCのターミナルからcurlコマンドでJSONデータをPOST

## やったこと
さっくりExpressの公式ドキュメントを参考にPOSTデータを受け取るプログラムを書きます。
POSTして、プログラム側で受け取ったデータの中身はreq.bodyに入っている模様。
なので公式ドキュメントのreq.bodyについての項目を参照。

http://expressjs.com/ja/api.html#req.body
```
index.js

var express = require('express')
var app = express()

app.listen(3000)
console.log('Server : online')

app.use(express.json())
app.use(express.urlencoded({ extended: true }))

app.post('/', function (req, res) {
  console.log(req.body)
  res.json(req.body)
})
```
下記コマンドでサーバを起動
`
node index.js
`
↓
`
Server : online
`
### body-parserはどうした？
→最新版のExpressはbody-parserが標準で組み込まれているのでbody-parserのインストールや記述なしでOK。

これで`http://localhost:3000`にコマンドを投げる準備ができました。

## curlコマンドはInvoke-requestに置き換えられる
JSONデータPOST用のcurlコマンドはこれ
`
curl -X POST http://localhost:3000 -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"name":"tanaka"}'
`

結果
__→Invoke-WebRequest : パラメーター 'Headers' をバインドできません。__

いきなりエラーです。たまらん。
これはVSCのターミナル(PowerShell)でcurlコマンドは、PowerShellの標準搭載コマンドであるInvoke-webRequestのコマンドにエイリアスされている為。

つまり「__curl__ hogefuga」のようなコマンドを打つと「__Invoke-WebRequrest__ hogefuga」というコマンドを打ちましたねアナタ！！って自動的に解釈してくれるという事。

「PowerShell curl エイリアス」でググったり

https://devadjust.exblog.jp/22690878/

こちらのサイトさんを参考にしたりしながらエイリアスを無効化しました。
最初はプロファイル自体が存在しなかったのでファイルを作るところからやってます。

ちなみにプロファイルを置く場所は全ユーザに効くか個別ユーザだけの設定するかによって変わるようですが、全ユーザに効くようにするなら`echo $Profile.AllUsersAllHosts`のコマンドをPowerShellで打つと実際のパスが分かります。
自環境に応じて適切な場所に置いてあげて。

## curlコマンドを実行してみる
結果
__→SyntaxError: Unexpected token n in JSON at position 1
    at JSON.parse (<anonymous>) うんたらかんたら__

またエラーです。プログラムとはエラーとの戦いの歴史である。
JSON.ParseがなんたらってあるのでJSONに関する場所が怪しい？
とりあえず`app.use(express.json())`はコメントアウト、`res.json(req.body)`は`  res.send(req.body)`に置き換えてみる。

### 実行してみる
`curl -X POST http://localhost:3000 -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"name":"tanaka"}'`
__→{}__
何も入ってない。打ったcurlコマンドは先ほどと同じJSONデータをPOSTする文字列なのでそういうもんなんだろう、という事で次に進む。

### JSONじゃないデータをPOSTしてみる
```
curl -X POST http://localhost:3000 -d "tanaka"

結果
node側(console.log(req.body)の結果) → { tanaka: '' }
PowerShell側(res.send(req.body))  → {"tanaka":""}
```
JSONとして格納されてるしJSONとして返しているのかな？

調べたらres.sendとres.jsonはほぼ似た動きをするのだとか。なるほど。

### ヘッダ情報をつけないでJSON形式をPOSTしてみる
```
curl -X POST http://localhost:3000 -d "{name:tanaka}"

結果
node側(console.log(req.body)の結果) → { '{name:tanaka}': '' }
PowerShell側(res.send(req.body))  → {"{name:tanaka}":""}
```
違う、そうじゃない。

データの内容の書き方を変えてみる。
```
curl -X POST http://localhost:3000 -d "{'name':'tanaka'}"

結果
node側(console.log(req.body)の結果) → { '{name:tanaka}': '' }
PowerShell側(res.send(req.body))  → {"{'name':'tanaka'}":""}
```
違う、そうじゃない。(2回目)

色々調べてみた結果下記のcurlコマンドでJSONデータでの格納と応答を得る事ができました。
PowerShell側の引数をreq.bodyからreq.body.nameにするときちんと`tanaka`が返ってきます。

```
curl -X POST http://localhost:3000 -d "name=tanaka"

結果
node側(console.log(req.body)の結果) → { name: 'tanaka' }
PowerShell側(res.send(req.body))  → {"name":"tanaka"}
```
でもこれはJSONを渡す＆node側でJSONを受け取っていることにならないしなぁ・・・


### app.use(express.json())の封印を解いてみる

コメントアウトしていた`app.use(express.json())`を戻してさっき打ったcurlコマンドを打ってみる。
```
curl -X POST http://localhost:3000 -d "name=tanaka"

結果
node側(console.log(req.body)の結果) → { name: 'tanaka' }
PowerShell側(res.send(req.body))  → {"name":"tanaka"}
```
普通にコマンドも通ってるようなのでコメントアウトしていた部分はとりあえず問題ないとみていいのかな？
JSONデータっぽい内容を打ってみる。
```
curl -X POST http://localhost:3000 -d "{'name':'tanaka'}"

結果
node側(console.log(req.body)の結果) → { '{name:tanaka}': '' }
PowerShell側(res.send(req.body))  → {"{'name':'tanaka'}":""}
```
違う、そうじゃない(3回目)

じゃあなんですか、やっぱりヘッダが要るんですね？

```
curl -X POST http://localhost:3000 -H 'Content-Type: application/json' -d "{'name':'tanaka'}"

結果
SyntaxError: Unexpected token ' in JSON at position 1
    at JSON.parse (<anonymous>)うんたらかんたら
```
 __メイのバカ！もうしらない！！！__


## 視点を変えてみる
一通り試してみて最初のところに戻ってきたのでアプローチを変えてみます。
そもそも論としてcurlはただのツール。VSC上でJSONをPOSTできてnode.jsで書いたプログラミングの動作チェックができればいいのです。

どうやら __REST Client__ というVSCの拡張機能でHTTPリクエストを簡単に投げられる模様。

https://zenn.dev/protoout/articles/26-vscode-rest-client

### REST Clientを使ってJSONデータをPOSTしてみる
早速インストールして.httpファイルを作ってJSONデータをPOSTしてみます。
```
POST http://localhost:3000 HTTP/1.1
content-type: application/json

{
    "name": "tanaka"
}
```
```
Response
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
{
  "name": "tanaka"
}
---
node側(console.log(req.body)の結果) → { name: 'tanaka' }
```

### ちゃんとJSON受け取ってJSON返してくれてるじゃん！！

じゃあなんですか、curlコマンドが間違ってたってことですか？
Invoke-requestも試してみる？
め、めんどくせ～～～

となったところで投了です。おとなしく __REST Client__ 使います。
どうしてもcurlでJSONデータをPOSTしなきゃいけない人にとってはお力になれずすみません。
POSTできりゃいいよって人はハマったら __REST Client__ をどうぞ。