หัด Golang part 4

Phai Panda
3 min readSep 22, 2019

--

RESTful API กับ gorilla/mux pacakge

ความเดิม

เราสามารถเชื่อมต่อ Golang กับฐานข้อมูล MS SQL Server มาถึง part นี้เราจะเขียน RESTful API เพื่อขอ เพิ่ม แก้ไขและลบ resource ซึ่งเก็บไว้ในฐานข้อมูล bookdb

Create Database

สร้างฐานข้อมูลชื่อ bookdb พร้อมกับกำหนดให้เข้าใจภาษาไทย

CREATE DATABASE bookdbCOLLATE Thai_CI_AS

Create Table

สร้างตารางชื่อ book ไว้เก็บหนังสือ

CREATE TABLE book(    id INT NOT NULL IDENTITY PRIMARY KEY,    isbn VARCHAR(20) NOT NULL,    name VARCHAR(100),    authorName VARCHAR(100),    year CHAR(4),    totalPage INT,)

เพิ่มหนังสือเล่มที่หนึ่ง

INSERT INTO book(isbn, name, authorName, year, totalPage)VALUES('978-616-08-2539-4', 'พัฒนาเว็บแอปพลิเคชั่นด้วย JavaScript', 'จตุรพัชร์ พัฒนทรงศิวิไล', '2529', 460)

เพิ่มหนังสือเล่มที่สอง

INSERT INTO book(isbn, name, authorName, year, totalPage)VALUES('978-616-93108-0-8', 'BIG DATA SERIES I, Introduction to a Big Data Project', 'ดร.อสมา กุลวานิชไชยนันท์', '2561', 247)

ผล

gorilla/mux pacakge

เราต้องการ router เพื่อจัดการกับ URI ต่างๆเหล่านี้

  • GET /books/{id}
  • PUT /books/{id}
  • DELETE /books/{id}

โดย Golang เสนอให้จัดการที่ r *http.Request ซึ่งเพื่อนๆได้เห็นผ่านตามาบ้างแล้ว แต่การใช้ r.URL.Query นั้นลำบากและต้องเขียนโค้ดเยอะ เราพบว่ามี package ชื่อ gorilla/mux เป็นพระเอกของเรื่องนี้ครับ

ดึงมันลงมา

go get -u github.com/gorilla/mux

ด้วยเหตุนี้เราสามารถใช้ gorilla/mux มาจัดการ router ได้

router := mux.NewRouter()router.HandleFunc("/books", getAllBooks).Methods("GET")

จากนั้นระบุไปใน http

http.ListenAndServe(":8080", router)

Update Database Connection String

เดิม connection string ที่สร้างไว้ใน part ก่อนไม่ได้ระบุฐานข้อมูลไว้ เมื่อเรามีฐานข้อมูลชื่อ bookdb แล้วก็ต้องเพิ่มส่วนนี้เข้าไปด้วย

ส่วนที่ประกาศตัวแปร global ได้ว่า

var server = "localhost"var port = 1433var user = "sa"var password = "Password1234"var database = "bookdb"

จากนั้นแก้ไข connection string

connString := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s", server, user, password, port, database)

Create db and err global variables

เนื่องจากฟังก์ชัน getAllBooks จำต้องใช้ตัวแปร db ที่ได้มาจากการ connection เพื่อ query ข้อมูลจากฐานข้อมูลมาใส่ไว้ใน struct ดังนั้นจึงต้องสร้างตัวแปร db และ err ในระดับ global

ส่วนที่ประกาศตัวแปร global ได้ว่า

var db *sql.DBvar err error

จากนั้นแก้ไขส่วน assignment คือเปลี่ยนจากเครื่องหมาย := เป็น = เฉยๆ

db, err = sql.Open("mssql", connString)

ด้วยเหตุนี้ฟังก์ชัน checkVersion เดิมที่รับ db เข้ามาเป็นพารามิเตอร์ก็ไม่จำเป็นแล้ว

func checkVersion() {
...
}

Update book struct

แน่นอนครับ เพราะตาราง book สัมพันธ์กับ book struct เมื่อมี id เพิ่มที่ตารางย่อมส่งผลให้ struct ต้องเพิ่ม id ด้วย ได้ว่า

type book struct {    Id int `json:"id"`    Isbn string `json:"isbn"`    Name string `json:"name"`    AuthorName string `json:"authorName"`    Year string `json:"year"`    TotalPage int `json:"totalPage"`}

getAllBooks Function

และแล้วก็มาถึงพระเอกของเรา ฟังก์ชัน getAllBooks ซึ่งจะต้องใช้ตัวแปร db ขอ query ไปยังฐานข้อมูลผ่านฟังก์ช้น Query

func (db *DB) Query(query string, args ...interface{}) (*Rows, error)

ฟังก์ชันนี้ให้ผลเป็น *Rows กับ error

ตัว *Rows นี้เมื่อทำงานเสร็จแล้วก็ต้อง Close ด้วยนะ (ห้ามลืม)

func getAllBooks(w http.ResponseWriter, r *http.Request) {    rows, err := db.Query("SELECT * FROM book")    if err != nil {        log.Fatal("Database SELECT failed:", err.Error())    }    defer rows.Close()...

มาถึงส่วนสุดท้าย เมื่อได้ข้อมูลมาแล้วก็ต้องใส่เข้าไปใน struct ก่อนจะนำไปพ่นออกเป็น JSON ต่อไป

var b bookerr := rows.Scan(&b.Id, &b.Isbn, &b.Name, &b.AuthorName, &b.Year, &b.TotalPage)...json.NewEncoder(w).Encode(books)

โค้ดทั้งหมด

rerun server แล้วดูผลลัพธ์

เอาล่ะครับ เอาให้ได้เท่านี้ก่อน ถ้าได้แล้วไม่ติดขัดเราค่อยมาต่อ POST, PUT และ DELETE กันนะ

--

--

Responses (1)