かけ足で学ぶ Golang その5 〜Webサーバからデータベース操作〜


f:id:Naotsugu:20170417231928p:plain

前回はデータベースの操作方法を見てきました。

etc9.hatenablog.com

今回はWebサーバで受けた情報をデータベースに保存します。

POST でデータ保存

POSTで受けたリクエストボディの Json 文字列をデコードし、データベースにインサートしてみます。

func usersHandler(w http.ResponseWriter, r *http.Request) {

    if r.Method == "POST" {

        decoder := json.NewDecoder(r.Body)
        var u User
        err := decoder.Decode(&u)
        if err != nil {
            panic(err)
        }

        db := h2.Db()
        defer db.Close()
        db.Exec("INSERT INTO users(name, email) VALUES($1, $2);", u.Name, u.Email)

        defer r.Body.Close()

    }
}

前回までの内容を組み合わせただけです。

GET でデータ取得

GETリクエストで保存したデータをJsonで取得します。

func usersHandler(w http.ResponseWriter, r *http.Request) {

    if r.Method == "GET" {

        db := h2.Db()
        defer db.Close()
        rows, err := db.Query(`select id, name, email from users`)
        if err != nil {
            log.Fatal(err)
        }
        defer rows.Close()

        users := []User{}
        for rows.Next() {
            var u User
            rows.Scan(&u.Id, &u.Name, &u.Email)
            users = append(users, u)
        }

        json, err := json.Marshal(users)
        if err != nil {
            log.Fatal(err)
        }

        w.Header().Set("Content-Type", "application/json; charset=utf-8")
        w.Write(json)
    }
}

ユーザ型のスライスを []User{} で作り、rows.Next() でデータベースのレコードを取得しながら追加しています。

結果は Marshal してレスポンスに書き込んでいるだけです。

実行

POST で登録してみます。

f:id:Naotsugu:20170621231919p:plain

GETで取得してみます。

f:id:Naotsugu:20170621232244p:plain

登録されていますね。

まとめ

全体像は以下のようになりました。

package main

import (
    "log"
    "net/http"
    "encoding/json"
    "github.com/xxxxx/hello/h2"
)

type User struct {
    Id    int     `json:"id"`
    Name  string  `json:"name"`
    Email string  `json:"e-mail"`
}

func handler(w http.ResponseWriter, r *http.Request) {

    u := User{ Id : 1, Name : "Thome", Email : "thome@example.com"}

    json, err := json.Marshal(u)
    if err != nil {
        log.Fatal(err)
    }

    w.Header().Set("Content-Type", "application/json; charset=utf-8")
    w.Write(json)
}

func usersHandler(w http.ResponseWriter, r *http.Request) {

    if r.Method == "GET" {

        db := h2.Db()
        defer db.Close()
        rows, err := db.Query(`select id, name, email from users`)
        if err != nil {
            log.Fatal(err)
        }
        defer rows.Close()

        users := []User{}
        for rows.Next() {
            var u User
            rows.Scan(&u.Id, &u.Name, &u.Email)
            users = append(users, u)
        }

        json, err := json.Marshal(users)
        if err != nil {
            log.Fatal(err)
        }

        w.Header().Set("Content-Type", "application/json; charset=utf-8")
        w.Write(json)

    } else if r.Method == "POST" {

        decoder := json.NewDecoder(r.Body)
        var u User
        err := decoder.Decode(&u)
        if err != nil {
            panic(err)
        }

        db := h2.Db()
        defer db.Close()
        db.Exec("INSERT INTO users(name, email) VALUES($1, $2);", u.Name, u.Email)


        defer r.Body.Close()

    }

}


func main() {

    h2.StartH2()
    h2.InitDb()

    http.HandleFunc("/", handler)
    http.HandleFunc("/users", usersHandler)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("Error ListenAndServe : ", err)
    }
}
package h2

import (
    "log"
    "os"
    "net/http"
    "io"
    "os/exec"
    "path/filepath"
    _ "github.com/lib/pq"
    "database/sql"
    "time"
)

const (
    url  = "http://central.maven.org/maven2/com/h2database/h2/1.4.194/h2-1.4.194.jar"
    path = "lib/h2-1.4.194.jar"
)

func download(url string, path string) error {

    out, err := os.Create(path)
    if err != nil {
        return err
    }
    defer out.Close()

    resp, err := http.Get(url)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    if _, err := io.Copy(out, resp.Body); err != nil {
        return err
    }

    return nil
}


func StartH2() {

    if _, err := os.Stat(path); os.IsNotExist(err) {
        os.MkdirAll(filepath.Dir(path), 0755)
        if err := download(url, path); err != nil  {
            panic(err)
        }
    }

    cmd := exec.Command("java", "-cp",  path, "org.h2.tools.Server")
    cmd.Start()
    time.Sleep(3 * time.Second)
    log.Printf("H2 Started. PID[%v]", cmd.Process.Pid)
}


func StopH2() {
    err := exec.Command("java", "-cp",  path,
        "org.h2.tools.Server", "-tcpShutdown", "tcp://localhost:9092").Run()
    if err != nil {
        log.Fatal(err)
    }
}


func InitDb() {

    db := Db()
    defer db.Close()

    db.Exec(`
      CREATE TABLE users (
          id    INTEGER auto_increment PRIMARY KEY,
          name  VARCHAR(20),
          email VARCHAR(255)
      );
    `)
}

func Db() *sql.DB {
    db, err := sql.Open("postgres",
        "postgres://sa:pass@localhost:5435/~/testdb?sslmode=disable")
    if err != nil {
        panic(err)
    }
    return db
}