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

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.

主站蜘蛛池模板: 昌平区| 正定县| 右玉县| 嘉善县| 昌江| 祁门县| 射洪县| 吐鲁番市| 泰宁县| 罗江县| 简阳市| 若尔盖县| 门源| 孟村| 精河县| 华池县| 黔西县| 二连浩特市| 定南县| 临猗县| 冕宁县| 濮阳县| 巴彦县| 文化| 连州市| 泰州市| 富民县| 宁陕县| 锡林浩特市| 若尔盖县| 南皮县| 潮安县| 佳木斯市| 新和县| 黄浦区| 全椒县| 上高县| 东乡县| 柘城县| 湘潭市| 凌云县|