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"])
}
}