详解Go语言RESTful JSON API创建

2020-01-28 13:00:06丽君


package logger
import (
  "log"
  "net/http"
  "time"
)

func Logger(inner http.Handler, name string) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    start := time.Now()
    inner.ServeHTTP(w, r)
    log.Printf(
      "%st%st%st%s",
      r.Method,
      r.RequestURI,
      name,
      time.Since(start),
    )
  })
}

上面我们定义了一个Logger函数,可以给handler进行包装修饰。

这是Go语言中非常标准的惯用方式。其实也是函数式编程的惯用方式。 非常有效,我们只需要将Handler传入该函数, 然后它会将传入的handler包装一下,添加web日志和耗时统计功能。

应用Logger修饰器

要应用Logger修饰符, 我们可以创建router, 我们只需要简单的将我们所有的当前路由都包到其中, NewRouter函数修改如下:


func NewRouter() *mux.Router {

  router := mux.NewRouter().StrictSlash(true)
  for _, route := range routes {
    var handler http.Handler

    handler = route.HandlerFunc
    handler = Logger(handler, route.Name)

    router.
      Methods(route.Method).
      Path(route.Pattern).
      Name(route.Name).
      Handler(handler)
  }

  return router
}

现在再次运行我们的程序,我们就可以看到日志大概如下:

2014/11/19 12:41:39 GET /todos TodoIndex 148.324us

这个路由文件太疯狂...让我们重构它吧

路由routes文件现在已经变得稍微大了些, 下面我们将它分解成多个文件:

    routes.go router.go

package main

import "net/http"

type Route struct {
  Name    string
  Method   string
  Pattern   string
  HandlerFunc http.HandlerFunc
}

type Routes []Route

var routes = Routes{
  Route{
    "Index",
    "GET",
    "/",
    Index,
  },
  Route{
    "TodoIndex",
    "GET",
    "/todos",
    TodoIndex,
  },
  Route{
    "TodoShow",
    "GET",
    "/todos/{todoId}",
    TodoShow,
  },
}


package main

import (
  "net/http"

  "github.com/gorilla/mux"
)

func NewRouter() *mux.Router {
  router := mux.NewRouter().StrictSlash(true)
  for _, route := range routes {
    var handler http.Handler
    handler = route.HandlerFunc
    handler = Logger(handler, route.Name)

    router.
      Methods(route.Method).
      Path(route.Pattern).
      Name(route.Name).
      Handler(handler)

  }
  return router
}

另外再承担一些责任

到目前为止,我们已经有了一些相当好的样板代码(boilerplate), 是时候重新审视我们的处理器了。我们需要稍微多的责任。 首先修改TodoIndex,添加下面两行代码:


func TodoIndex(w http.ResponseWriter, r *http.Request) {
  todos := Todos{
    Todo{Name: "Write presentation"},
    Todo{Name: "Host meetup"},
  }
  w.Header().Set("Content-Type", "application/json; charset=UTF-8")
  w.WriteHeader(http.StatusOK)
  if err := json.NewEncoder(w).Encode(todos); err != nil {
    panic(err)
  }
}