ボクダイモリ

Life is like a Game

Vue.js + Golangでタスクリスト作ってみた

Vue.jsとgolangを使って何か作ってみたかったので試しにタスクリストを作ってみました。

github.com

Vue.jsの書き方やgolangAPI実装はmattnさんのブログを大いに参考にさせて頂きました。

mattn.kaoriya.net

見た目はこんな感じです。

f:id:anrakusan:20180625070806p:plain

WebアプリケーションフレームワークはEcho、ORMにgormを利用しています。 また、Dockerの勉強も兼ねてフロントエンドとバックエンドの環境を立ち上げられるよう設定ファイルも書いてみました。

バージョン確認

$ go version
go version go1.10 darwin/amd64

$ node -v
v9.8.0

$ npm -v
5.8.0

なお、環境構築の手順は割愛します。

フロントエンドの実装

タスクリストの機能は次の通りです。 - タスクの一覧表示 - タスク作成 - タスクの完了、及び残タスクに戻す

上記の処理はsrc/components/Todo.vueにあります。 下のコードはjsが動く部分です。

<script>
import axios from 'axios'
export default {
  name: 'Todo',
  data () {
    return {
      newTask: '',
      todos: []
    }
  },
  created: function () {
    axios.get('http://localhost:1323/tasks')
      .then((response) => {
        console.log(response)
        this.todos = response.data.items || []
      })
      .catch((error) => {
        console.log(error)
      })
  },
  methods: {
    addTask: function (todo) {
      let params = new URLSearchParams()
      params.append('text', this.newTask)
      params.append('done', false)
      axios.post('http://localhost:1323/tasks', params)
        .then((response) => {
          this.todos.unshift(response.data)
          this.newTask = ''
        })
        .catch((error) => {
          console.log(error)
        })
    },
    updateTask: function (todo) {
      let params = new URLSearchParams()
      params.append('done', !todo.done)
      axios.put('http://localhost:1323/tasks/' + todo.id, params)
        .then((response) => {
          todo.done = !todo.done
          console.log(response)
        })
        .catch((error) => {
          console.log(error)
        })
    }
  }
}
</script>

created()はページをロードした時だけ実行されます。

また、データのやり取りはすべてAjaxAPIを実行して結果を取得するようにしています。

axios使いやすいです。

バックエンドの実装

バックエンドのAPIGolang + Echo + Gormで実装しています。

ミドルウェアやルーティングの設定はmain.goでして実処理はhandler.goに書いてます。

model/にはタスクのデータ定義やデータアクセスの処理を定義していて、ビジネスロジックは書かずシンプルにしています。

func (m *Model) FindAll() (tasks []model.Task, err error) {
    err = m.DB.Table(table).Find(&tasks).Error
    return
}

func (m *Model) Create(task model.Task) (t model.Task, err error) {
    t = task
    err = m.DB.Table(table).Create(&t).Error
    return
}

func (m *Model) Update(task model.Task) (t model.Task, err error) {
    t = task
    err = m.DB.Table(table).Where("id = ?", task.ID).Update("done", task.Done).Error
    return
}

実際のデータベース接続処理とも切り離していて、接続処理はdatabase/に定義しています。

func Connect() (*gorm.DB, error) {
    db, err := gorm.Open("mysql", "root:password@tcp(mysql:3306)/app?charset=utf8&parseTime=True&loc=Local")
    if err != nil {
        return nil, err
    }
    return db, nil
}

また、tasksのテーブル定義はinfra/mysql/sqls/1_init.sqlに記載してます。

環境構築

今回紹介したアプリはなるべくdocker-composeで再現できるようにしていますが、APIのビルドは事前に実行する必要があります。本当はそこもMakefile使う等で自動化したい。。

cd TodoList/backend/service
GOOS=linux go build -o api main.go handler.go

基本必要な記述はできるだけ個々のDockerfileではなくdocker-compose.ymlに寄せてます。

version: '2'
services:
  web:
    container_name: 'web'
    build:
      context: ../front/
      dockerfile: Dockerfile
    volumes:
      - ../front:/app
    networks:
      - front
    ports:
      - 8080:8080

  api:
    container_name: 'api'
    build:
      context: ../backend/service/
      dockerfile: Dockerfile
    networks:
      - front
      - datastore
    ports:
      - 1323:1323

  mysql:
    container_name: 'db'
    build:
      context: ./mysql/
      dockerfile: Dockerfile
    volumes:
      - ./mysql/mysql_data:/var/lib/mysql # データの永続化
      - ./mysql/sqls:/docker-entrypoint-initdb.d # 初期データ投入
    environment:
      - MYSQL_ROOT_PASSWORD=password #rootパスワードの設定
    networks:
      - datastore
    ports:
      - 3306:3306

networks:
    front:
    datastore:

webのDockerコンテナは起動時にnpm installとnpm runしてます。 apiコンテナは事前にlinux用にビルドされたバイナリを配置して起動しているだけです。 DBのテーブル定義などはコンテナ構築時に初期データを読み込むようにしています。

      - ./mysql/sqls:/docker-entrypoint-initdb.d # 初期データ投入

感想

なんだかんだで今回一番時間かかったのはdockerを使った環境構築。。。

Vue.jsを使ってみたくてアプリを作ってみましたが、ファイル分割しやすいしstyleとhtmlとjsをコンポーネント毎に分けられるので処理を理解しやすい。axiosなどの使いやすいライブラリもあるので開発するならVue.jsでいい感じ。レイアウトのデザインを作るためのライブラリも充実していてElementやVuetifyがあります。Vuetifyは簡単にマテリアルデザインが作れる感じなので使ってみたい。