Skip to content

Commit 6d06413

Browse files
authored
Merge pull request #497 from marle3003/develop
v0.13.2
2 parents c9d2fc3 + 48ee6dc commit 6d06413

File tree

7 files changed

+477
-2
lines changed

7 files changed

+477
-2
lines changed

api/handler_schema.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import (
77
"io"
88
"mokapi/media"
99
openApiSchema "mokapi/providers/openapi/schema"
10+
"mokapi/runtime"
1011
avro "mokapi/schema/avro/schema"
1112
"mokapi/schema/encoding"
1213
"mokapi/schema/json/generator"
1314
jsonSchema "mokapi/schema/json/schema"
1415
"net/http"
1516
)
1617

18+
const toManyResults = "Your request matches multiple results. Please refine your parameters for a more precise selection."
19+
1720
type schemaInfo struct {
1821
Format string `json:"format,omitempty"`
1922
Schema interface{} `json:"schema,omitempty"`
@@ -34,6 +37,12 @@ type example struct {
3437

3538
func (h *handler) getExampleData(w http.ResponseWriter, r *http.Request) {
3639
body, err := io.ReadAll(r.Body)
40+
41+
if len(r.URL.RawQuery) > 0 || len(body) == 0 {
42+
h.getExampleByQuery(w, r)
43+
return
44+
}
45+
3746
if err != nil {
3847
http.Error(w, err.Error(), http.StatusBadRequest)
3948
return
@@ -89,6 +98,30 @@ func (h *handler) getExampleData(w http.ResponseWriter, r *http.Request) {
8998
writeJsonBody(w, examples)
9099
}
91100

101+
func (h *handler) getExampleByQuery(w http.ResponseWriter, r *http.Request) {
102+
103+
spec := r.URL.Query().Get("spec")
104+
name := r.URL.Query().Get("name")
105+
106+
specs := getSpecs(h.app, spec, name)
107+
if len(specs) > 1 {
108+
http.Error(w, fmt.Sprintf(toManyResults), http.StatusBadRequest)
109+
return
110+
} else if len(specs) == 0 {
111+
http.Error(w, fmt.Sprintf("No result found"), http.StatusBadRequest)
112+
return
113+
}
114+
115+
switch v := specs[0].(type) {
116+
case *runtime.HttpInfo:
117+
getOpenApiExample(w, r, v.Config)
118+
case *runtime.KafkaInfo:
119+
getAsyncApiExample(w, r, v.Config)
120+
default:
121+
http.Error(w, fmt.Sprintf("No result found"), http.StatusBadRequest)
122+
}
123+
}
124+
92125
func encodeExample(v interface{}, schema interface{}, schemaFormat string, contentTypes []string) ([]example, error) {
93126
var examples []example
94127
for _, str := range contentTypes {
@@ -294,3 +327,45 @@ func isOpenApi(format string) bool {
294327
return false
295328
}
296329
}
330+
331+
func getSpecs(app *runtime.App, spec, name string) []interface{} {
332+
var results []interface{}
333+
334+
switch spec {
335+
case "openapi":
336+
if name == "" {
337+
for _, s := range app.Http.List() {
338+
results = append(results, s)
339+
}
340+
}
341+
s := app.Http.Get(name)
342+
if s != nil {
343+
results = append(results, s)
344+
}
345+
case "asyncapi":
346+
if name == "" {
347+
for _, s := range app.Kafka.List() {
348+
results = append(results, s)
349+
}
350+
} else if s := app.Kafka.Get(name); s != nil {
351+
results = append(results, s)
352+
}
353+
default:
354+
if name == "" {
355+
for _, s := range app.Http.List() {
356+
results = append(results, s)
357+
}
358+
} else if s := app.Http.Get(name); s != nil {
359+
results = append(results, s)
360+
}
361+
if name == "" {
362+
for _, s := range app.Kafka.List() {
363+
results = append(results, s)
364+
}
365+
} else if s := app.Kafka.Get(name); s != nil {
366+
results = append(results, s)
367+
}
368+
}
369+
370+
return results
371+
}

api/handler_schema_asyncapi.go

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package api
2+
3+
import (
4+
"fmt"
5+
"mokapi/media"
6+
"mokapi/providers/asyncapi3"
7+
openApiSchema "mokapi/providers/openapi/schema"
8+
avro "mokapi/schema/avro/schema"
9+
"mokapi/schema/encoding"
10+
"mokapi/schema/json/generator"
11+
jsonSchema "mokapi/schema/json/schema"
12+
"net/http"
13+
)
14+
15+
func getAsyncApiExample(w http.ResponseWriter, r *http.Request, cfg *asyncapi3.Config) {
16+
channelName := r.URL.Query().Get("channel")
17+
msgName := r.URL.Query().Get("message")
18+
19+
var channel *asyncapi3.Channel
20+
if channelName == "" {
21+
if len(cfg.Channels) > 1 {
22+
http.Error(w, fmt.Sprintf(toManyResults), http.StatusBadRequest)
23+
return
24+
}
25+
for _, p := range cfg.Channels {
26+
channel = p.Value
27+
break
28+
}
29+
} else {
30+
if r := cfg.Channels[channelName]; r != nil {
31+
channel = r.Value
32+
}
33+
}
34+
if channel == nil {
35+
http.Error(w, fmt.Sprintf("No result found"), http.StatusBadRequest)
36+
return
37+
}
38+
39+
var msg *asyncapi3.Message
40+
if msgName == "" {
41+
if len(channel.Messages) > 1 {
42+
http.Error(w, fmt.Sprintf(toManyResults), http.StatusBadRequest)
43+
return
44+
}
45+
for _, m := range channel.Messages {
46+
msg = m.Value
47+
break
48+
}
49+
} else {
50+
msg = channel.Messages[msgName].Value
51+
}
52+
if msg == nil || msg.Payload == nil {
53+
http.Error(w, fmt.Sprintf("No result found"), http.StatusBadRequest)
54+
return
55+
}
56+
57+
var s *jsonSchema.Schema
58+
switch t := msg.Payload.Value.Schema.(type) {
59+
case *openApiSchema.Schema:
60+
s = openApiSchema.ConvertToJsonSchema(t)
61+
case *avro.Schema:
62+
s = t.Convert()
63+
default:
64+
var ok bool
65+
s, ok = t.(*jsonSchema.Schema)
66+
if !ok {
67+
http.Error(w, fmt.Sprintf("unsupported schema type: %T", t), http.StatusBadRequest)
68+
return
69+
}
70+
}
71+
72+
rnd, err := generator.New(&generator.Request{
73+
Path: generator.Path{
74+
&generator.PathElement{Schema: s},
75+
},
76+
})
77+
if err != nil {
78+
http.Error(w, err.Error(), http.StatusBadRequest)
79+
return
80+
}
81+
82+
ct := media.ParseContentType(msg.ContentType)
83+
var data []byte
84+
switch t := msg.Payload.Value.Schema.(type) {
85+
case *openApiSchema.Schema:
86+
data, err = t.Marshal(rnd, ct)
87+
case *avro.Schema:
88+
switch {
89+
case ct.Subtype == "json":
90+
data, err = encoding.NewEncoder(t.Convert()).Write(rnd, ct)
91+
case ct.Key() == "avro/binary" || ct.Key() == "application/octet-stream":
92+
data, err = t.Marshal(rnd)
93+
default:
94+
http.Error(w, fmt.Sprintf("unsupported schema type: %T", t), http.StatusBadRequest)
95+
return
96+
}
97+
default:
98+
data, err = encoding.NewEncoder(s).Write(rnd, ct)
99+
100+
}
101+
102+
w.Header().Set("Content-Type", ct.String())
103+
w.WriteHeader(http.StatusOK)
104+
_, _ = w.Write(data)
105+
}

api/handler_schema_openapi.go

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package api
2+
3+
import (
4+
"fmt"
5+
"mokapi/media"
6+
"mokapi/providers/openapi"
7+
openApiSchema "mokapi/providers/openapi/schema"
8+
"mokapi/schema/json/generator"
9+
"net/http"
10+
"strconv"
11+
"strings"
12+
)
13+
14+
func getOpenApiExample(w http.ResponseWriter, r *http.Request, cfg *openapi.Config) {
15+
pathName := r.URL.Query().Get("path")
16+
opName := r.URL.Query().Get("operation")
17+
status := r.URL.Query().Get("status")
18+
contentType := r.URL.Query().Get("contentType")
19+
if contentType == "" {
20+
contentType = r.Header.Get("Accept")
21+
}
22+
23+
var path *openapi.Path
24+
if pathName == "" {
25+
if len(cfg.Paths) > 1 {
26+
http.Error(w, fmt.Sprintf(toManyResults), http.StatusBadRequest)
27+
return
28+
}
29+
for _, p := range cfg.Paths {
30+
path = p.Value
31+
break
32+
}
33+
} else {
34+
if r := cfg.Paths[pathName]; r != nil {
35+
path = r.Value
36+
}
37+
}
38+
if path == nil {
39+
http.Error(w, fmt.Sprintf("No result found"), http.StatusBadRequest)
40+
return
41+
}
42+
43+
var op *openapi.Operation
44+
if opName == "" {
45+
if len(path.Operations()) > 1 {
46+
http.Error(w, fmt.Sprintf(toManyResults), http.StatusBadRequest)
47+
return
48+
}
49+
for _, o := range path.Operations() {
50+
op = o
51+
break
52+
}
53+
} else {
54+
op = path.Operation(strings.ToUpper(opName))
55+
}
56+
if op == nil {
57+
http.Error(w, fmt.Sprintf("No result found"), http.StatusBadRequest)
58+
return
59+
}
60+
61+
var res *openapi.Response
62+
if status == "" {
63+
val := op.Responses.Values()
64+
if len(val) > 1 {
65+
http.Error(w, fmt.Sprintf(toManyResults), http.StatusBadRequest)
66+
return
67+
}
68+
res = val[0].Value
69+
} else {
70+
i, err := strconv.Atoi(status)
71+
if err != nil {
72+
http.Error(w, fmt.Sprintf("Invalid status value: %s", status), http.StatusBadRequest)
73+
}
74+
res = op.Responses.GetResponse(i)
75+
}
76+
if res == nil {
77+
http.Error(w, fmt.Sprintf("No result found"), http.StatusBadRequest)
78+
return
79+
}
80+
81+
var s *openApiSchema.Schema
82+
var ct media.ContentType
83+
if len(contentType) == 0 {
84+
if len(res.Content) > 1 {
85+
http.Error(w, fmt.Sprintf(toManyResults), http.StatusBadRequest)
86+
return
87+
}
88+
for key, c := range res.Content {
89+
ct = media.ParseContentType(key)
90+
s = c.Schema
91+
break
92+
}
93+
} else {
94+
var mt *openapi.MediaType
95+
var err error
96+
ct, mt, err = openapi.NegotiateContentType(contentType, res)
97+
if err != nil {
98+
http.Error(w, err.Error(), http.StatusBadRequest)
99+
return
100+
}
101+
s = mt.Schema
102+
}
103+
if s == nil {
104+
http.Error(w, fmt.Sprintf("No result found"), http.StatusBadRequest)
105+
return
106+
}
107+
108+
rnd, err := generator.New(&generator.Request{
109+
Path: generator.Path{
110+
&generator.PathElement{Schema: openApiSchema.ConvertToJsonSchema(s)},
111+
},
112+
})
113+
if err != nil {
114+
http.Error(w, err.Error(), http.StatusBadRequest)
115+
return
116+
}
117+
118+
var data []byte
119+
data, err = s.Marshal(rnd, ct)
120+
if err != nil {
121+
http.Error(w, err.Error(), http.StatusBadRequest)
122+
return
123+
}
124+
125+
w.Header().Set("Content-Type", ct.String())
126+
w.WriteHeader(http.StatusOK)
127+
_, _ = w.Write(data)
128+
}

0 commit comments

Comments
 (0)