初心者になりますが、上記の記事を使ってAPIサーバーの作成を実践、自分なりにパッケージ等を調べて解説してみました。
概要
GolangでRESTサーバを起動し、POSTメソッドを受け付けるAPIを作成しました。(用語の使い方あってる?)
go-json-rest
パッケージを利用して、JSON形式のデータをやりとりする。
- httpieを使って
localhost:9999/hello
にアクセス - JSON形式の
Name="gatapon"
のデータを渡す -
Hello, gatapon
のレスポンスを受け取る
環境
- go1.11.4
- HTTPie/1.0.2
そのほか参考
実践
コーディング
package main
import (
"log"
"net/http"
// githubから直接パッケージをいっポートできて便利
"github.com/ant0ine/go-json-rest/rest"
)
// 入力の定義
type postHelloInput struct {
Name string
}
// 出力の定義
type postHelloOutput struct {
Result string
}
func postHello(w rest.ResponseWriter, req *rest.Request) {
input := postHelloInput{}
// 各種バリデーションが行われている README.md参照
err := req.DecodeJsonPayload(&input)
// バリデーションで引っかかったエラーを返す
if err != nil {
rest.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if input.Name == "" {
rest.Error(w, "Name is required", 400)
}
log.Printf("%#v", input)
w.WriteJson(&postHelloOutput{
"Hello, " + input.Name,
})
}
func main() {
api := rest.NewApi()
api.Use(rest.DefaultDevStack...)
router, err := rest.MakeRouter(
rest.Post("/hello", postHello),
)
if err != nil {
log.Fatal(err)
}
log.Printf("Server started.")
api.SetApp(router)
log.Fatal(http.ListenAndServe(":9999", api.MakeHandler()))
}
実行準備
検証にhttpieを利用するのでインストール
$ brew install httpie
プログラムの実行。これでサーバが起動しAPIにアクセスができます。
$ go run server.go
2019/XX/XX XX:XX:XX Server started.
別のターミナルからhttpieを使ってアクセス
$ http -v POST localhost:9999/hello "Content-Type:application/json; charset=utf-8" Name="gatapon"
以下の内容でレスポンスが返ってくれば成功
POST /hello HTTP/1.1
Accept: application/json, */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 15
Content-Type: application/json; charset=utf-8
Host: localhost:9999
User-Agent: HTTPie/1.0.2
{
"Name": "gatapon"
}
HTTP/1.1 200 OK
Content-Length: 28
Content-Type: application/json; charset=utf-8
Date: XXX
X-Powered-By: go-json-rest
{
"Result": "Hello, gatapon"
}
内容の詳細について
ターミナルで叩いたコマンドについて振り返ります。
http -v POST localhost:9999/hello "Content-Type:application/json; charset=utf-8" Name="gatapon"
これを簡単に訳すると、以下のようなことをしています。
「localhost:9999/hello
にPOSTメソッドでJSON形式のName="gatapon"
を渡す。」
このコマンドを受け取ったサーバーの動きを見ていきます。
ファンクション:postHello()
について
// 第一引数 "Content-Type:application/json; charset=utf-8"
// 第二引数 Name="gatapon"
func postHello(w rest.ResponseWriter, req *rest.Request) {
input := postHelloInput{}
err := req.DecodeJsonPayload(&input)
if err != nil { // DecodeJsonPayload で検出されたエラーを返す
rest.Error(w, err.Error(), http.StatusInternalServerError)
return
DecodeJsonPayload
で様々なバリデーションを行なっており、当てはまった場合はエラーを返す。
- 文字列の終端まで読み込み、バイトスライス
- 文字列が0の時のバリデーション
- Json形式の文字列をパース:json.Unmarshal
便利なコンストラクタ:rest.NewApi()
NewApi()
は3つの強力なメソッドを持っており、それらを使うことで艱難にAPIサーバーを立ち上げることができます。
api := NewApi()
api.Use()
api.SetApp()
api.MakeHandler()
- api.Use => APIサーバーの環境に合わせて用意されたMiddlewareの設定ができる
- DefaultDevStack : 開発時に利用するMiddleware群
- DefaultProdStack : プロダクト時に利用するMiddleware群
- DefaultCommonStack : どちらにしても一般的に利用するMiddleware群
- api.SetApp => 主にrest.MakeRouterのrouterをセットするメソッド
- api.MakeHandler()
感想
go-json-restを使えばとても簡単にRESTfullなAPIサーバーが作成できます。
パッケージを使えば、思ったより早く簡単なアプリが作成できそう。さらにGoの深淵を覗き込みたくなってきました。MakeHandlerメソッドは内容を理解するのには時間がかかりそうなので、スルー状態...
- Useで指定したMiddlewareを取り出し、サーバで走らせる
- http.Handlerの準備を行なっている
これらを行なっているそうですが、まだ私には難しかったです。少しずつ勉強していきます。
間違いがあればご指摘ください。