GolangでシンプルなRESTful APIを作ってみた


## 概要
GoでシンプルなRESTful APIを作りました。
簡単にしたかったので読み出しの機能のみです。

サンプルは[ここ](https://github.com/yuuulf/go-simple-api)

#### 環境
- go 1.13.4
- mysql 8.0.17

#### Framework
- [echo](https://echo.labstack.com/)


## Hello World!
- hogeリポジトリを作る
- プロジェクトを作成

```bash
$ mkdir hoge
$ cd hoge
$ go mod init github.com/<owner>/hoge
```

`go mod`については以下参照
[Package Management With Go Modules](https://medium.com/@adiach3nko/package-management-with-go-modules-the-pragmatic-guide-c831b4eaaf31)




echoを依存関係に追加

```bash
$ go get -u github.com/labstack/echo/...
```

main.goを作成

```golang
package main

import (
	"net/http"
	
	"github.com/labstack/echo"
)

func main() {
	e := echo.New()
	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello, World!")
	})
	e.Logger.Fatal(e.Start(":1323"))
}
```

サーバを起動

```bash
$ go run main.go
```


```bash
$ curl http://127.0.0.1:1323/
Hello, World!
```


## ユーザを取得するAPIを作成する

以下のAPIを作成する

- [/users](http://127.0.0.1:1323/users) -> userのリスト、userデータを全部返す
- [/users/{id}](http://127.0.0.1:1323/users/{id}) -> idに紐づくuserの情報を返す


```golang
...
func main() {
	e := echo.New()
	e.GET("/users", GetUsers)
	e.GET("/users/:id", GetUser)

	e.Logger.Fatal(e.Start(":1323"))
}

type User struct {
	ID   int
	Name string
}

func GetUsers(c echo.Context) error {
	var users []User
	return c.JSON(http.StatusOK, users)
}

func GetUser(c echo.Context) error {
	userid, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		return err
	}
	user := &User{
		ID:   userid,
		Name: "dummy",
	}
	return c.JSON(http.StatusOK, user)
}
```

サーバを起動する

```bash
$ curl http://127.0.0.1:1323/users
null

$ curl http://127.0.0.1:1323/users/1
{"ID":1,"Name":"dummy"}
```



## MySQLに接続する
mysqlを依存関係に追加

```bash
$ go get github.com/go-sql-driver/mysql
```

DB名: sample
テーブル名: users

| id | name |
|---:|:----:|
|  1 | suzuki |
|  2 | takahashi |
|  3 | tanaka |

db接続

```golang
  db, err := sql.Open("mysql", "root@/gosample")
  if err != nil {
    panic(err.Error())
  }
  defer db.Close()

```

データ取得

```golang
  rows, err := db.Query("SELECT * FROM users")
  defer rows.Close()
  if err != nil {
    return []User{}, err
  }
```

サーバを起動する

```bash
$ curl http://127.0.0.1:1323/users
[{"ID":1,"Name":"suzuki"},{"ID":2,"Name":"takahashi"},{"ID":3,"Name":"tanaka"}]

$ curl http://127.0.0.1:1323/users/1
{"ID":1,"Name":"suzuki"}
```

main.go

```golang
package main

import (
	"database/sql"
	"net/http"
	"strconv"

	_ "github.com/go-sql-driver/mysql"
	"github.com/labstack/echo"
)

var connection *sql.DB

func main() {
	db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/sample")
	if err != nil {
		panic(err.Error())
	}
	connection = db
	defer db.Close()

	e := echo.New()
	e.GET("/users", GetUsers)
	e.GET("/users/:id", GetUser)

	e.Logger.Fatal(e.Start(":1323"))
}

type User struct {
	ID   int
	Name string
}

func GetUsers(c echo.Context) error {
	users, err := FindAll(connection)
	if err != nil {
		return err
	}
	return c.JSON(http.StatusOK, users)
}

func GetUser(c echo.Context) error {
	userid, err := strconv.Atoi(c.Param("id"))
	if err != nil {
		return err
	}
	user, err := FindById(connection, userid)
	if err != nil {
		return err
	}
	return c.JSON(http.StatusOK, user)
}

func FindAll(db *sql.DB) ([]User, error) {
	rows, err := db.Query("SELECT * FROM users")
	defer rows.Close()
	if err != nil {
		return []User{}, err
	}

	var users []User
	for rows.Next() {
		var user User
		if err := rows.Scan(&user.ID, &user.Name); err != nil {
			return []User{}, err
		}
		users = append(users, user)
	}

	return users, nil
}

func FindById(db *sql.DB, id int) (User, error) {
	rows, err := db.Query("SELECT * FROM users WHERE id = ?", id)
	defer rows.Close()
	if err != nil {
		return User{}, err
	}

	rows.Next()
	var user User
	if err := rows.Scan(&user.ID, &user.Name); err != nil {
		return User{}, err
	}
	return user, nil
}

```

## まとめ
今回はGETの実装のみで終わってしまいましたが、その他のメソッドについても実装したいです。
ORMも試すのもありかな。