-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample_test.go
More file actions
235 lines (198 loc) · 5.59 KB
/
Copy pathexample_test.go
File metadata and controls
235 lines (198 loc) · 5.59 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
233
234
235
package roamer_test
import (
"bytes"
"fmt"
"io"
"net/http"
"net/url"
"github.com/slipros/roamer"
"github.com/slipros/roamer/decoder"
"github.com/slipros/roamer/formatter"
"github.com/slipros/roamer/parser"
)
// ExampleRoamer demonstrates basic usage of the roamer package
// for parsing HTTP requests into Go structures.
func ExampleRoamer() {
// Define a structure to hold parsed request data
type UserRequest struct {
ID int `query:"id"`
Name string `json:"name"`
UserAgent string `header:"User-Agent"`
Email string `json:"email" string:"trim_space"`
}
// Create a roamer instance with parsers, decoders, and formatters
r := roamer.NewRoamer(
roamer.WithParsers(
parser.NewQuery(), // Parse URL query parameters
parser.NewHeader(), // Parse HTTP headers
),
roamer.WithDecoders(
decoder.NewJSON(), // Decode JSON request bodies
),
roamer.WithFormatters(
formatter.NewString(), // Apply string formatting
),
)
// Create a sample HTTP request
req := createSampleRequest()
// Parse the request
var userData UserRequest
err := r.Parse(req, &userData)
if err != nil {
fmt.Printf("Error parsing request: %v\n", err)
return
}
fmt.Printf("Parsed data:\n")
fmt.Printf("ID: %d\n", userData.ID)
fmt.Printf("Name: %s\n", userData.Name)
fmt.Printf("Email: %s\n", userData.Email)
fmt.Printf("User-Agent: %s\n", userData.UserAgent)
// Output:
// Parsed data:
// ID: 123
// Name: John Doe
// Email: john@example.com
// User-Agent: test-agent
}
// ExampleParse demonstrates the generic Parse function for direct value retrieval.
func ExampleParse() {
// Define a structure
type ProductRequest struct {
Category string `query:"category"`
MinPrice float64 `query:"min_price"`
MaxPrice float64 `query:"max_price"`
}
// Create roamer instance
r := roamer.NewRoamer(
roamer.WithParsers(parser.NewQuery()),
)
// Create request with query parameters
req := &http.Request{
Method: "GET",
URL: &url.URL{
RawQuery: "category=electronics&min_price=100.50&max_price=999.99",
},
Header: make(http.Header),
}
// Use generic Parse function
product, err := roamer.Parse[ProductRequest](r, req)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Category: %s\n", product.Category)
fmt.Printf("Price range: $%.2f - $%.2f\n", product.MinPrice, product.MaxPrice)
// Output:
// Category: electronics
// Price range: $100.50 - $999.99
}
// ExampleMiddleware demonstrates using roamer as HTTP middleware.
func ExampleMiddleware() {
type APIRequest struct {
Action string `query:"action"`
UserID int `query:"user_id"`
}
// Create roamer instance
r := roamer.NewRoamer(
roamer.WithParsers(parser.NewQuery()),
)
// Create middleware
middleware := roamer.Middleware[APIRequest](r)
// Sample handler
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var data APIRequest
if err := roamer.ParsedDataFromContext(r.Context(), &data); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
fmt.Printf("Action: %s, User ID: %d\n", data.Action, data.UserID)
w.WriteHeader(http.StatusOK)
})
// Wrap handler with middleware
wrappedHandler := middleware(handler)
// Create test request
req := &http.Request{
Method: "GET",
URL: &url.URL{
RawQuery: "action=update&user_id=456",
},
Header: make(http.Header),
}
// Simulate request handling
wrappedHandler.ServeHTTP(&mockResponseWriter{}, req)
// Output:
// Action: update, User ID: 456
}
// ExampleWithPreserveBody demonstrates how to preserve the request body
// after parsing so downstream handlers can read it again.
func ExampleWithPreserveBody() {
type RequestData struct {
Message string `json:"message"`
UserID int `json:"user_id"`
}
// Create roamer with body preservation enabled
r := roamer.NewRoamer(
roamer.WithDecoders(decoder.NewJSON()),
roamer.WithPreserveBody(), // Enable body preservation
)
// Create a sample request with JSON body
jsonBody := `{"message": "Hello, World!", "user_id": 123}`
req := &http.Request{
Method: "POST",
URL: &url.URL{
Path: "/api/data",
},
Header: http.Header{
"Content-Type": {"application/json"},
},
Body: &readCloser{bytes.NewBufferString(jsonBody)},
ContentLength: int64(len(jsonBody)),
}
// Parse the request (this normally consumes the body)
var data RequestData
err := r.Parse(req, &data)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Parsed: Message=%s, UserID=%d\n", data.Message, data.UserID)
// Read the body again - this works because preservation is enabled
bodyBytes, err := io.ReadAll(req.Body)
if err != nil {
fmt.Printf("Error reading body: %v\n", err)
return
}
fmt.Printf("Body still available: %s\n", string(bodyBytes))
// Output:
// Parsed: Message=Hello, World!, UserID=123
// Body still available: {"message": "Hello, World!", "user_id": 123}
}
// Helper functions for examples
func createSampleRequest() *http.Request {
jsonBody := `{"name": "John Doe", "email": " john@example.com "}`
req := &http.Request{
Method: "POST",
URL: &url.URL{
RawQuery: "id=123",
},
Header: http.Header{
"Content-Type": {"application/json"},
"User-Agent": {"test-agent"},
},
Body: &readCloser{bytes.NewBufferString(jsonBody)},
ContentLength: int64(len(jsonBody)),
}
return req
}
type mockResponseWriter struct {
statusCode int
}
func (m *mockResponseWriter) Header() http.Header {
return make(http.Header)
}
func (m *mockResponseWriter) Write([]byte) (int, error) {
return 0, nil
}
func (m *mockResponseWriter) WriteHeader(statusCode int) {
m.statusCode = statusCode
}