golangでBMIを計算するAPIサーバを実装
身長 [cm]と体重 [kg]を受け取りBMIを返すAPIサーバをつくる
JSON形式の文字列をgolangで読み取る
golangでJSON形式の文字列をパースして構造体のフィールド変数に代入したり,構造体からJSON形式の文字列に変換したりする方法.
まずはJSON形式を扱うためのライブラリ"encoding/json"
をインポートする.
import ( "encoding/json" "fmt" "log" "math" )
次に,身長と体重の値が入っているJSON形式の文字列を考える.
{ "height": 170, "weight": 50 }
そして,この形式のJSONを読み取るための構造体を定義する.
type HeightWeight struct { Height int `json:"height"` Weight int `json:"weight"` }
各変数は[変数名] [型名] [文字列]
と定義する.[文字列]
はjson:"[key]"
とする.
そしてJSON形式の文字列
から構造体
に値を代入するコードは以下のようになる.
// JSON形式の文字列を定義 jsontest := `{"height": 170, "weight": 50}` // HeightWeight型の変数の定義 var heightweight HeightWeight // jsontestを読み取りheightweightの変数に値を書き込む if err := json.Unmarshal([]byte(jsontest), &heightweight); err != nil { log.Fatal(err) }
このコードは
jsontest
にJSON形式の文字列を定義HeightWeight
構造体のインスタンスheightweight
をつくるjson.Unmarshal
でheightweight
のフィールド変数にjsontest
の値を代入する.
という流れになっている.
構造体からJSON形式の文字列
先ほど読み取ったheightweight
を使ってBMIを計算してBMIの値をフィールド変数に持つ構造体のインスタンスを返す関数を作る.Bmis
という名前の構造体とcalc_bmi
という引数にHeightWeight
のインスタンスを受け取りBmis
を返す関数を定義.
type Bmis struct { Bmi float64 `json:"bmi"` } func calc_bmi(hw HeightWeight) Bmis { var bmi Bmis bmi.Bmi = hw.Weight / math.Pow(hw.Height / 100, 2) return bmi }
heightweight
を使ってBmis
のインスタンスbmi
を作成し,bmi
からJSON形式の文字列を作る.
// heightweightを使ってBmisのインスタンスbmiを定義 bmi := calc_bmi(heightweight) // bmiを使ってJSON形式のバイト配列jsonBytesを定義 jsonBytes, err := json.MarshalIndent(bmi, "", " ") if err != nil { log.Fatal(err) }
byte
型配列のjsonBytes
を文字列に変換するにはstring(jsonBytes)
で可能.
これらをまとめたコード
これを実行したら以下のようになり,heightweight
の各フィールド変数Height, Weight
にJSON文字列に含まれていた値が格納されていることを確認できる.
HeightWeight構造体 {170 50} BMIのJSON { "bmi": 17.301038062283737 }
golangでAPIサーバの実装
全体のコード
handler
関数の動作は以下のようになっている.
- HTTPリクエストを受け取り,
Body
のbyte
配列を読み込みbody
に格納 body
からHeightWeight
インスタンスhw
を生成hw
からcalc_bmi
関数でBmis
インスタンスbmi
を生成bmi
からjson.MarshalIndent
を使ってJSON
文字列を生成- HTTPレスポンスのBodyに
bmi
のJSON文字列
を書き込む
HTTPリクエストのBody読み込み部分
r.ContentLength
でHTTPリクエストのバイト長が分かるので,その長さのbyte
配列body
を用意する.
body := make([]byte, r.ContentLength)
そしてHTTPリクエストのBodyのバイト配列をbody
の要素に代入する.
length, err := r.Body.Read(body)
あとはbody
を使ってjson.Unmarshal
できる.
HTTPレスポンス部分
HTTPレスポンスのヘッダーにのcontent-type
にapplication/json
をセットしてJSON形式であることを明示する.そして,Body
にBMIのJSON形式文字列を書き込めばOK.
// JSON形式であることを明示 w.Header().Set("content-type", "application/json") // 計算したbmiをJSON形式で返す fmt.Fprintf(w, string(jsonBytes)) fmt.Fprintf(w, "\n")
curlコマンドで動作確認
go run main.go
で実行してサーバを起動して
curl -v -H "Content-Type: application/json" -X POST -d '{"height":140, "weight":50} http://localhost:5000'
すると結果が返ってくる.
Note: Unnecessary use of -X or --request, POST is already inferred. * Trying 127.0.0.1... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 5000 (#0) > POST / HTTP/1.1 > Host: localhost:5000 > User-Agent: curl/7.63.0 > Accept: */* > Content-Type: application/json > Content-Length: 27 > * upload completely sent off: 27 out of 27 bytes < HTTP/1.1 200 OK < Date: Sun, 09 Jun 2019 12:30:31 GMT < Content-Length: 34 < Content-Type: text/plain; charset=utf-8 < { "bmi": 25.510204081632658 } * Connection #0 to host localhost left intact