-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample_test.go
More file actions
232 lines (192 loc) · 6.01 KB
/
example_test.go
File metadata and controls
232 lines (192 loc) · 6.01 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
package httpx_test
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"github.com/quentinalbertone/httpx"
)
// ExampleNewRouter demonstrates basic usage of the httpx router.
func ExampleNewRouter() {
// Create a new router with default logging and error handling
router := httpx.NewRouter(nil, nil)
// Add a simple GET route
router.GET("/hello", func(w http.ResponseWriter, r *http.Request) error {
return httpx.JSON(w, http.StatusOK, map[string]string{
"message": "Hello, World!",
})
})
// Create a test server
server := httptest.NewServer(router)
defer server.Close()
// Make a request to test the route
resp, err := http.Get(server.URL + "/hello")
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Status:", resp.StatusCode)
fmt.Println("Content-Type:", resp.Header.Get("Content-Type"))
// Output:
// Status: 200
// Content-Type: application/json
}
// ExampleGroup demonstrates route grouping and middleware.
func ExampleGroup() {
router := httpx.NewRouter(nil, nil)
// Create an API group with a common prefix
api := router.Group("/api")
// Create a v1 subgroup
v1 := api.Group("/v1")
// Add routes to the v1 group
v1.GET("/users", func(w http.ResponseWriter, r *http.Request) error {
users := []map[string]interface{}{
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"},
}
return httpx.JSON(w, http.StatusOK, users)
})
v1.POST("/users", func(w http.ResponseWriter, r *http.Request) error {
return httpx.JSON(w, http.StatusCreated, map[string]string{
"message": "User created",
})
})
server := httptest.NewServer(router)
defer server.Close()
// Test the grouped route
resp, err := http.Get(server.URL + "/api/v1/users")
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Status:", resp.StatusCode)
// Output:
// Status: 200
}
// ExampleNext demonstrates middleware usage with the Next function.
func ExampleNext() {
// Custom middleware that adds a header
headerMiddleware := func(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("X-Custom-Header", "middleware-value")
// Call the next handler in the chain
return httpx.Next(w, r)
}
router := httpx.NewRouter(nil, nil)
// Add a route with middleware
router.GET("/protected", headerMiddleware, func(w http.ResponseWriter, r *http.Request) error {
return httpx.JSON(w, http.StatusOK, map[string]string{
"message": "This response has a custom header",
})
})
server := httptest.NewServer(router)
defer server.Close()
resp, err := http.Get(server.URL + "/protected")
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Custom Header:", resp.Header.Get("X-Custom-Header"))
// Output:
// Custom Header: middleware-value
}
// ExampleJSON demonstrates the JSON utility function.
func ExampleJSON() {
handler := func(w http.ResponseWriter, r *http.Request) error {
data := struct {
Message string `json:"message"`
Count int `json:"count"`
}{
Message: "Hello from JSON",
Count: 42,
}
return httpx.JSON(w, http.StatusOK, data)
}
// Create a test request
req := httptest.NewRequest("GET", "/test", nil)
w := httptest.NewRecorder()
// Call the handler
err := handler(w, req)
if err != nil {
panic(err)
}
resp := w.Result()
fmt.Println("Status:", resp.StatusCode)
fmt.Println("Content-Type:", resp.Header.Get("Content-Type"))
// Output:
// Status: 200
// Content-Type: application/json
}
// ExampleListenAndServe demonstrates how to start an HTTP server with graceful
// shutdown and a CORS middleware applied globally via WithHTTPMiddleware.
func ExampleListenAndServe() {
// Create a router with routes
router := httpx.NewRouter(nil, nil)
router.GET("/api/users", func(w http.ResponseWriter, r *http.Request) error {
return httpx.JSON(w, http.StatusOK, []string{"Alice", "Bob"})
})
// CORSMiddleware sets CORS headers on every response and handles preflight requests.
corsMiddleware := func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
// Handle preflight requests
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
// Configure the server with custom settings
serverConf := func(server *http.Server) {
server.Addr = ":8080"
// You can set other server options here:
// server.ReadTimeout = 5 * time.Second
// server.WriteTimeout = 10 * time.Second
// server.IdleTimeout = 120 * time.Second
}
// Start the server with CORS enabled globally.
// WithHTTPMiddleware wraps the server's handler so it applies to all
// requests, including those that don't match any route.
ctx := context.Background()
if err := httpx.ListenAndServe(ctx, router,
serverConf,
httpx.WithHTTPMiddleware(corsMiddleware),
); err != nil {
fmt.Printf("Server error: %v\n", err)
}
}
// ExampleDecodeQueryParams_nestedStruct demonstrates using DecodeQueryParams with nested structs.
func ExampleDecodeQueryParams_nestedStruct() {
// Define structs with nested structure
type Location struct {
City string `query:"city"`
Country string `query:"country"`
}
type User struct {
Name string `query:"name"`
Age int `query:"age"`
Location Location `query:"loc"`
}
// Parse a URL with nested query parameters
u, _ := url.Parse("https://api.example.com/users?name=Alice&age=30&loc.city=Paris&loc.country=France")
// Decode query parameters into the struct
var filter User
err := httpx.DecodeQueryParams(*u, &filter)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
// Use the decoded values
fmt.Printf("Name: %s\n", filter.Name)
fmt.Printf("Age: %d\n", filter.Age)
fmt.Printf("City: %s\n", filter.Location.City)
fmt.Printf("Country: %s\n", filter.Location.Country)
// Output:
// Name: Alice
// Age: 30
// City: Paris
// Country: France
}