在server.go
的NewServer中加入 getAccount
的router
Path
包含我們想要獲取的Account的id:/accounts/:id
server.go
func NewServer(store *db.Store) *Server {
server := &Server{store: store}
router := gin.Default()
// TODO: add routes
...
router.GET("/accounts/:id", server.getAccount)
server.router = router
return server
}
設定**getAccountRequest
用来存儲輸入參數,其中有一個int64
類型**的ID。
type getAccountRequest struct {
ID int64 `uri:"id" binding:"required,min=1"`
}
在**server.getAccount
處理器中,我們會像之前一樣操作。首先,我們宣告一個新的req
變量,類型為getAccountRequest,
並且調用ShouldBindUri
來取得ID**。
如果出現ErrNoRows
錯誤,我們返回400 Bad Request狀態碼,而預料之外的Error則向Client發送500 Internal Server Error
,反正成功GET為200 OK
。
type getAccountRequest struct {
ID int64 `uri:"id" binding:"required,min=1"`
}
func (server *Server) getAccount(ctx *gin.Context) {
var req getAccountRequest
if err := ctx.ShouldBindUri(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
account, err := server.store.GetAccount(ctx, req.ID)
if err != nil {
if err == sql.ErrNoRows {
ctx.JSON(http.StatusNotFound, errorResponse(err))
return
}
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
ctx.JSON(http.StatusOK, account)
}
重啟伺服器並開啟Postman測試。
新增一個請求,方法選擇GET,URL設定為 http://localhost:8080/accounts/1
。
結果成功,我們得到了200 OK狀態碼和找到的帳戶。
嘗試獲取不存在的帳戶,例如ID為100的帳戶。
這次我們得到了404 Not Found狀態碼,錯誤:sql no rows in result set
。
使用一個負的ID再次嘗試,例如-**1**
。
我們得到了400 Bad Request狀態碼和關於驗證失敗的錯誤消息。
隨著時間的推移,我們資料庫中儲存的帳戶數量可能會增長到一個非常大的數字。
因此不應該在單一API呼叫中查詢和返回所有記錄,而是改為使用listAccount
。
與**getAccount
不同不再透過URI或是Body來取得參數,而是改用Query String
。**
page_id
: which is the index number of the page we want to getpage_size
: which is the maximum number of records can be returned in 1 pagehttp://localhost:8080/accounts?page_id=1&page_size=5
在server.go
的NewServer中加入 listAccount
的router
server.go
func NewServer(store *db.Store) *Server {
server := &Server{store: store}
router := gin.Default()
// TODO: add routes
...
router.GET("/accounts", server.listAccount)
server.router = router
return server
}
設定listAccountRequest
用来存儲輸入參數,其中有一個**int64
類型**的ID。
PageID
和PageSize
。uri
獲取這些參數,而是從Query String
中獲取的,所以改為使用**form tag
**。PageID
**的最小值應該是1。PageSize
**,我們不希望它太大或太小,所以我設定其最小限制是5條記錄,最大限制是10條記錄。type listAccountRequest struct {
PageID int32 `form:"page_id" binding:"required,min=1"`
PageSize int32 `form:"page_size" binding:"required,min=5,max=10"`
}
在**server.listAccount
處理器中,我們會像之前一樣操作。首先,我們宣告一個新的req
**變量,類型為listAccountRequest**,**
但在這會調用ShouldBindQuery
來取得PageID
與PageSize
。
如果出現Query String
錯誤,我們返回400 Bad Request
狀態碼
接下來調用**server.store.ListAccounts()
從資料庫中查詢一頁的帳戶記錄,必須為其中的2個字段提供值:Limit
和Offset
**。
Limit
就是req.PageSize
。Offset
是資料庫應該跳過的記錄數,因此我們必須使用這個公式來計算它:(req.PageID - 1) * req.PageSize
****ListAccounts
**如果發生錯誤,那麼我們則向Client發送500 Internal Server Error
,反之成功GET為200 OK
。
在測試時嘗試獲取page_id=100
且page_size=5
的Accounts,會獲得 null response body,雖然這是可以接受的結果,但更好的結果是要returns an empty list
接下來修改SQLC的參數emit_empty_slices
:
sqlc.yaml
emit_empty_slices: true
make sqlc
type getAccountRequest struct {
ID int64 `uri:"id" binding:"required,min=1"`
}
func (server *Server) getAccount(ctx *gin.Context) {
var req getAccountRequest
if err := ctx.ShouldBindUri(&req); err != nil {
ctx.JSON(http.StatusBadRequest, errorResponse(err))
return
}
account, err := server.store.GetAccount(ctx, req.ID)
if err != nil {
if err == sql.ErrNoRows {
ctx.JSON(http.StatusNotFound, errorResponse(err))
return
}
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
return
}
ctx.JSON(http.StatusOK, account)
}
重啟伺服器並開啟Postman測試。
新增一個請求,方法選擇GET,URL設定為 http://{{base_url}}/accounts?page_id=1&page_size=5
結果成功,我們得到了200 OK狀態碼和找到的帳戶。
嘗試獲取page_id=100
且page_size=5
的Accounts,這次會獲得 null response body,雖然這是可以接受的結果,但更好的結果是要returns an empty list
接下來修改SQLC的參數emit_empty_slices
:
sqlc.yaml
emit_empty_slices: true
make sqlc
這次我們得到了404 Not Found狀態碼,錯誤:sql no rows in result set
。
使用一個負的ID再次嘗試,例如-**1**
。
我們得到了400 Bad Request狀態碼和關於驗證失敗的錯誤消息。
嘗試使用超出限制的page_size
:
請求:更改**page_size
**為20,這超出了最大限制10。
回應:獲得了400 Bad Request的狀態碼。
錯誤訊息:指出**page_size
的驗證在max
**標籤上失敗。
嘗試使用page_id
為0:
請求:設置**page_id
**為0。
回應:仍然獲得400 Bad Request的狀態碼。
錯誤訊息:因為**page_id
的驗證在required
**標籤上失敗。這裡的情況是,在驗證器套件中,任何零值都會被認為是缺失的。在這種情況下這是可以接受的,因為我們無需設置第0頁。