設計API回傳/接收JSON


Posted by Nacho on 2020-04-01

實作目標

延續之前的寫的Simple RESTful API,加入解析JSON的功能使API可以存取JSON資料。

the small wiki of JSON(參考)

  • JSON 的全名叫做 JavaScript Object Notation
  • 是一個存取與交換資料的輕量格式(輕量大概是跟XML比較出來的)
  • 通常被Server用來最為傳給網頁的資料

開始

階段一: 專案基礎建設

先進行專案的基礎建設,開一個新專案叫simpleJson,新增一個檔案叫simplejson.go,並導入了套件gorilla/mux。用這行指令$ go get -u github.com/gorilla/mux取得這個套件。

package main

import(
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

func home(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "welcome home!")
}

func main(){
    router := mux.NewRouter().StrictSlash(true)
    router.HandleFunc("/", home)
    log.Fatal(http.ListenAndServe(":8080", router))
}

階段二: 取得JSON格式的資料

首先,宣告一個叫event的結構,json格式的宣告附在value之後。宣告一個allEvents的slice用來存取多筆event,並在events初始化兩筆event,另外,還需要匯入encoding套件裡的json函示庫,之後要透過它來解析json資料。
注意: 在struct的宣告中key必須是大寫開頭,否則會拋出錯誤(切身經驗),但可以在json內將key轉換成小寫!! 原因

import(
    "encoding/json"
    ...
)

type event struct {
    Id string `json:"id"`
    Title string `json:"title"`
    Desc string `json:"desc"`
}

type allEvents []event

var events = allEvents{  // 加入一些events
    {
        Id: "1", Title: "test1", Desc: "this is the first test",
    },
    {
        Id: "2", Title: "test2", Desc: "this is the second test",
    },
}

加入一個getAllEvents的func,內容是將回傳值透過json加入解析後的events資料。打開Terminal使用curl -X GET localhost:8080/events可以看到回傳值是一串JSON解析後的格式,如果與fmt.Println印出來的結果相比應該會發現JSON提供完整的key/value。

func getAllEvents(w http.ResponseWriter, r *http.Request){
    json.NewEncoder(w).Encode(events)
    fmt.Println("call all events api")
    // fmt.Println(events)
}

func main(){
    router := mux.NewRouter().StrictSlash(true)
    router.HandleFunc("/", home)
    router.HandleFunc("/events", getAllEvents).Methods("GET")
    log.Fatal(http.ListenAndServe(":8080", router))
}

階段三: 存取JSON資料

新增一筆event,這裡使用到io套件的ioutil功能,ioutil.ReadAll(r.Body)讀取API傳來的HTTP body。Go透過 json.Unmarshal 將JSON字串轉成 struct(json.marshal則相反),所以我將reqBody的值轉換後指給newEvent,並將它加入events中,最後回傳成功結果給client。打開Terminal用curl -X POST -d '{"id":"3","title":"test3","desc":"This is the third test"}' localhost:8080/event

import(
    "io/ioutil"
    ...
)

func createEvent(w http.ResponseWriter, r *http.Request){
    var newEvent event
    reqBody, _ := ioutil.ReadAll(r.Body)
    // 轉換成 event struct
    json.Unmarshal(reqBody, &newEvent)
    events = append(events, newEvent)
    // 201 created status code
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(newEvent)
}

func main(){
    ..
    router.HandleFunc("/event", createEvent).Methods("POST")
    ..
}

取得其中一筆event,假設我在Terminal輸入curl -X GET localhost:8080/events/1,mux幫我解析這串url,若是發現符合events/{id}的格式,mux.Vars(r)["id"]幫我把id的值取出給路徑變數,接著在迴圈中找出有等於這個id的event,並回傳給client。

func getOneEvent(w http.ResponseWriter, r *http.Request) {
    // 宣告路徑變數,解析 url取出 id 的值
    eventId := mux.Vars(r)["id"]
    // loop 找出對應 id
    for _, singleEvent := range events {
        if singleEvent.Id == eventId {
            json.NewEncoder(w).Encode(singleEvent)
        }
    }
}

func main(){
    ..
    router.HandleFunc("/events/{id}", getOneEvent).Methods("GET")
    ..
}

另外,還有編輯跟刪除event的功能,因為概念與新增和讀取是相似的,所以不多做紀錄。
完整範例參考

筆記參考
Creating a RESTful API With Golang


#Go JSON #GO marshal #RESTful API







Related Posts

W16 直播檢討

W16 直播檢討

How to solve the perpetual loading issue in Evernote? Evernote 一直轉圈圈的解決辦法

How to solve the perpetual loading issue in Evernote? Evernote 一直轉圈圈的解決辦法

Key Sequence Detection

Key Sequence Detection


Comments