Skip to content

Commit 99c6059

Browse files
author
tdakkota
committed
feat(gen): generate API metadata definition
1 parent 5d51e9b commit 99c6059

File tree

4 files changed

+231
-132
lines changed

4 files changed

+231
-132
lines changed

gen/_template/handlers.tmpl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ func (s *{{ if $op.WebhookInfo }}Webhook{{ end }}Server) handle{{ $op.Name }}Req
5252
s.requests.Add(ctx, 1, otelAttrs...)
5353

5454
var (
55-
op = operations[{{ quote $op.Name }}]
55+
{{- if $op.WebhookInfo }}
56+
op = getWebhooks().{{ $op.Name }}
57+
{{- else }}
58+
op = getPaths().{{ $op.Name }}
59+
{{- end }}
5660
recordError = func(stage string, err error) {
5761
span.RecordError(err)
5862
span.SetStatus(codes.Error, stage)

gen/_template/ogenreflect.tmpl

Lines changed: 101 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,110 @@
33
{{ $pkg := $.Package }}
44
{{ template "header" $ }}
55

6-
var operations = map[string]ogenreflect.Operation{
7-
{{- range $op := $.Operations }}
8-
{{- template "ogenreflect/operation" $op }}
9-
{{ end }}
6+
// API is generated API metadata.
7+
var API = api{
8+
{{- with $ops := $.Operations }}
9+
Paths: paths{
10+
{{- range $op := $ops }}
11+
{{ $op.Name }}: {{ template "ogenreflect/operation" $op -}},
12+
{{- end }}
13+
},
14+
{{- end }}
15+
{{- with $ops := $.Webhooks }}
16+
Webhooks: webhooks{
17+
{{- range $op := $ops }}
18+
{{ $op.Name }}: {{ template "ogenreflect/operation" $op -}},
19+
{{- end }}
20+
},
21+
{{- end }}
22+
}
1023

11-
{{- range $op := $.Webhooks }}
12-
{{- template "ogenreflect/operation" $op }}
13-
{{ end }}
24+
type api struct {
25+
{{- if $.Operations }}
26+
Paths paths
27+
{{- end }}
28+
{{- if $.Webhooks }}
29+
Webhooks webhooks
30+
{{- end }}
31+
}
32+
33+
{{ with $ops := $.Operations }}
34+
type paths struct {
35+
{{- range $op := $ops }}
36+
{{ $op.Name }} ogenreflect.Operation
37+
{{- end }}
38+
}
39+
40+
func getPaths() paths {
41+
return API.Paths
42+
}
43+
44+
// FindByName finds operation by ogen name.
45+
func (p paths) FindByName(name string) (op ogenreflect.Operation, _ bool) {
46+
switch name {
47+
{{- range $op := $ops }}
48+
case {{ quote $op.Name }}:
49+
return p.{{ $op.Name }}, true
50+
{{- end }}
51+
default:
52+
return op, false
53+
}
54+
}
55+
56+
// FindByOperationID finds operation by operationId.
57+
func (p paths) FindByOperationID(operationID string) (op ogenreflect.Operation, _ bool) {
58+
switch operationID {
59+
{{- range $op := $ops }}{{- with $id := $op.Spec.OperationID }}
60+
case {{ quote $id }}:
61+
return p.{{ $op.Name }}, true
62+
{{- end }}{{- end }}
63+
default:
64+
return op, false
65+
}
66+
}
67+
{{- end }}
68+
69+
{{ with $ops := $.Webhooks }}
70+
type webhooks struct {
71+
{{- range $op := $ops }}
72+
{{ $op.Name }} ogenreflect.Operation
73+
{{- end }}
74+
}
75+
76+
func getWebhooks() webhooks {
77+
return API.Webhooks
1478
}
1579

80+
// FindByName finds operation by ogen name.
81+
func (w webhooks) FindByName(name string) (op ogenreflect.Operation, _ bool) {
82+
switch name {
83+
{{- range $op := $ops }}
84+
case {{ quote $op.Name }}:
85+
return w.{{ $op.Name }}, true
86+
{{- end }}
87+
default:
88+
return op, false
89+
}
90+
}
91+
92+
// FindByOperationID finds operation by operationId.
93+
func (w webhooks) FindByOperationID(operationID string) (op ogenreflect.Operation, _ bool) {
94+
switch operationID {
95+
{{- range $op := $ops }}{{- with $id := $op.Spec.OperationID }}
96+
case {{ quote $id }}:
97+
return w.{{ $op.Name }}, true
98+
{{- end }}{{- end }}
99+
default:
100+
return op, false
101+
}
102+
}
103+
{{- end }}
104+
16105
{{ end }}
17106

18-
{{ define "ogenreflect/operation" }}
19-
{{- /*gotype: github.com/ogen-go/ogen/gen/ir.Operation*/ -}}{{ $op := $ }}
20-
{{ quote $op.Name }}: ogenreflect.Operation{
107+
{{ define "ogenreflect/operation" -}}
108+
{{- /*gotype: github.com/ogen-go/ogen/gen/ir.Operation*/ -}}{{ $op := $ -}}
109+
ogenreflect.Operation{
21110
Name: {{ quote $op.Name }},
22111
ID: {{ quote $op.Spec.OperationID }},
23112
Types: ogenreflect.OperationTypes{
@@ -79,8 +168,8 @@ var operations = map[string]ogenreflect.Operation{
79168
},
80169
{{- end }}
81170
},
82-
},
83-
{{ end }}
171+
}
172+
{{- end }}
84173

85174
{{ define "ogenreflect/contents" -}}
86175
ogenreflect.Contents{

gen/template_config.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package gen
2+
3+
import (
4+
"regexp"
5+
6+
"github.com/ogen-go/ogen/gen/ir"
7+
"github.com/ogen-go/ogen/internal/xmaps"
8+
"github.com/ogen-go/ogen/ogenregex"
9+
)
10+
11+
type TemplateConfig struct {
12+
Package string
13+
Operations []*ir.Operation
14+
Webhooks []*ir.Operation
15+
Types map[string]*ir.Type
16+
Interfaces map[string]*ir.Type
17+
Error *ir.Response
18+
ErrorType *ir.Type
19+
Servers ir.Servers
20+
Securities map[string]*ir.Security
21+
Router Router
22+
WebhookRouter WebhookRouter
23+
ClientEnabled bool
24+
ServerEnabled bool
25+
26+
skipTestRegex *regexp.Regexp
27+
}
28+
29+
// ErrorGoType returns Go type of error.
30+
func (t TemplateConfig) ErrorGoType() string {
31+
typ := t.ErrorType
32+
if typ.DoPassByPointer() {
33+
return "*" + typ.Go()
34+
}
35+
return typ.Go()
36+
}
37+
38+
// SkipTest returns true, if test should be skipped.
39+
func (t TemplateConfig) SkipTest(typ *ir.Type) bool {
40+
return t.skipTestRegex != nil && t.skipTestRegex.MatchString(typ.Name)
41+
}
42+
43+
func (t TemplateConfig) collectStrings(cb func(typ *ir.Type) []string) []string {
44+
var (
45+
add func(typ *ir.Type)
46+
m = map[string]struct{}{}
47+
seen = map[*ir.Type]struct{}{}
48+
)
49+
add = func(typ *ir.Type) {
50+
_, skip := seen[typ]
51+
if typ == nil || skip {
52+
return
53+
}
54+
seen[typ] = struct{}{}
55+
for _, got := range cb(typ) {
56+
m[got] = struct{}{}
57+
}
58+
59+
for _, f := range typ.Fields {
60+
add(f.Type)
61+
}
62+
for _, f := range typ.SumOf {
63+
add(f)
64+
}
65+
add(typ.AliasTo)
66+
add(typ.PointerTo)
67+
add(typ.GenericOf)
68+
add(typ.Item)
69+
}
70+
71+
for _, typ := range t.Types {
72+
add(typ)
73+
}
74+
for _, typ := range t.Interfaces {
75+
add(typ)
76+
}
77+
if t.Error != nil {
78+
add(t.Error.NoContent)
79+
for _, media := range t.Error.Contents {
80+
add(media.Type)
81+
}
82+
}
83+
add(t.ErrorType)
84+
85+
_ = walkOpTypes(t.Operations, func(t *ir.Type) error {
86+
add(t)
87+
return nil
88+
})
89+
_ = walkOpTypes(t.Webhooks, func(t *ir.Type) error {
90+
add(t)
91+
return nil
92+
})
93+
94+
return xmaps.SortedKeys(m)
95+
}
96+
97+
// RegexStrings returns slice of all unique regex validators.
98+
func (t TemplateConfig) RegexStrings() []string {
99+
return t.collectStrings(func(typ *ir.Type) (r []string) {
100+
for _, exp := range []ogenregex.Regexp{
101+
typ.Validators.String.Regex,
102+
typ.MapPattern,
103+
} {
104+
if exp == nil {
105+
continue
106+
}
107+
r = append(r, exp.String())
108+
}
109+
return r
110+
})
111+
}
112+
113+
// RatStrings returns slice of all unique big.Rat (multipleOf validation).
114+
func (t TemplateConfig) RatStrings() []string {
115+
return t.collectStrings(func(typ *ir.Type) []string {
116+
if r := typ.Validators.Float.MultipleOf; r != nil {
117+
// `RatString` return a string with integer value if denominator is 1.
118+
//
119+
// That makes string representation of `big.Rat` shorter and simpler.
120+
// Also, it is better for executable size.
121+
return []string{r.RatString()}
122+
}
123+
return nil
124+
})
125+
}

0 commit comments

Comments
 (0)