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

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.

主站蜘蛛池模板: 阿拉善右旗| 阳山县| 临西县| 贵阳市| 奉化市| 墨江| 桃江县| 油尖旺区| 廉江市| 富源县| 开原市| 广丰县| 墨竹工卡县| 双柏县| 通道| 临海市| 福建省| 赤峰市| 衡水市| 始兴县| 定南县| 广州市| 柘城县| 安远县| 会宁县| 定边县| 萍乡市| 威宁| 伊川县| 兴化市| 盐边县| 邯郸县| 宁武县| 都昌县| 福鼎市| 桃园市| 甘孜| 仁怀市| 犍为县| 岳阳市| 灵宝市|