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

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.

主站蜘蛛池模板: 双城市| 当雄县| 新龙县| 永嘉县| 景德镇市| 十堰市| 太和县| 冷水江市| 孟州市| 襄城县| 长治县| 开封县| 霸州市| 志丹县| 阳新县| 彩票| 田东县| 政和县| 义乌市| 曲阜市| 德惠市| 韩城市| 凉城县| 信宜市| 宽甸| 宜春市| 出国| 东海县| 湘潭县| 五寨县| 南和县| 张家界市| 临夏县| 安徽省| 沂水县| 新丰县| 龙山县| 永德县| 中卫市| 东辽县| 平湖市|