Ubuntu+Golang+MySQLを使用してRESTful APIサーバーを構築する(for Windows x64)

#<i class="fa fa-cubes" style="font-size:1em;"></i> 概要
Ubuntu(16.04)にGo(1.6)+MySQLの環境を構築し、RESTful APIサーバーを作成した手順を記載します。
RESTful APIサーバー構築部分については、Naren Aryaさんの[記事](http://blog.narenarya.in/build-rest-api-go-mysql.html)を参考にさせて頂きました。
Ubuntuに環境構築した理由はWindowsマシンに色々と入れたくなかった。。。ただそれだけです。


#<i class="fa fa-cube" style="font-size:1em;"></i> 必要なもの
・[VMware Workstation Player](https://my.vmware.com/jp/web/vmware/free#desktop_end_user_computing/vmware_workstation_player/12_0)
　【VMware Workstation 12.5.4 Player for Windows 64-bit Operating Systems.】

・[Ubuntuのisoイメージ](https://www.ubuntulinux.jp/download/ja-remix)
　【ubuntu-ja-16.04-desktop-amd64.iso】

・[Postman](https://www.getpostman.com/)　(※既に使用しているAPIClientToolでも可)
　APIClientツール


#<i class="fa fa-cube" style="font-size:1em;"></i> Ubuntu(16.04)環境構築
##1.VMware Workstation Playerのインストール
ダウンロードした、「VMware-player-12.5.4-5192485.exe」を実行、特に問題が無ければデフォルト値のまま「次へ」を押下し、インストールが完了するまで待ちます。

##2.Ubuntuのisoイメージを登録
①「VMware Workstation Player」を起動し、「新規仮想マシンの作成(N)」をクリック
②「インストーラ ディスク イメージ ファイル」にダウンロードした、「ubuntu-ja-16.04-desktop-amd64.iso」を指定
③ユーザー名、パスワード等、任意の文字を指定
④仮想マシン名、任意のフォルダを指定
⑤以降問題が無ければ画面にしたがって進む

##3.おまけ(個人的に行ったUbuntuの外観設定)
・画面右上の歯車マーククリック→システム設定→時刻と日付→場所(L):「Tokyo」に変更
・画面右上の歯車マーククリック→システム設定→外観→「Launcherアイコンのサイズ」変更
・画面右上の歯車マーククリック→システム設定→ディスプレイ→「メニューとタイトルバーの拡大縮小」変更
・Launcherを下に配置
　以下のコマンドを「端末(Ctrl+Alt+T)」にて実行

```bash
$ gsettings set com.canonical.Unity.Launcher launcher-position Bottom
```

　左端に戻す場合

```bash
$ gsettings set com.canonical.Unity.Launcher launcher-position Left
```

#<i class="fa fa-cube" style="font-size:1em;"></i> Golang環境構築(for Ubuntu16.04)
##1.Ubuntuアップデート
以下のコマンドを実行

```bash
$ sudo apt-get update
```

##2.Goをインストール
以下のコマンドを実行

```bash
$ sudo apt-get install golang
```

バージョンを確認する

```bash
$ go version
go version go1.6.2 linux/amd64
```

##3.パスの設定
ホームディレクトリ配下に作業用のフォルダ「go」を作成する。

```bash
$ mkdir go
```

「.bashrc」をnanoエディタにて開く

```bash
$ nano ~/.bashrc
```

「.bashrc」ファイル末尾に下記を追記　()

```bash
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$PATH
# 保存して閉じる：【Ctrl+O】→【Enter】→【Ctrl+X】
```

##4.Hello World!
ホームディレクトリ配下に作成した「go」フォルダに「hello.go」ファイルを作成

```go:hello.go
package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello World!")
}
```

「hello.go」を実行してみる

```bash
$ cd $GOPATH
$ go run hello.go
Hello World!
```

#<i class="fa fa-cube" style="font-size:1em;"></i> GolangとMySQLを使用して基本的なRESTful APIを構築
##1.必要なものを揃える
gitインストール

```bash
$ sudo apt-get install git
```

mysqlServerインストール

```bash
$ sudo apt-get install mysql-server
# 今回パスワードは「root」としました。
```

mysqlドライバーをgithubより取得

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

APIサーバーを作成するためにGinというHTTPフレームワークを取得

```bash
# カレントディレクトリは[$GOPATH]のまま
$ go get "github.com/gin-gonic/gin"
```

##2.MySQLサーバーにデータ登録
MySQLシェルで"gotest"というデータベースを作成

```bash
# 下記コマンドでmysqlコマンドラインツール起動
$ mysql -u root -p

# データベース作成
mysql> create database gotest;

# データベースが作成されたか確認
mysql> show create database gotest;
+-----------+--------------------------------------------------------------------+
| Database | Create Database                                                     |
+-----------+--------------------------------------------------------------------+
| WP_DB     | CREATE DATABASE `gotest` /*!40100 DEFAULT CHARACTER SET latin1 */  |
+-----------+--------------------------------------------------------------------+
1 row in set (0.00 sec)
```

作成した「gotest」DBに「Person Table」を作成
・$GOPATH/src 直下に下記ファイルを作成

```go:migrate_person.go
package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
)

func main() {
	db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/gotest")
	if err != nil {
		fmt.Println(err.Error())
	}
	defer db.Close()
	// make sure connection is available
	err = db.Ping()
	if err != nil {
		fmt.Println(err.Error())
	}

	stmt, err := db.Prepare("CREATE TABLE person (id int NOT NULL AUTO_INCREMENT, first_name varchar(40), last_name varchar(40), PRIMARY KEY (id));")
	if err != nil {
		fmt.Println(err.Error())
	}
	_, err = stmt.Exec()
	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println("Person Table successfully migrated....")
	}
}
```
・上記「migrate_person.go」実行

```bash
$ cd $GOPATH
$ go run migrate_person.go
Person Table successfully migrated....

# MySQLシェルにて対象テーブルが作成されているか確認
mysql> describe person;
+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| id         | int(11)     | NO   | PRI | NULL    | auto_increment |
| first_name | varchar(40) | YES  |     | NULL    |                |
| last_name  | varchar(40) | YES  |     | NULL    |                |
+------------+-------------+------+-----+---------+----------------+
3 rows in set (0.02 sec)
```

##3.APIサーバー
・$GOPATH/src 直下に下記ファイルを作成

```go:gitter.go
package main

import (
	"bytes"
	"database/sql"
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	_ "github.com/go-sql-driver/mysql"
)

func main() {
	db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/gotest")
	if err != nil {
		fmt.Print(err.Error())
	}
	defer db.Close()
	// make sure connection is available
	err = db.Ping()
	if err != nil {
		fmt.Print(err.Error())
	}
	type Person struct {
		Id         int
		First_Name string
		Last_Name  string
	}
	router := gin.Default()

	// GET a person detail
	router.GET("/person/:id", func(c *gin.Context) {
		var (
			person Person
			result gin.H
		)
		id := c.Param("id")
		row := db.QueryRow("select id, first_name, last_name from person where id = ?;", id)
		err = row.Scan(&person.Id, &person.First_Name, &person.Last_Name)
		if err != nil {
			// If no results send null
			result = gin.H{
				"result": nil,
				"count":  0,
			}
		} else {
			result = gin.H{
				"result": person,
				"count":  1,
			}
		}
		c.JSON(http.StatusOK, result)
	})

	// GET all persons
	router.GET("/persons", func(c *gin.Context) {
		var (
			person  Person
			persons []Person
		)
		rows, err := db.Query("select id, first_name, last_name from person;")
		if err != nil {
			fmt.Print(err.Error())
		}
		for rows.Next() {
			err = rows.Scan(&person.Id, &person.First_Name, &person.Last_Name)
			persons = append(persons, person)
			if err != nil {
				fmt.Print(err.Error())
			}
		}
		defer rows.Close()
		c.JSON(http.StatusOK, gin.H{
			"result": persons,
			"count":  len(persons),
		})
	})

	// POST new person details
	router.POST("/person", func(c *gin.Context) {
		var buffer bytes.Buffer
		first_name := c.PostForm("first_name")
		last_name := c.PostForm("last_name")
		stmt, err := db.Prepare("insert into person (first_name, last_name) values(?,?);")
		if err != nil {
			fmt.Print(err.Error())
		}
		_, err = stmt.Exec(first_name, last_name)

		if err != nil {
			fmt.Print(err.Error())
		}

		// Fastest way to append strings
		buffer.WriteString(first_name)
		buffer.WriteString(" ")
		buffer.WriteString(last_name)
		defer stmt.Close()
		name := buffer.String()
		c.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf(" %s successfully created", name),
		})
	})

	// PUT - update a person details
	router.PUT("/person", func(c *gin.Context) {
		var buffer bytes.Buffer
		id := c.Query("id")
		first_name := c.PostForm("first_name")
		last_name := c.PostForm("last_name")
		stmt, err := db.Prepare("update person set first_name= ?, last_name= ? where id= ?;")
		if err != nil {
			fmt.Print(err.Error())
		}
		_, err = stmt.Exec(first_name, last_name, id)
		if err != nil {
			fmt.Print(err.Error())
		}

		// Fastest way to append strings
		buffer.WriteString(first_name)
		buffer.WriteString(" ")
		buffer.WriteString(last_name)
		defer stmt.Close()
		name := buffer.String()
		c.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf("Successfully updated to %s", name),
		})
	})

	// Delete resources
	router.DELETE("/person", func(c *gin.Context) {
		id := c.Query("id")
		stmt, err := db.Prepare("delete from person where id= ?;")
		if err != nil {
			fmt.Print(err.Error())
		}
		_, err = stmt.Exec(id)
		if err != nil {
			fmt.Print(err.Error())
		}
		c.JSON(http.StatusOK, gin.H{
			"message": fmt.Sprintf("Successfully deleted user: %s", id),
		})
	})
	router.Run(":3000")
}
```

・上記「gitter.go」実行

```bash
$ cd $GOPATH/src
$ go build gitter.go
$ ./gitter
```

##4.APIClientToolにて確認（Postmanを使用）
【POST】ユーザーを追加 ([http:XXX.XXX.XXX.XXX(APIサーバーIPアドレス):3000/person]())
![image](https://qiita-image-store.s3.amazonaws.com/0/153587/ac93c7da-1728-30ba-b3c2-248e6fffce7e.png)
実行結果
![image](https://qiita-image-store.s3.amazonaws.com/0/153587/2cc76826-a4b4-d411-7c5a-dd97426d9f7c.png)

【GET】全ユーザーを取得 ([http:XXX.XXX.XXX.XXX:3000/persons]())
(※ここでは複数ユーザー追加後に実行しています)
![image](https://qiita-image-store.s3.amazonaws.com/0/153587/fda9cde7-b4a4-68de-8e7e-510b3f4f4307.png)
実行結果
![image](https://qiita-image-store.s3.amazonaws.com/0/153587/23550cfd-3fd7-7d45-07c8-5058bc1be7b7.png)

【GET】個別にユーザーを取得 ([http:XXX.XXX.XXX.XXX:3000/person/"id"]())
![image](https://qiita-image-store.s3.amazonaws.com/0/153587/1a7d6db1-62f0-c82c-2c6e-d9dc17faf7e0.png)
実行結果
![image](https://qiita-image-store.s3.amazonaws.com/0/153587/c8098e67-c5fe-e245-55df-9fcebcf868a0.png)

【PUT】ユーザー更新 ([http:XXX.XXX.XXX.XXX:3000/person?id="id"]())
![image](https://qiita-image-store.s3.amazonaws.com/0/153587/a7c3e566-f6b1-ec49-e63d-b1fdd77225a3.png)
実行結果
![image](https://qiita-image-store.s3.amazonaws.com/0/153587/2f61eb9b-4aa2-fc9a-5d2b-6c3203ebf558.png)

【DELETE】ユーザー削除 ([http:XXX.XXX.XXX.XXX:3000/person?id="id"]())
![image](https://qiita-image-store.s3.amazonaws.com/0/153587/4d731335-f2bf-ba9c-67e0-ad5e301da364.png)
実行結果
![image](https://qiita-image-store.s3.amazonaws.com/0/153587/e36590fc-7b9a-4f4f-83af-b783bf7d5868.png)
最終結果
![image](https://qiita-image-store.s3.amazonaws.com/0/153587/305b5ff8-6c3e-c8e4-a363-4660b338aabc.png)

#<i class="fa fa-cube" style="font-size:1em;"></i> 最後に
元々、Oracleを使用して、RESTful APIサーバーを構築する予定でしたが、
UbuntuにOracleClinetをインストールした際、うまくいかずUbuntuの再構築をしなければならなくなり、
あきらめてMySQLを使用することにしました。
Golangについてもかなりの初心者ですので、どなたにでもわかり易いように手順だけは細かく記載したつもりですが、
記載に間違いがあれば、ご指摘いただけると助かります。

2017年くらいに勉強用に限定公開していた記事ですが、
今回全体公開としました。バージョンが古かったりと多々問題があるかとは思います。。。