@@ -13,6 +13,7 @@ const (
13
13
defaultTagName = "param"
14
14
queryTagValuePrefix = "query"
15
15
pathTagValuePrefix = "path"
16
+ formTagValuePrefix = "form"
16
17
)
17
18
18
19
// TagResolver is a function that decides from a field tag what parameter should be searched.
@@ -34,6 +35,9 @@ func TagNameResolver(tagName string) TagResolver {
34
35
// PathParamFunc is a function that returns value of specified http path parameter.
35
36
type PathParamFunc func (r * http.Request , key string ) string
36
37
38
+ // FormParamFunc is a function that returns value of specified form parameter.
39
+ type FormParamFunc func (r * http.Request , key string ) string
40
+
37
41
// Parser can Parse query and path parameters from http.Request into a struct.
38
42
// Fields struct have to be tagged such that either QueryParamTagResolver or PathParamTagResolver returns
39
43
// valid parameter name from the provided tag.
@@ -43,6 +47,7 @@ type PathParamFunc func(r *http.Request, key string) string
43
47
type Parser struct {
44
48
ParamTagResolver TagResolver
45
49
PathParamFunc PathParamFunc
50
+ FormParamFunc FormParamFunc
46
51
}
47
52
48
53
// DefaultParser returns query and path parameter Parser with intended struct tags
@@ -51,6 +56,7 @@ func DefaultParser() Parser {
51
56
return Parser {
52
57
ParamTagResolver : TagNameResolver (defaultTagName ),
53
58
PathParamFunc : nil , // keep nil, as there is no sensible default of how to get value of path parameter
59
+ FormParamFunc : nil , // keep nil, as there is no sensible default of how to get value of form parameter
54
60
}
55
61
}
56
62
@@ -61,6 +67,13 @@ func (p Parser) WithPathParamFunc(f PathParamFunc) Parser {
61
67
return p
62
68
}
63
69
70
+ // WithFormParamFunc returns a copy of Parser with set function for getting form parameters from http.Request.
71
+ // For more see Parser description.
72
+ func (p Parser ) WithFormParamFunc (f FormParamFunc ) Parser {
73
+ p .FormParamFunc = f
74
+ return p
75
+ }
76
+
64
77
// Parse accepts the request and a pointer to struct with its fields tagged with appropriate tags set in Parser.
65
78
// Such tagged fields must be in top level struct, or in exported struct embedded in top-level struct.
66
79
// All such tagged fields are assigned the respective parameter from the actual request.
@@ -113,6 +126,7 @@ type paramType int
113
126
const (
114
127
paramTypeQuery paramType = iota
115
128
paramTypePath
129
+ paramTypeForm
116
130
)
117
131
118
132
type taggedFieldIndexPath struct {
@@ -139,6 +153,7 @@ func (p Parser) findTaggedIndexPaths(typ reflect.Type, currentNestingIndexPath [
139
153
}
140
154
tag := typeField .Tag
141
155
pathParamName , okPath := p .resolvePath (tag )
156
+ formParamName , okForm := p .resolveForm (tag )
142
157
queryParamName , okQuery := p .resolveQuery (tag )
143
158
if okPath {
144
159
newPath := make ([]int , 0 , len (currentNestingIndexPath )+ 1 )
@@ -150,6 +165,16 @@ func (p Parser) findTaggedIndexPaths(typ reflect.Type, currentNestingIndexPath [
150
165
indexPath : newPath ,
151
166
})
152
167
}
168
+ if okForm {
169
+ newPath := make ([]int , 0 , len (currentNestingIndexPath )+ 1 )
170
+ newPath = append (newPath , currentNestingIndexPath ... )
171
+ newPath = append (newPath , i )
172
+ paths = append (paths , taggedFieldIndexPath {
173
+ paramType : paramTypeForm ,
174
+ paramName : formParamName ,
175
+ indexPath : newPath ,
176
+ })
177
+ }
153
178
if okQuery {
154
179
newPath := make ([]int , 0 , len (currentNestingIndexPath )+ 1 )
155
180
newPath = append (newPath , currentNestingIndexPath ... )
@@ -194,6 +219,11 @@ func (p Parser) parseParam(r *http.Request, path taggedFieldIndexPath) error {
194
219
if err != nil {
195
220
return err
196
221
}
222
+ case paramTypeForm :
223
+ err := p .parseFormParam (r , path .paramName , path .destValue )
224
+ if err != nil {
225
+ return err
226
+ }
197
227
case paramTypeQuery :
198
228
err := p .parseQueryParam (r , path .paramName , path .destValue )
199
229
if err != nil {
@@ -217,6 +247,22 @@ func (p Parser) parsePathParam(r *http.Request, paramName string, v reflect.Valu
217
247
return nil
218
248
}
219
249
250
+ func (p Parser ) parseFormParam (r * http.Request , paramName string , v reflect.Value ) error {
251
+ if r .Method != http .MethodPost && r .Method != http .MethodPut && r .Method != http .MethodPatch {
252
+ return fmt .Errorf ("struct's field was tagged for parsing the form parameter (%s) but request method is not POST, PUT or PATCH" , paramName )
253
+ }
254
+ if err := r .ParseForm (); err != nil {
255
+ return fmt .Errorf ("parsing form data: %w" , err )
256
+ }
257
+ if values , ok := r .Form [paramName ]; ok && len (values ) > 0 {
258
+ err := unmarshalValueOrSlice (values , v )
259
+ if err != nil {
260
+ return fmt .Errorf ("unmarshaling form parameter %s: %w" , paramName , err )
261
+ }
262
+ }
263
+ return nil
264
+ }
265
+
220
266
func (p Parser ) parseQueryParam (r * http.Request , paramName string , v reflect.Value ) error {
221
267
query := r .URL .Query ()
222
268
if values , ok := query [paramName ]; ok && len (values ) > 0 {
@@ -331,6 +377,10 @@ func (p Parser) resolvePath(fieldTag reflect.StructTag) (string, bool) {
331
377
return p .resolveTagWithModifier (fieldTag , pathTagValuePrefix )
332
378
}
333
379
380
+ func (p Parser ) resolveForm (fieldTag reflect.StructTag ) (string , bool ) {
381
+ return p .resolveTagWithModifier (fieldTag , formTagValuePrefix )
382
+ }
383
+
334
384
func (p Parser ) resolveQuery (fieldTag reflect.StructTag ) (string , bool ) {
335
385
return p .resolveTagWithModifier (fieldTag , queryTagValuePrefix )
336
386
}
0 commit comments