Golangを使ったREST APIとjsonに関する個人的メモ
- 概要- Webシステムを外部から利用するためのプログラムの呼び出し規約(API)
- リソースの操作はHTTPメソッドによって指定(取得ならGETメソッド、書き込みならPOSTメソッド)される
- 結果はXMLやHTML、JSONなどで返される
- 処理結果はHTTPステータスコードで通知する
 
- RESTの基本仕様- セッション管理を行わない
- 情報を操作する命令の体系が予め定義(HTTPのGETやPOSTメソッドなどで)されている
- 汎用的な構文で識別される(URLやURIなど)
- 情報の内部に、別の情報を含めることができる
- リソースに対してURLが対応づけられる
- 「GET」なら取得、「POST」なら作成、「PUT」なら更新、「DELETE」なら削除のように処理する
 
- ここから先は、Golangの開発プロセスになる- go get -u github.com/gorilla/mux を行う
 
golangでシンプルなRESTful APIを作ってみよう!を、そのまま書き下してトレースで動きを追ってみました。
今回から、emacs + gdb を断念して、Visual Studio Code を使ってみました。うん、死ぬほど便利。
//C:\Users\ebata\go_rest\restful\main.go
 
package main
import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"github.com/gorilla/mux"
)
// Item representation
type Item struct {
	Title       string `json:"title"`
	Description string `json:"description"`
}
// Global, static list of items
var itemList = []Item{
	Item{Title: "Item A", Description: "The first item"},
	Item{Title: "Item B", Description: "The second item"},
	Item{Title: "Item C", Description: "The third item"},
}
// Controller for the / route (home)
func homePage(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "This is the home page. Welcome!")
}
// Contoller for the /items route
func returnAllItems(w http.ResponseWriter, r *http.Request) {
	respondWithJson(w, http.StatusOK, itemList)
}
// Controller for the /items/{id} route
func returnSingleItem(w http.ResponseWriter, r *http.Request) {
	// Get query parameters using Mux
	vars := mux.Vars(r)
	// Convert {id} parameter from string to int
	key, err := strconv.Atoi(vars["id"])
	// If {id} parameter is not valid in
	if err != nil {
		respondWithError(w, http.StatusBadRequest, "Invalid reqest payload")
		return
	}
	// If item with ID of {id} does not exist
	if key >= len(itemList) {
		respondWithError(w, http.StatusNotFound, "Item does not exist")
		return
	}
	respondWithJson(w, http.StatusOK, itemList[key])
}
func respondWithError(w http.ResponseWriter, code int, msg string) {
	respondWithJson(w, code, map[string]string{"error": msg})
}
func respondWithJson(w http.ResponseWriter, code int, payload interface{}) {
	response, _ := json.Marshal(payload)
	w.Header().Set("Content-type", "application/json")
	w.WriteHeader(code)
	w.Write(response)
}
func handleRequests() {
	myRouter := mux.NewRouter().StrictSlash(true)
	myRouter.HandleFunc("/", homePage)
	myRouter.HandleFunc("/items", returnAllItems)
	myRouter.HandleFunc("/items/{id}", returnSingleItem)
	log.Fatal(http.ListenAndServe(":8000", myRouter))
}
func main() {
	handleRequests()
}
http://localhost:8000/ → ホームページ、テキスト("This is the home page. Welcome!")を見せる
http://localhost:8000/items → "[{"title":"Item A","description":"The first item"},{"title":"Item B","description":"The second item"},{"title":"Item C","description":"The third item"}]"
http://localhost:8000/items/1 → {"title":"Item B","description":"The second item"}
なるほど、こんな感じで使うのね。
ーーーーー
jsonの使い方についても、Go言語でJSONを扱う を写経させて頂いた。
vro.json
[
    {"id":1, "name":"akane","birthday":"08-16","vivid_info":{"color":"red","weapon":"Rang"}},
    {"id":2, "name":"aoi","birthday":"06-17","vivid_info":{"color":"blue","weapon":"Impact"}},
    {"id":3, "name":"wakaba","birthday":"05-22","vivid_info":{"color":"green","weapon":"Blade"}},
    {"id":4, "name":"himawari","birthday":"07-23","vivid_info":{"color":"yellow","weapon":"Collider"}}, 
    {"id":0, "name":"rei"}    
]vro.go
package main
import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
)
/** JSONデコード用の構造体定義 */
type Person struct {
	Id       int      `json:"id"`
	Name     string   `json:"name"`
	Birthday string   `json:"birthday"`
	Vivid    struct { // 構造体の中にネストさせて構造体を定義
		Color  string `json:color`
		Weapon string `json:weapon`
	} `json:"vivid_info"`
}
func main() {
	// JSONファイル読み込み
	bytes, err := ioutil.ReadFile("vro.json")
	if err != nil {
		log.Fatal(err)
	}
	// JSONデコード
	var persons []Person
	if err := json.Unmarshal(bytes, &persons); err != nil {
		log.Fatal(err)
	}
	// デコードしたデータを表示
	for _, p := range persons {
		fmt.Printf("%d : %s : (%s) [%s]\n", p.Id, p.Name, p.Vivid.Color, p.Birthday)
	}
	// JSONデコード
	var decode_data interface{}
	if err := json.Unmarshal(bytes, &decode_data); err != nil {
		log.Fatal(err)
	}
	// 表示
	for _, data := range decode_data.([]interface{}) {
		var d = data.(map[string]interface{})
		fmt.Printf("%d : %s\n", int(d["id"].(float64)), d["name"])
	}
}