Go + Vue + MySQLの基盤を晒す

# はじめに
社会人として働き始めて技術と知識もついてきたので、初心に返ってTODOアプリを作成しようと思いました。
言語やフレームワークは気分で選びました。

方針としては`docker-compose build`, `docker-compose up`の2コマンドだけで完結できるように作成しました。
実際まだ半分くらいしか出来ていないのでフロントとか全くかけていないです。(むしろ @Angelan1720に手伝ってもらっています)

[作成中のリポジトリ](https://github.com/thimi0412/todo-go_vue)
以下の記事を参考にしながら作成して、ハマったところや気づいたところなどを書いていきます。

##　参考にした記事
- [今日から始めるDocker【docker-composeを使ってGo & Mysqlをよしなに起動しよう編】](https://qiita.com/yu-croco/items/0c0d5083298f7db9e1bb)
- [「Vue.js + Go言語 + Firebase 」で始める! Frontend & Backend API 両方で認証するセキュアなSPA開発ハンズオン!](https://qiita.com/po3rin/items/d3e016d01162e9d9de80)



# 構成
```
.
├── README.md
├── docker/
│   ├── client/
│   ├── golang/
│   └── mysql/
└── docker-compose.yml
```

```yml:docker-compose.yml
version: '3'

services:
  mysql:
    container_name: todo-mysql
    image: mysql:5.7
    ports:
      - "3306:3306"
    environment:
      MYSQL_USER: root
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: todo-mysql
    volumes:
      - ./db-data:/var/lib/mysql
      - ./docker/mysql/my.cnf:/etc/mysql/my.cnf
      - ./docker/mysql/init/:/docker-entrypoint-initdb.d
  golang:
    links:
      - mysql
    build: ./docker/golang/
    ports:
      - "8090:8080"
    volumes:
      - ./docker/golang/:/go/src/
    command: sh ./scripts/start_app.sh
  vue:
    build: ./docker/client
    ports:
      - 8888:8080
    volumes:
      - ./docker/client:/app
      - /app/node_modules

volumes:
  db-data:
    driver: local

```

## MySQL
`Dockerfile`は特に用意せずに公式のイメージからとってきました。 特別なことはしていません。

### 気づいた点
`docker-compose up`の際DBを作成して`mysql/init`配下にあるsqlを実行するのですが、ファイルの名前順に実行されるのでテーブルを作成する前にテストデータをinsertしてしまうことがあったのでファイル名の先頭に数字をつけました。

```
└── init
    ├── 1.todo.sql
    ├── 2.users.sql
    └── testdata.sql
```

## Go
- フレームワークは[gin](https://github.com/gin-gonic/gin)を使用。特に選定理由はないです。
- ORMは[gorm](http://gorm.io/ja_JP/)を使用。日本語のドキュメントも割と充実しているのでとてもいいです。
- 依存関係は`modules`を使用。 buildの時に全部入れてくれるのはいいですよね。

```dockerfile:golang/Dockerfile

FROM golang:latest

RUN apt-get update -qq && \
    apt-get install -y mysql-client vim

WORKDIR /go/src/

COPY . .

ENV GO111MODULE=on

RUN go build
RUN go install

ENV PATH /go/bin:$PATH
```

私は`vscode`で開発を行っていたので自分のローカルにパッケージがないと補完してくれないので`go get`しまくってました。(いい案があるなら教えて欲しいです)

ハマった点は`gorm`で`string`で渡された日時をinsertする際、時間がズレてしまうことが起こってしまいました。原因としてMySQLのタイムゾーンを疑いましたが、Go側のタイムゾーンの問題でした。

```go

limitDate := "2018-03-31 12:00:00"
timeformat := "2006-01-02 15:04:05"
loc, _ := time.LoadLocation("Asia/Tokyo")

t, err := time.ParseInLocation(timeformat, limitDate, loc)
if err != nil {
	panic(err)
}
```
`ParseInLocation`を使用して、タイムゾーンに合わせたtime型に変換することで解決しました。

### gormのいいところ
TODOをDBに登録する際、おそらく作成日(created_at)と更新日(updated_at)のカラムは必要となると思います。

```go
type Todo struct {
	ID        int        `json:"id"`
	UserID    int        `json:"user_id"`
	Context   string     `json:"context"`
	LimitDate *time.Time `json:"limit_date"`
	CreatedAt time.Time  `json:"created_at"`
	UpdatedAt time.Time  `json:"updated_at"`
}
```
`TODO`のstructを定義する際、`CreatedAt`と`UpdatedAt`を上のように定義すると自動的に`CreatedAt`と`UpdatedAt`を入れてくれます。

```go
todo := Todo{}
todo.UserID = userID
todo.Context = context
todo.LimitDate = &t

db.Create(&todo) // CreatedAtとUpdatedAtを入れてくれる
```

```go
todo := Todo{}
todo.ID = ID
todo.UserID = userID

db.Model(&todo).Updates(Todo{Context: context, LimitDate: &t}) // UpdatedAtを更新してくれる
```

## Vue

```dockerfile:client/Dockerfile

FROM node:10.12-alpine as build-stage
WORKDIR /app
COPY . .
RUN yarn install
CMD yarn serve
```

クライアント側は現時点ではほとんど作成していないのでVueが立ち上がってくれればいいかな程度まで作成しました。
Vueはそんなに詳しくないでのとりあえず`axios`と`vue-router`を使って色々試してみます。

# これからやっていきたいこと
1. とりあえず完成させて公開したい
2. REST-APIで作成したので`swagger`を使ってAPIドキュメントも作りたい
3. ユーザ登録を`firebase`を使用してGoogleアカウントでログインできるようにしたい