Goで簡易的なAPIサーバーを立てる


Goで簡易的なAPIサーバーを作ってみました。
フレームワークに頼る前に自分でシンプルな構成で立ててみたかったので、今回はフレームワークは使いません


## 環境
- MacOS 10.15.2
- go version go1.14.4 darwin/amd64
- mysql 8.0.19

## インストール
brewに従います。
```bash
brew install go
```



## hello world
こんにちは世界

```go
package main

import "fmt"

func main() {
	fmt.Printf("hello, world\n")
}
```
`fmt` は入出力系のパッケージです。
他言語でみたことある方は違和感なく使えそうです。

https://golang.org/pkg/fmt/


## HTTP server 構築

`net/http` はHTTP client and server のパッケージです。
なんとたったこれだけでHTTP serverが立てられてしまうそうです。すごい

https://golang.org/pkg/net/http/

```go
package main

import (
  "fmt"
  "log"
  "net/http"
)

func homePage(w http.ResponseWriter, r *http.Request){
  fmt.Fprintf(w, "Welcome to the HomePage!")
  fmt.Println("Endpoint Hit: homePage")
}

func handleRequests() {
  http.HandleFunc("/", homePage)
  log.Fatal(http.ListenAndServe(":8081", nil))
}

func main() {
    handleRequests()
}
```


Get リクエストを送ると設定しているテキストが返ってきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55864/009de935-39e2-6b9e-1ecb-a3fecded71c2.png)



## JSON　形式での返却

通常のAPIサーバーではJSON形式が返って来るのが一般的です
`struct` と `encoding/json` を使って、よくあるAPI形式で結果を返却してみます
https://golang.org/pkg/encoding/json/

```go
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
)

type Article struct {
	Title   string `json:"Title"`
	Desc    string `json:"desc"`
	Content string `json:"content"`
}

type Articles []Article

func homePage(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Welcome to the HomePage!")
	fmt.Println("Endpoint Hit: homePage")
}

func handleRequests() {
	http.HandleFunc("/", homePage)
	http.HandleFunc("/articles", returnAllArticles)
	log.Fatal(http.ListenAndServe(":8081", nil))
}
func returnAllArticles(w http.ResponseWriter, r *http.Request) {
	articles := Articles{}
	for i := 0; i < 10; i++ {
		title := "Hello_%d"
		articles = append(
			articles,
			Article{Title: fmt.Sprintf(title, i), Desc: "Article Description", Content: "Article Content"})
	}
	fmt.Println("Endpoint Hit: returnAllArticles")
	json.NewEncoder(w).Encode(articles)
}

func main() {
	handleRequests()
}

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55864/e52b3c79-8815-9cec-224f-6fc3fda8c30e.png)

こちらの記事を完全参考にしました。。。ありがたいです！
https://hodalog.com/creating-restfulapi-with-golang/




## DBの内容を返却
APIで返却する内容はDBへのSQL結果を利用する場合が多いです。
 `gorm` と言うORMを利用し、実現しました

###  環境準備
go get でパッケージのインストールをします
```bash
$ go get github.com/jinzhu/gorm
$ go get github.com/go-sql-driver/mysql
```




### テーブル作成
gorm　でマイグレーションの機能があるのですが普通にcreate tableで作成しました。

```sql
CREATE TABLE `gorm-example`.`players` (
  `id` INT NOT NULL,
  `name` VARCHAR(255) NULL,
  `created_at` DATETIME NULL,
  `updated_at` DATETIME NULL,
  `deleted_at` DATETIME NULL,
  PRIMARY KEY (`id`));
```

### DB接続and データ取得
`GetDBConn()`  `GetDBConfig()` でDB接続処理を行い
`fetchPlayers` でデータ取得した結果をJSONに変更して返却しています。

```go
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
)

type Player struct {
	gorm.Model
	Name string
}

var player Player
var players []Player

func handleRequests() {
	http.HandleFunc("/", homePage)
	http.HandleFunc("/players", fetchPlayers)
	log.Fatal(http.ListenAndServe(":8081", nil))
}

func fetchPlayers(w http.ResponseWriter, r *http.Request) {
	db := GetDBConn()

	db.Find(&players)
	fmt.Println(players)
	profJson, _ := json.Marshal(players)
	fmt.Fprintf(w, string(profJson))
}

func GetDBConn() *gorm.DB {
	db, err := gorm.Open(GetDBConfig())
	if err != nil {
		panic(err)
	}

	db.LogMode(true)
	return db
}

func GetDBConfig() (string, string) {
	DBMS := "mysql"
	USER := "root"
	PASS := ""
	PROTOCOL := ""
	DBNAME := "gorm-example"
	OPTION := "charset=utf8&parseTime=True&loc=Local"

	CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?" + OPTION

	return DBMS, CONNECT
}

func homePage(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Welcome to the HomePage!")
	fmt.Println("Endpoint Hit: homePage")
}

func main() {
	handleRequests()
}

```

データを取得すると想定通りに値が返ってきています。
（何故か大文字になるけど）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55864/16366594-7dc2-5a91-057b-dee43c874eef.png)
参考記事: https://medium.com/@taka.abc.hiko/gorm%E3%81%A8%E3%81%84%E3%81%86orm%E3%81%8C%E8%B6%85%E7%B5%B6%E4%BE%BF%E5%88%A9%E3%81%A0%E3%81%A3%E3%81%9F%E4%BB%B6-8d279489c38f


# まとめ
- GoでAPIサーバーを立てるのは、標準ライブラリが揃ってて簡単
- ルーター/認証などフレームワークに乗っ取ったりする部分はどうするかまだわからない


# 最後に
visual stadio code のGoが素晴らしい。型安全(๑˃̵ᴗ˂̵)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55864/b77cb5d4-60de-bdf8-7b9a-03b3624608ac.png)