官术网_书友最值得收藏!

Creating handlers

We will now finish off our examples here by showing how you can create a Handler rather than just using HandleFunc. We are going to split the code that performs the request validation for our helloworld endpoint and the code that returns the response out into separate handlers to illustrate how it is possible to chain handlers.

Example 1.8 chapter1/reading_writing_json_7.go:

31 type validationHandler struct { 
32 next http.Handler
33 }
34
35 func newValidationHandler(next http.Handler) http.Handler {
36 return validationHandler{next: next}
37 }

The first thing we need to do when creating our own Handler is to define a struct field that will implement the methods in the Handlers interface. Since in this example, we are going to be chaining handlers together, the first handler, which is our validation handler, needs to have a reference to the next in the chain as it has the responsibility for calling ServeHTTP or returning a response.

For convenience, we have added a function that returns us a new handler; however, we could have just set the next field. This method, however, is better form as it makes our code a little easier to read and when we need to pass complex dependencies to the handler using a function to create, it keeps things a little neater:

37 func (h validationHandler) ServeHTTP(rw http.ResponseWriter, r  
*http.Request) {
38 var request helloWorldRequest
39 decoder := json.NewDecoder(r.Body)
40
41 err := decoder.Decode(&request)
42 if err != nil {
43 http.Error(rw, "Bad request", http.StatusBadRequest)
44 return
45 }
46
47 h.next.ServeHTTP(rw, r)
48 }

The previous code block illustrates how we would implement the ServeHTTP method. The only interesting thing to note here is the statement that begins at line 44. If an error is returned from decoding the request, we write a 500 error to the response, the handler chain would stop here. Only when no error is returned do we call the next handler in the chain and we do this simply by invoking its ServeHTTP method. To pass the name decoded from the request, we are simply setting a variable:

53 type helloWorldHandler struct{} 
54
55 func newHelloWorldHandler() http.Handler {
56 return helloWorldHandler{}
57 }
58
59 func (h helloWorldHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
60 response := helloWorldResponse{Message: "Hello " + name}
61
62 encoder := json.NewEncoder(rw)
63 encoder.Encode(response)
64 }

The helloWorldHandler type that writes the response does not look too different from when we were using a simple function. If you compare this to example 1.6, you will see that all we really have done is remove the request decoding.

Now the first thing I want to mention about this code is that it is purely to illustrate how you can do something, not that you should do something. In this simple case, splitting the request validation and response sending into two handlers adds a lot of needless complexity and it is not really making our code DRYer. The technique, however, is useful. When we examine authentication in a later chapter, you will see this pattern as it allows us to centralize our authentication logic and share it among handlers.

主站蜘蛛池模板: 北碚区| 乌兰浩特市| 砀山县| 祁连县| 高陵县| 班戈县| 城口县| 姜堰市| 湟源县| 鹰潭市| 日土县| 陆河县| 文安县| 红原县| 太和县| 新绛县| 武宣县| 昆山市| 宣威市| 柳江县| 石嘴山市| 静安区| 监利县| 平安县| 博湖县| 盐山县| 东至县| 浦东新区| 海宁市| 济阳县| 团风县| 天等县| 商河县| 赞皇县| 安顺市| 黔西| 金昌市| 大宁县| 罗平县| 开化县| 宣武区|