はじめに
GolangでAPIの作成をしている際にハンドラがきちんと動作するか確認しながら開発をしている際に、curlでjson形式のデータをPOSTする際にうまくリクエストできず、エンコードできなかったので解決法を残しておきます。
curlコマンドとは
cURLとは、主にUNIX系OSでよく利用されるコマンドおよびプログラムの一つで、様々なプロトコル(通信手順)を用いてURLで示されるネットワーク上の場所との間でデータの送受信を行うもの。オープンソースソフトウェアとして公開されている。
API作成をしていると、HTTPリクエストをしながら作業をするシーンが多くあります。
そのときに選択肢として一つ使えるのがcurlコマンドというわけです。
詳しい使い方などはこちらを参照してください。
https://qiita.com/yasuhiroki/items/a569d3371a66e365316f
curlでのJSON形式のPOSTのコマンド
$ curl https://xxxxx.net/xxxxxx -X POST -H "Content-Type: application/json" -d '{"name":"太郎", "age":"30"}'
上記のような形で紹介されているサイトがほとんどでした。
オプション | 説明 |
---|---|
-X | HTTPメソッドの指定 |
-H | HTTPリクエストでリクエストヘッダを指定 |
-d | POST でフォームを送信する |
しかし私の環境(windows10)ではうまくいかず。。。
問題
func PostArticleHandler(w http.ResponseWriter, req *http.Request) {
length, err := strconv.Atoi(req.Header.Get("Content-Length"))
if err != nil {
http.Error(w, "cannot get content length\n", http.StatusBadRequest)
return
}
reqBodybuffer := make([]byte, length)
if _, err := req.Body.Read(reqBodybuffer); !errors.Is(err, io.EOF) {
http.Error(w, "fail to get request body\n", http.StatusBadRequest)
return
}
defer req.Body.Close()
var reqArticle models.Article
if err := json.Unmarshal(reqBodybuffer, &reqArticle); err != nil {
http.Error(w, "fail to decode json\n", http.StatusBadRequest)
return
}
article := reqArticle
jsonData, err := json.Marshal(article)
if err != nil {
http.Error(w, "fail to encode json\n", http.StatusInternalServerError)
return
}
w.Write(jsonData)
}
上記コードにおいて、エンドポイントは/articleで,メソッドはPOSTのみ受け付けます。
そのため、ターミナル上で
curl http://localhost:8080/article -X POST -d '{"title" : "a","contents":"b","user_name":"c"}'
とコマンドを入力すると結果は以下のようになりました。
//結果
{"article_id":0,"title":"","contents":"","user_name":"","nice":0,"comments":null,"created_at":"0001-01-01T00:00:00Z"}
このようにうまくいかず。。。
POSTで送信しているはずの「title」「contents」「user_name」がデータとして入っていないことがわかります
解決策
上記コマンドを
curl http://localhost:8080/article -X POST -d "{\"title\":\"a\",\"contents\":\"b\",\"user_name\":\"c\"}"
このように変更すると
//結果
{"article_id":0,"title":"a","contents":"b","user_name":"c","nice":0,"comments":null,"created_at":"0001-01-01T00:00:00Z"}
さっきは入ってなかったデータが入ってます!!
このようにwindowsでは二重引用符「"」の前にエスケープ「\」をつけてエスケープする必要があるようです。
原因
そもそもJSONというのはkey-value型のデータ形式であり、
{
"Key": "Value",
"キー": "値",
"Key1": "Value1"
}
このような記述になります。
また、コマンドプロンプトにおいて文字列を渡す場合は二重引用符「"」を付ける必要がある。
このことから、失敗していたコマンドでは"title"や"a"をただの文字列だと認識し、JSON形式のデータだと認識していなかったようです。
(コマンドプロンプトで{"title":"a"}と入力しても「title」と「a」という文字列と認識(?)されてしまう。)
つまりコマンドプロンプト側に二重引用符「"」も含めてデータなんだと認識させる必要があります。
ここで「"」としてエスケープすることで二重引用符「"」を認識してくれるようになったのです。
(自分が調べた感じこのような解釈になりました。間違っていたり、知見がある方は教えてください!!)
最後に
エラー文が出てくれないのでなかなか解決しづらいエラー(?)でした。
コマンドではこのようにOSで差異が出てしまうと感じたため、クライアントツールを導入しました!
それでは、みなさん楽しいエンジニアライフを!