forked from swaggest/openapi-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoperation.go
174 lines (137 loc) · 4.34 KB
/
operation.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
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
package openapi
import (
"context"
"fmt"
"regexp"
"strings"
"github.com/swaggest/jsonschema-go"
)
// In defines value location in HTTP content.
type In string
// In values enumeration.
const (
InPath = In("path")
InQuery = In("query")
InHeader = In("header")
InCookie = In("cookie")
InFormData = In("formData")
InBody = In("body")
)
// ContentOption configures ContentUnit.
type ContentOption func(cu *ContentUnit)
// ContentUnit defines HTTP content.
type ContentUnit struct {
Structure interface{}
ContentType string
Format string
// HTTPStatus can have values 100-599 for single status, or 1-5 for status families (e.g. 2XX)
HTTPStatus int
// IsDefault indicates default response.
IsDefault bool
Description string
fieldMapping map[In]map[string]string
}
// ContentUnitPreparer defines self-contained ContentUnit.
type ContentUnitPreparer interface {
SetupContentUnit(cu *ContentUnit)
}
// WithContentType is a ContentUnit option.
func WithContentType(contentType string) func(cu *ContentUnit) {
return func(cu *ContentUnit) {
cu.ContentType = contentType
}
}
// WithHTTPStatus is a ContentUnit option.
func WithHTTPStatus(httpStatus int) func(cu *ContentUnit) {
return func(cu *ContentUnit) {
cu.HTTPStatus = httpStatus
}
}
// SetFieldMapping sets custom field mapping.
func (c *ContentUnit) SetFieldMapping(in In, fieldToParamName map[string]string) {
if len(fieldToParamName) == 0 {
return
}
if c.fieldMapping == nil {
c.fieldMapping = make(map[In]map[string]string)
}
c.fieldMapping[in] = fieldToParamName
}
// FieldMapping returns custom field mapping.
func (c ContentUnit) FieldMapping(in In) map[string]string {
return c.fieldMapping[in]
}
// OperationContext defines operation and processing state.
type OperationContext interface {
OperationInfo
OperationInfoReader
OperationState
Method() string
PathPattern() string
Request() []ContentUnit
Response() []ContentUnit
AddReqStructure(i interface{}, options ...ContentOption)
AddRespStructure(o interface{}, options ...ContentOption)
UnknownParamsAreForbidden(in In) bool
}
// OperationInfo extends OperationContext with general information.
type OperationInfo interface {
SetTags(tags ...string)
SetIsDeprecated(isDeprecated bool)
SetSummary(summary string)
SetDescription(description string)
SetID(operationID string)
AddSecurity(securityName string, scopes ...string)
}
// OperationInfoReader exposes current state of operation context.
type OperationInfoReader interface {
Tags() []string
IsDeprecated() bool
Summary() string
Description() string
ID() string
}
// OperationState extends OperationContext with processing state information.
type OperationState interface {
IsProcessingResponse() bool
ProcessingIn() In
SetIsProcessingResponse(isProcessingResponse bool)
SetProcessingIn(in In)
}
type ocCtxKey struct{}
// WithOperationCtx is a jsonschema.ReflectContext option.
func WithOperationCtx(oc OperationContext, isProcessingResponse bool, in In) func(rc *jsonschema.ReflectContext) {
return func(rc *jsonschema.ReflectContext) {
oc.SetIsProcessingResponse(isProcessingResponse)
oc.SetProcessingIn(in)
rc.Context = context.WithValue(rc.Context, ocCtxKey{}, oc)
}
}
// OperationCtx retrieves operation context from reflect context.
func OperationCtx(rc *jsonschema.ReflectContext) (OperationContext, bool) {
if oc, ok := rc.Value(ocCtxKey{}).(OperationContext); ok {
return oc, true
}
return nil, false
}
var regexFindPathParameter = regexp.MustCompile(`{([^}:]+)(:[^}]+)?(?:})`)
// SanitizeMethodPath validates method and parses path element names.
func SanitizeMethodPath(method, pathPattern string) (cleanMethod string, cleanPath string, pathParams []string, err error) {
method = strings.ToLower(method)
pathParametersSubmatches := regexFindPathParameter.FindAllStringSubmatch(pathPattern, -1)
switch method {
case "get", "put", "post", "delete", "options", "head", "patch", "trace":
break
default:
return "", "", nil, fmt.Errorf("unexpected http method: %s", method)
}
if len(pathParametersSubmatches) > 0 {
for _, submatch := range pathParametersSubmatches {
pathParams = append(pathParams, submatch[1])
if submatch[2] != "" { // Remove gorilla.Mux-style regexp in path.
pathPattern = strings.Replace(pathPattern, submatch[0], "{"+submatch[1]+"}", 1)
}
}
}
return method, pathPattern, pathParams, nil
}