Skip to content

unokun/go-todo-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

プログラミング言語goを使ってWeb API開発する記事はいろいろとありますが、できるだけ外部パッケージを使わない方針で開発しましたので報告します。goを使ったWeb API開発する際の参考になれば幸いです。 また、Web APIを公開する場合、Webサーバー(nginx) + アプリケーションサーバー(go)という構成が一般的(?)かと思いましたので、設定についての記載を最後に追加しました。

ソースコードはGithubにあります。 https://github.com/unokun/go-todo-api

環境

項目 バージョン
OS Centos7
go 1.11.4
mysql(maria DB) 5.5.60

TODO管理 Web API

baseurl(/todo/api/v1)にPathを加えたURLで各機能を実装しています。

Path HTTPメソッド 機能
/tasks GET タスク一覧取得
/tasks POST タスク登録
/tasks/:id PATCH タスク更新
/tasks/:id DELETE タスク削除

インストール

goのインストールは、以下の記事を、 CentOSにGo言語のインストール - Qiita

また、Web APIの実装については以下の記事を参考にさせていただきました。 GoでWebアプリを作ろう 第一回 : Goで簡単なCRUD - Studio Andy

使った外部パッケージは、以下の二つです。

  • gin
  • mysql

ginは、go製のWebフレームワークです。jsonレスポンス処理機能も持っている優れものです。 mysqlはDBに合わせて変更してください。

$ go get github.com/gin-gonic/gin
$ go get github.com/go-sql-driver/mysql

ファイル構成

$ tree go-todo-api
go-todo-api
├── db
│   └── createTask.sql
└── src
    ├── controller
    │   └── task.go
    ├── main.go
    └── model
        ├── model.go
        └── task.go

DB

データベース(tododb)作成 専用のユーザー(todo)を作成し権限を付与します。

$ mysql -u root -p
MariaDB [(none)]> create database tododb default charset utf8;
MariaDB [(none)]> create user 'todo'@'localhost' identified by 'todo';
MariaDB [(none)]> grant all on `tododb`.* to 'todo'@'localhost';

テーブルはタイトルのみ持つシンプルな構成です。

USE tododb
DROP TABLE IF EXISTS task;
CREATE TABLE IF NOT EXISTS task (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    created_at TIMESTAMP NOT NULL,
    updated_at TIMESTAMP NOT NULL,
    title VARCHAR(255) NOT NULL,
    PRIMARY KEY(id)
);

model

DBアクセス処理を作成します。 task.goにJson返却用のstructを定義しています。

package model

import (
    "time"
)

type Task struct {
    ID        uint      `json:"id"`         // id
    CreatedAt time.Time `json:"created_at"` // created_at
    UpdatedAt time.Time `json:"updated_at"` // updated_at
    Title     string    `json:"title"`      // title
}

model.goにDB接続用関数を作成しています。

package model

import (
    "database/sql"
    "log"
    "os"

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

// DBConnect returns *sql.DB
func DBConnect() (db *sql.DB) {
    dbDriver := "mysql"
    dbUser := "todo"
    dbPass := os.Getenv("MYSQL_TODO_PASSWORD") // 環境変数から取得
    dbName := "tododb"
    dbOption := "?parseTime=true"
    db, err := sql.Open(dbDriver, dbUser+":"+dbPass+"@/"+dbName+dbOption)
    if err != nil {
        log.Fatal(err)
    }
    return db
}

controller

mainから呼び出すタスク処理を記述します。

package controller

import (
    "fmt"
    "net/http"
    "strconv"
    "time"

    "github.com/gin-gonic/gin"
    "github.com/unokun/go-todo-api/src/model"
)

// タスク一覧
func TasksGET(c *gin.Context) {
    db := model.DBConnect()
    result, err := db.Query("SELECT * FROM task ORDER BY id DESC")
    if err != nil {
        panic(err.Error())
    }

    // json返却用
    tasks := []model.Task{}
    for result.Next() {
        task := model.Task{}
        var id uint
        var createdAt, updatedAt time.Time
        var title string

        err = result.Scan(&id, &createdAt, &updatedAt, &title)
        if err != nil {
            panic(err.Error())
       }

        task.ID = id
        task.CreatedAt = createdAt
        task.UpdatedAt = updatedAt
        task.Title = title
        tasks = append(tasks, task)
    }
    c.JSON(http.StatusOK, gin.H{"tasks": tasks})
}
// タスク検索
func FindByID(id uint) model.Task {
    db := model.DBConnect()
    result, err := db.Query("SELECT * FROM task WHERE id = ?", id)
    if err != nil {
        panic(err.Error())
    }
    task := model.Task{}
    for result.Next() {
        var createdAt, updatedAt time.Time
        var title string

        err = result.Scan(&id, &createdAt, &updatedAt, &title)
        if err != nil {
            panic(err.Error())
        }

        task.ID = id
        task.CreatedAt = createdAt
        task.UpdatedAt = updatedAt
        task.Title = title
    }
    return task
}
// タスク登録
func TaskPOST(c *gin.Context) {
    db := model.DBConnect()

    title := c.PostForm("title")
    now := time.Now()

    _, err := db.Exec("INSERT INTO task (title, created_at, updated_at) VALUES(?, ?, ?)", title, now, now)
    if err != nil {
        panic(err.Error())
    }

    fmt.Printf("post sent. title: %s", title)
}
// タスク更新
func TaskPATCH(c *gin.Context) {
    db := model.DBConnect()

    id, _ := strconv.Atoi(c.Param("id"))
    title := c.PostForm("title")
    now := time.Now()

    _, err := db.Exec("UPDATE task SET title = ?, updated_at=? WHERE id = ?", title, now, id)
    if err != nil {
        panic(err.Error())
    }

    task := FindByID(uint(id))

    fmt.Println(task)
    c.JSON(http.StatusOK, gin.H{"task": task})
}
// タスク削除
func TaskDELETE(c *gin.Context) {
    db := model.DBConnect()

    id, _ := strconv.Atoi(c.Param("id"))

    _, err := db.Query("DELETE FROM task WHERE id = ?", id)
    if err != nil {
        panic(err.Error())
    }

    c.JSON(http.StatusOK, "deleted")
}

main

メイン処理を記述します。

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/unokun/go-todo-api/src/controller"
)

func main() {
    router := gin.Default()

    v1 := router.Group("/todo/api/v1")
    {
        v1.GET("/tasks", controller.TasksGET)
        v1.POST("/tasks", controller.TaskPOST)
        v1.PATCH("/tasks/:id", controller.TaskPATCH)
        v1.DELETE("/tasks/:id", controller.TaskDELETE)
    }
    // nginxのreverse proxy設定
    router.Run(":9000")
}

実行

バックグランドジョブとして実行します。

$ MYSQL_TODO_PASSWORD=xxx go run main.go &

API呼び出し

API呼び出しを実行する方法はいろいろありますが、Google Chromeの拡張機能である「Restlet Client」が使いやすいです。 Restlet Client - REST API Testing - Chrome ウェブストア

タスク一覧 go_todo_list_tasks.png

タスク登録 go_todo_add_task.png

ginのログ gin_log.png

nginxの設定

Webサーバー(nginx) + アプリケーションサーバー(go webapi)という構成にする場合、リバースプロキシーとして動作させます。locationの記述についてはここを参考にしてください。

$ cat /etc/nginx/conf.d/https.conf
        location ^~ /todo/ {
                proxy_pass   http://127.0.0.1:9000;
        }

リンク

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages