[Golang]RESTfulなAPIサーバー作成


[こんなに簡単! Goで作るRESTサーバー](https://qiita.com/suin/items/f32fa82d6c35a34e8d16)

初心者になりますが、上記の記事を使ってAPIサーバーの作成を実践、自分なりにパッケージ等を調べて解説してみました。

## 概要

GolangでRESTサーバを起動し、POSTメソッドを受け付けるAPIを作成しました。（用語の使い方あってる？）<br>
`go-json-rest`パッケージを利用して、JSON形式のデータをやりとりする。<br>

 1. httpieを使って `localhost:9999/hello`にアクセス
 2. JSON形式の`Name="gatapon"`のデータを渡す
 3. `Hello, gatapon`のレスポンスを受け取る

### 環境

 - go1.11.4
 - HTTPie/1.0.2
 
### そのほか参考

 - https://golang.org/pkg/
 - https://github.com/ant0ine/go-json-rest#api-and-static-files



## 実践

### コーディング

```golang:server.go
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を利用するのでインストール<br>

```
$ brew install httpie
```


プログラムの実行。これでサーバが起動しAPIにアクセスができます。<br>

```
$ go run server.go
2019/XX/XX XX:XX:XX Server started.
```

別のターミナルからhttpieを使ってアクセス<br>

```
$ http -v POST localhost:9999/hello "Content-Type:application/json; charset=utf-8" Name="gatapon"
```

以下の内容でレスポンスが返ってくれば成功<br>

```shell
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"
}
```

## 内容の詳細について

ターミナルで叩いたコマンドについて振り返ります。<br>

```
http -v POST localhost:9999/hello "Content-Type:application/json; charset=utf-8" Name="gatapon"
```

これを簡単に訳すると、以下のようなことをしています。<br>

「`localhost:9999/hello`にPOSTメソッドでJSON形式の`Name="gatapon"`を渡す。」<br>

このコマンドを受け取ったサーバーの動きを見ていきます。<br>

### ファンクション：`postHello()　`について

```golang
// 第一引数 "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](https://github.com/ant0ine/go-json-rest/blob/ebb33769ae013bd5f518a8bac348c310dea768b8/rest/request.go#L34) 

`DecodeJsonPayload`で様々なバリデーションを行なっており、当てはまった場合はエラーを返す。<br>

 - 文字列の終端まで読み込み、バイトスライス
 - 文字列が0の時のバリデーション
 - Json形式の文字列をパース：json.Unmarshal

### 便利なコンストラクタ：`rest.NewApi()`

[NewApi()](https://github.com/ant0ine/go-json-rest/blob/ebb33769ae013bd5f518a8bac348c310dea768b8/rest/api.go#L14)

`NewApi()`は3つの強力なメソッドを持っており、それらを使うことで艱難にAPIサーバーを立ち上げることができます。<br>

```golang

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サーバーが作成できます。<br>
 パッケージを使えば、思ったより早く簡単なアプリが作成できそう。さらにGoの深淵を覗き込みたくなってきました。**MakeHandler**メソッドは内容を理解するのには時間がかかりそうなので、スルー状態...
 
  [MakeHandler()](https://github.com/ant0ine/go-json-rest/blob/ebb33769ae013bd5f518a8bac348c310dea768b8/rest/api.go#L35)

  - Useで指定したMiddlewareを取り出し、サーバで走らせる
  - http.Handlerの準備を行なっている
  
 これらを行なっているそうですが、まだ私には難しかったです。少しずつ勉強していきます。<br>
 
間違いがあればご指摘ください。<br>

### ソースコード

https://github.com/rinonkia/Go-Rest_Api