-
Notifications
You must be signed in to change notification settings - Fork 0
/
openapi.go
120 lines (99 loc) · 2.96 KB
/
openapi.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
package gkBoot
import (
"context"
"fmt"
"github.com/swaggest/openapi-go/openapi3"
"github.com/yomiji/gkBoot/helpers"
"github.com/yomiji/gkBoot/kitDefaults"
gkRequest "github.com/yomiji/gkBoot/request"
"github.com/yomiji/gkBoot/service"
)
func GenerateSpecification(requests []ServiceRequest, optionalReflector *openapi3.Reflector) (
openapi3.Reflector,
error,
) {
reflector := openapi3.Reflector{}
if optionalReflector != nil {
reflector = *optionalReflector
}
if reflector.Spec == nil {
reflector.Spec = &openapi3.Spec{Openapi: "3.0.3"}
}
for _, request := range requests {
op := &openapi3.Operation{}
// request parts
method := string(request.Request.Info().Method)
name := request.Request.Info().Name
path := request.Request.Info().Path
if name == "" {
name = helpers.GetFriendlyRequestName(request.Request)
}
op = op.WithID(name)
if anyThingy, ok := request.Request.(gkRequest.OpenAPIExtended); ok {
op = op.WithMapOfAnything(anyThingy.OpenAPIExtensions())
}
if secured, ok := request.Request.(gkRequest.OpenAPISecure); ok {
securityList := secured.OpenAPISecurity()
op = op.WithSecurity(securityList...)
}
err := reflector.SetRequest(op, request.Request, method)
if err != nil {
return reflector, err
}
if srv, ok := request.Service.(service.OpenAPICompatible); ok {
for _, response := range srv.ExpectedResponses() {
// ignore error, we want 0 for code if uninterpretable
err = reflector.SetJSONResponse(op, response.Type, response.ExpectedCode)
if err != nil {
return reflector, err
}
}
} else {
return reflector, fmt.Errorf(
"service associated with %s is not OpenAPI Compatible",
name,
)
}
err = reflector.Spec.AddOperation(method, path, *op)
if err != nil {
return reflector, err
}
}
return reflector, nil
}
type openApiResponseValidatorService struct {
mappedResponses service.MappedResponses
next service.Service
}
func (o openApiResponseValidatorService) Execute(ctx context.Context, request interface{}) (
response interface{}, err error,
) {
response, err = o.next.Execute(ctx, request)
// pass through strict errors without checking API conformity
if err != nil {
return response, err
}
if j, ok2 := response.(kitDefaults.HttpCoder); ok2 {
if service.IsResponseValid(o.mappedResponses, response, j.StatusCode()) {
return response, err
}
}
return response, fmt.Errorf(
"possible api violation, type or code not matched for response",
)
}
func (o openApiResponseValidatorService) GetNext() service.Service {
return o.next
}
func (o *openApiResponseValidatorService) UpdateNext(nxt service.Service) {
o.next = nxt
}
func APIValidationWrapper(srv service.Service) service.Service {
if _, ok := srv.(service.OpenAPICompatible); !ok {
panic(fmt.Errorf("service is not OpenAPI compatible: %t", srv))
}
return &openApiResponseValidatorService{
mappedResponses: srv.(service.OpenAPICompatible).ExpectedResponses(),
next: srv,
}
}