仍然在终端中输出一些日志消息,并且可以添加一个 BookCreate
handler 来创建一个新的 Book。
首先,让我们解决 handlers.go
。
package main
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"github.com/julienschmidt/httprouter"
)
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Welcome!\n")
}
// Handler for the books Create action
// POST /books
func BookCreate(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
book := &Book{}
if err := populateModelFromHandler(w, r, params, book); err != nil {
writeErrorResponse(w, http.StatusUnprocessableEntity, "Unprocessible Entity")
return
}
bookstore[book.ISDN] = book
writeOKResponse(w, book)
}
// Handler for the books index action
// GET /books
func BookIndex(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
books := []*Book{}
for _, book := range bookstore {
books = append(books, book)
}
writeOKResponse(w, books)
}
// Handler for the books Show action
// GET /books/:isdn
func BookShow(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
isdn := params.ByName("isdn")
book, ok := bookstore[isdn]
if !ok {
// No book with the isdn in the url has been found
writeErrorResponse(w, http.StatusNotFound, "Record Not Found")
return
}
writeOKResponse(w, book)
}
// Writes the response as a standard JSON response with StatusOK
func writeOKResponse(w http.ResponseWriter, m interface{}) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(&JsonResponse{Data: m}); err != nil {
writeErrorResponse(w, http.StatusInternalServerError, "Internal Server Error")
}
}
// Writes the error response as a Standard API JSON response with a response code
func writeErrorResponse(w http.ResponseWriter, errorCode int, errorMsg string) {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(errorCode)
json.
NewEncoder(w).
Encode(&JsonErrorResponse{Error: &ApiError{Status: errorCode, Title: errorMsg}})
}
//Populates a model from the params in the Handler
func populateModelFromHandler(w http.ResponseWriter, r *http.Request, params httprouter.Params, model interface{}) error {
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
if err != nil {
return err
}
if err := r.Body.Close(); err != nil {
return err
}
if err := json.Unmarshal(body, model); err != nil {
return err
}
return nil
}
我创建了两个函数,writeOKResponse
用于将 StatusOK
写入响应,其返回一个 model 或一个 model slice,writeErrorResponse
将在发生预期或意外错误时将 JSON
错误作为响应。像任何一个优秀的 gopher 一样,我们不应该 panic。我还添加了一个名为 populateModelFromHandler
的函数,它将内容从 body 中解析成所需的任何 model(struct)。在这种情况下,我们在 BookCreate
handler 中使用它来填充一个 Book
。
现在,我们来看看日志。我们简单地创建一个 Logger
函数,它包装了 handler 函数,并在执行 handler 函数之前和之后打印日志消息。
package main
import (
"log"
"net/http"
"time"
"github.com/julienschmidt/httprouter"
)
// A Logger function which simply wraps the handler function around some log messages
func Logger(fn func(w http.ResponseWriter, r *http.Request, param httprouter.Params)) func(w http.ResponseWriter, r *http.Request, param httprouter.Par