-
Notifications
You must be signed in to change notification settings - Fork 0
/
helpers.common.go
147 lines (124 loc) · 3.69 KB
/
helpers.common.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package main
import (
"context"
"encoding/json"
"errors"
"net"
"net/http"
"os"
"strings"
)
var ErrBookNotFound = errors.New("book not found")
type (
ContextKey string
missingFieldError string
)
const (
BookIDPrefix string = "b"
RequestIDPrefix string = "r"
RequestIDContextKey ContextKey = "request.id"
RequestNumberContextKey ContextKey = "request.number"
ConnContextKey ContextKey = "http-conn"
)
func (m missingFieldError) Error() string {
return string(m) + " is required"
}
// GetValueFromContext returns the value of a given key in the context
// if this key is not available, it returns an empty string.
func GetValueFromContext(ctx context.Context, contextKey ContextKey) string {
if val := ctx.Value(contextKey); val != nil {
return val.(string)
}
return ""
}
// GetRequestNumberFromContext returns the request number set in
// the context. if not previously set then it returns 0.
func GetRequestNumberFromContext(ctx context.Context) uint64 {
if val := ctx.Value(RequestNumberContextKey); val != nil {
return val.(uint64)
}
return 0
}
// DecodeCreateOrUpdateBookRequestBody is a helper function to read the content of a book creation or update request.
func DecodeCreateOrUpdateBookRequestBody(r *http.Request, book *Book) error {
if r.Body == nil {
return errors.New("invalid create book request body")
}
return json.NewDecoder(r.Body).Decode(book)
}
// ValidateCreateBookRequestBody is a helper function to check if the content of a book creation request is valid.
func ValidateCreateBookRequestBody(book *Book) error {
if len(book.Title) == 0 {
return missingFieldError("title")
}
if len(book.Description) == 0 {
return missingFieldError("description")
}
if len(book.Author) == 0 {
return missingFieldError("author")
}
if len(book.Price) == 0 {
return missingFieldError("price")
}
return nil
}
// ValidateUpdateBookRequestBody is a helper function to check if the content of a book update request is valid.
func ValidateUpdateBookRequestBody(book *Book) error {
if err := ValidateCreateBookRequestBody(book); err != nil {
return err
}
if len(book.ID) == 0 {
return missingFieldError("id")
}
if len(book.CreatedAt) == 0 {
return missingFieldError("created_at")
}
return nil
}
// GetRequestSourceIP helps find the source IP of the caller.
func GetRequestSourceIP(r *http.Request) string {
// Get IP from the X-REAL-IP header
ip := r.Header.Get("X-REAL-IP")
netIP := net.ParseIP(ip)
if netIP != nil {
return ip
}
// Get IP from X-FORWARDED-FOR header
ips := r.Header.Get("X-FORWARDED-FOR")
splitIps := strings.Split(ips, ",")
for _, ip := range splitIps {
netIP = net.ParseIP(ip)
if netIP != nil {
return ip
}
}
// Get IP from RemoteAddr
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
return ""
}
netIP = net.ParseIP(ip)
if netIP != nil {
return ip
}
return ""
}
// IsAppRunningInDocker checks the existence of the .dockerenv
// file at the root directory and returns a boolean result. This
// helps know if the App is running in a docker container or not.
func IsAppRunningInDocker() bool {
if _, err := os.Stat("/.dockerenv"); err == nil {
return true
}
return false
}
// SaveConnInContext is the hook used by the server under ConnContext.
// It sets the underlying connection into the request context for later
// use by ReadDeadline or WriteDeadline method on *CustomResponseWriter.
func SaveConnInContext(ctx context.Context, c net.Conn) context.Context {
return context.WithValue(ctx, ConnContextKey, c)
}
// GetConnFromContext returns the connection saved into the context.
func GetConnFromContext(ctx context.Context) net.Conn {
return ctx.Value(ConnContextKey).(net.Conn)
}