概要
Golangなんもわからない状態からREST APIを提供できるようになったので、その時の備忘録
TL; DR
github.com/julienschmidt/httprouter
を使えば簡単に作成できる
net/http
とは違い、ハンドラにわたす引数が1つ多いのでそこだけ注意
encoding/json
を組み合わせてJSONレスポンスまで作れたよ
完成物
本来は複数ファイルに分かれているけど、わかりやすさのためにまとめた
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
type StatusCode int
type Response struct {
Status StatusCode `json:"status"`
Result interface{} `json:"result"`
}
func CreateJSON (data interface{}, status StatusCode) []byte {
response := Response{status, data}
res, err := json.Marshal(response)
if err != nil {
log.Panic(err)
}
return res
}
func RenderJSONOK(w *http.ResponseWriter, data interface{}) {
RenderJSON(w, data, http.StatusOK)
}
func RenderJSON(w *http.ResponseWriter, data interface{}, status StatusCode) {
res := CreateJSON(data, status)
(*w).Header().Set("Content-Type", "application/json")
(*w.)WriteHeader(status)
(*w).Write(res)
}
func GetMessageList(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
RenderJSONOK(&w, "Call GetMessageList!")
}
func PostMessage(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
RenderJSON(&w, "coming soon", http.StatusNotFound)
}
func GetMessageById(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
RenderJSON(&w, "coming soon", http.StatusNotFound)
}
func Registration(router *httprouter.Router) {
router.GET("/message", GetMessageList)
router.POST("/message", PostMessage)
router.GET("/message/:id", GetMessageById)
}
func main() {
router := httprouter.New()
Registration(router)
err := http.ListenAndServe(":8080", router)
if err != nil {
log.Panic(err)
} else {
fmt.Println("something wrong")
}
}
解説
httprouterを使う
net/http
だけでも、メソッドごとに分割して作れなくも無いっぽいが
func Test(w http.ResponseWriter, r *http.Request) {
switch (r.Method) {
case: http.MethodGet:
case: http.MethodPost
}
}
func Registration() {
http.HandleFunc("/", Test)
}
このように記述することになる。
個人的には、Registrationの中で一発でメソッドを管理できないなど可読性が悪く感じるのでなし。
そこで、調べていたところ、12kスターが付いている github.com/julienschmidt/httprouter
を見つけた。
これを使うと、完成コードのように、
func TestGet(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}
func TestPost(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
}
func Registration(router *httprouter.Router) {
router.GET("/", TestGet)
router.POST("/", TestPost)
}
と、メソッドごとに処理を分けて記述することができる。
しかし、httprouterの基本機能として、Paramsが渡ってくる場所が別にあるため、これを受け取れるようにする必要がある。
ここまでで、自由にREST APIを作れるようになった。
ここからは、APIのレスポンスでおなじみのJSONを返すように少してを加える。
encoding/jsonを使う
encoding/json
は標準で搭載されている。
構造体に一手間加えると、JSONを返せるようになる便利パッケージ。
使い方は以下の通り
type Response struct {
Hoge int `json:"hoge"`
Fuga string `json:"fuga"`
}
func CreateJSON () []byte {
response := Response{123, "abc"}
json, err := json.Marshal(response)
if err != nil {
panic(err)
}
return json
}
これで手軽にJSON形式を生成できるので、これをhttpレスポンスにのせて上げればもう完成。
それで、あちこち関数化などをして出来上がったのが上のコード。
まとめ
便利パッケージがある!
名前わかりにくすぎる!
リファレンスちゃんと読まないと型が特定できないからドキュメントなどはちゃんと見よう!
参考にしたところ