Ptt-official-app / Ptt-backend

PTT APP 的後端
BSD 3-Clause "New" or "Revised" License
208 stars 67 forks source link

[建議] 應該可以把目前 Response 的回應改成 struct 格式 #184

Closed Yu-Jack closed 3 years ago

Yu-Jack commented 3 years ago

在練習寫 go 途中發現也許有可以改善的地方 所以就來提案看看 ~ 歡迎各位指教!

原本作法的問題 / Existed Problem

目前寫法會都需要直接寫死 key 在 Response 的地方, 我想也許可以改用 struct 的方式

m := map[string]string{
    "error":             "find_board_error",
    "error_description": "get board for " + boardID + " failed",
}

實作細節 / Details of Implement

可以把統一會用到的 Response 結構放在 delivery/http/http.go 底下, 類似這樣

type ErrorResponse struct {
    Error  int    `json:"error"`
    ErrorDescription string `json:"error_description"`
}

再透過呼叫 func 去建立 Response

func NewErrorResponse(errorType string, description string) (response ErrorResponse) {
    return Response{
        Error:  errorType,
        ErrorDescription: description,
    }
}
// 接著透過 MarshalIndent 就可以製造出來 json response
resp := NewErrorResponse("error1", "error message")
b, _ := json.MarshalIndent(resp, "", "  ")

那如果說除了固定的 error error_description 之外, 想要合併其他額外訊息 舉例像是要在某一個特定 router 額外回傳 username (這邊 function 舉例叫做 GetUserName) 可以在檔案在最面建構一個 struct

type getUserNameResponse struct {
    ErrorResponse
    Username string `json:"username"`
}

接著使用的時候可以這樣去做轉換

response := getUserNameResponse{
    NewErrorResponse("errortype", "errordescription"),
    Username: "jack"
}
responseJson, _ := json.MarshalIndent(response, "", "")

想說那接著可以再把 json.MarshalIndent 包進去一層 這樣不管是用上面合併組出來的 struct 或是原本定義的 ErrorResponse 都可以轉換

func ToJson (response interface{}) []byte {
    responseJson, _ := json.MarshalIndent(response, "", "")
    return responseJson

}
// 外面就可以直接這樣使用 
w.Write(ToJson(response))

期程 / Schedule

相關文件 / Documents

PichuChen commented 3 years ago

這部分我覺得可以,不過比較高一個層級的是應該要定義出錯誤訊息的類別以及格式,這個我覺得可以合併入 Milestone 2做處理?

Yu-Jack commented 3 years ago

目前聽起來有以下兩種做法

  1. 跟著 Milestone1 邊寫邊改, 暫時改成 struct, 等待商業邏輯比較完整後, 再重新整理出錯誤訊息類別和格式
  2. 等到 Milestone1 大部分商業邏輯撰寫完成後, 會比較好規劃抽離共同錯誤訊息類別和格式, 然後放在 Milestone2 去改完

不過我有個想法, 我覺得可以先拿已經完成的 API 去進行修改, 畢竟這算一種重構 一來更改既有已完成的 API 相對應的風險比較少, 二來可以先定義該如何配置各個 struct 格式和位置 這樣就不用特地拉到 Milestone2 之後才能處理, 但大概流程會拆成兩塊

  1. 在 Milestone1 中更改選定幾支已完成 API
  2. 剩餘尚未修改的 API 一併移動到 Milestone2 去進行修改

這樣就可以一併進行, 到時候 Milestone2 的功能也可以直接參照之前定義好的格式去寫, 這樣的方式如何?

PichuChen commented 3 years ago

目前聽起來有以下兩種做法

  1. 跟著 Milestone1 邊寫邊改, 暫時改成 struct, 等待商業邏輯比較完整後, 再重新整理出錯誤訊息類別和格式
  2. 等到 Milestone1 大部分商業邏輯撰寫完成後, 會比較好規劃抽離共同錯誤訊息類別和格式, 然後放在 Milestone2 去改完

不過我有個想法, 我覺得可以先拿已經完成的 API 去進行修改, 畢竟這算一種重構 一來更改既有已完成的 API 相對應的風險比較少, 二來可以先定義該如何配置各個 struct 格式和位置 這樣就不用特地拉到 Milestone2 之後才能處理, 但大概流程會拆成兩塊

  1. 在 Milestone1 中更改選定幾支已完成 API
  2. 剩餘尚未修改的 API 一併移動到 Milestone2 去進行修改

這樣就可以一併進行, 到時候 Milestone2 的功能也可以直接參照之前定義好的格式去寫, 這樣的方式如何?

目前會稍微缺人力實作原有的 API 以及確認行為正確,因此行為正確確認之前其實做重構的意義不大。 但是在這階段應該可以先討論錯誤訊息的 struct 或者是 interface 應該要有哪些 method 我預估在討論上可能會需要至少兩週,所以這樣會剛好和 milestone 1 的進度接起來。

Yu-Jack commented 3 years ago

目前會稍微缺人力實作原有的 API 以及確認行為正確,因此行為正確確認之前其實做重構的意義不大。 但是在這階段應該可以先討論錯誤訊息的 struct 或者是 interface 應該要有哪些 method 我預估在討論上可能會需要至少兩週,所以這樣會剛好和 milestone 1 的進度接起來。

了解, 那不如就由我來負責幫忙整理目前現有 Response 的各種規格 整理完現有規格, 再來討論要用什麼樣的 struct or interface 去處理以及要如何放置?

PichuChen commented 3 years ago

OK

這部分有打算用什麼方式紀錄嗎? Google docs? Google sheet?

On Mon, Apr 19, 2021 at 2:43 PM YuJack @.***> wrote:

目前會稍微缺人力實作原有的 API 以及確認行為正確,因此行為正確確認之前其實做重構的意義不大。 但是在這階段應該可以先討論錯誤訊息的 struct 或者是 interface 應該要有哪些 method 我預估在討論上可能會需要至少兩週,所以這樣會剛好和 milestone 1 的進度接起來。

了解, 那不如就由我來負責幫忙整理目前現有 Response 的各種規格 整理完現有規格, 再來討論要用什麼樣的 struct or interface 去處理以及要如何放置?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/Ptt-official-app/Ptt-backend/issues/184#issuecomment-822213692, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAESRLTRX7RXS4RULZYG3G3TJPGHPANCNFSM427XFEEA .

Yu-Jack commented 3 years ago

目前初步想法是用 Google Sheet, 然後內容大該會如下 主要是去整理目前哪些 API 回的格式是固定的, 哪些是只有這個 API 才回傳 這樣就可以交集出共用的部分, 以及找出非共用的部分

API Name Success Response Failed Response
API Name 1 field1 field2 field3 field4
API Name 2 field1 field6 field3 field8
Yu-Jack commented 3 years ago

實際看著 API 文件和程式後, 簡單的用了六支 API 整理了一個版本

  1. 有幾支 API 的確回傳格式差不多, 某些部分可以共用 struct, 但有些只能用一次, 就變成只有他自己能用 struct
    • /v1/token 單獨一組
    • /v1/users/{{user_id}}/information 單獨一組
    • /v1/users/{{user_id}}/comments, /v1/users/{{user_id}}/articles 兩組部分可共用
    • /v1/users/{{user_id}}/preferences GET + POST 兩組全部可共用
  2. error 的部分很明顯可以把 find_userrec_error 這個錯誤型態拉成一個 struct

我不確定這樣整理有沒有用, 但想說還是先試著整理看看 雖然這樣用 Sheet 整理有點難看, 但用 Sheet 上下比對會比較快一點

PichuChen commented 3 years ago

作法上如果有其他地方的做法可以提出來參考這樣

y2468101216 commented 3 years ago

error 的格式可以統一成 struct,其他的我覺得不用

PichuChen commented 3 years ago

轉不轉成struct 可能也有效能上面可以測試的地方,理論上使用 map 效能應該是會比較差,但是我印象中差異小到其實可以忽略。

Yu-Jack commented 3 years ago

主要想轉換成 struct 有一個主要原因程式撰寫起來比較不會有 typo 的問題, 智能提示也比較有效

PichuChen commented 3 years ago

這個 ISSUE 目前還有在更新嗎? 不然兩週後要把他先關掉了喔?

Yu-Jack commented 3 years ago

好, 非常不好意思, 你可以先關掉了