-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdecorator.go
102 lines (89 loc) · 2.73 KB
/
decorator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package structural
import (
"fmt"
"io"
"net/http"
"strings"
)
/*
Summary:
Decaorator pattern helps in achieving single responsibility
Decorator pattern helps in adding additional pre and post
functionality to some function without actually touching the actual function
and making it complicated.
Example:
Basic examples demonstrated
then Real world examples of middlewares demostrated.
Benefit: Readability, Maintainability and Single Responsiblity.
1. It can be used when some pattern of pre and post functionality is required
over some functionality. Instead of making changes to original function we
decorate it.
2. It helps from complicating existing functions and helps them be small
3. Unit testing functionalities which are small is easy. Decorators can keep
things small.
*/
/* Basic Examples below */
type Hello func(s string) string
// DecorateV1 decorates hello function with some pre post prints
// v1 style: function as a type
// Decorated functon is returned as a new function and
// then called with parameters
func DecorateV1(f Hello) Hello {
return func(s string) string {
fmt.Printf("pre ")
v := f(s)
fmt.Printf("post:%v", v)
return v
}
}
// DecorateV2 decorates function
// v2 style: functions with complete signatures (more readable?)
// Decorated functon is returned as a new function and
// then called with parameters
func DecorateV2(f func(s string) string) func(string) string {
return func(s string) string {
fmt.Printf("pre ")
v := f(s)
fmt.Printf("post:%v", v)
return v
}
}
// DecorateV3 is another style to wrap functions in one call
// Decorated functon is passed as a parameter and also the parameters
// required for the core function is passed along. In this call only
// everything happens.
func DecorateV3(f func(s string) string, param string) string {
fmt.Printf("pre ")
v := f(param)
fmt.Printf("post:%v", v)
return v
}
/* Real work examples below */
// NewRelicMiddleWare decorates newrelic: middleware
// Uses DecoratorV1 style
func NewRelicMiddleWare(next http.Handler) http.Handler {
return http.HandlerFunc(
func(rw http.ResponseWriter, r *http.Request) {
io.WriteString(rw, "newrelic_start")
next.ServeHTTP(rw, r)
io.WriteString(rw, "newrelic_end")
},
)
}
// AuthorizeMiddleware decorates and terminates early if the
// the request is not having the right token
// Uses DecoratorV1 style
func AuthorizeMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(
func(rw http.ResponseWriter, r *http.Request) {
value := r.Header.Get("Authorization")
token := strings.Replace(value, "Bearer ", "", 1)
if token != "usertoken" {
http.Error(rw, "access denied", http.StatusForbidden)
return
}
io.WriteString(rw, "access_allowed")
next.ServeHTTP(rw, r)
},
)
}