Skip to content

Commit c1f6ad6

Browse files
committed
Generating SQS controller with V2 works!!
1 parent a80dcbe commit c1f6ad6

29 files changed

+734
-912
lines changed

apiv2/converter.go

+284
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
package apiv2
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"os"
8+
"strings"
9+
10+
"github.com/aws-controllers-k8s/code-generator/pkg/api"
11+
)
12+
13+
type API struct {
14+
Shapes map[string]Shape
15+
}
16+
17+
type Shape struct {
18+
Type string
19+
Traits map[string]interface{}
20+
MemberRefs map[string]*ShapeRef `json:"members"`
21+
MemberRef *ShapeRef `json:"member"`
22+
KeyRef ShapeRef `json:"key"`
23+
ValueRef ShapeRef `json:"value"`
24+
InputRef ShapeRef `json:"input"`
25+
OutputRef ShapeRef `json:"output"`
26+
ErrorRefs []ShapeRef `json:"errors"`
27+
}
28+
29+
type ShapeRef struct {
30+
API *API `json:"-"`
31+
Shape *Shape `json:"-"`
32+
ShapeName string `json:"target"`
33+
Traits map[string]interface{}
34+
}
35+
36+
func ConvertApiV2Shapes(modelPath string) (map[string]*api.API, error) {
37+
38+
// Read the json file
39+
file, err := os.ReadFile(modelPath)
40+
if err != nil {
41+
return nil, fmt.Errorf("error reading file: %v", err)
42+
}
43+
44+
// unmarshal the file
45+
var customAPI API
46+
err = json.Unmarshal(file, &customAPI)
47+
if err != nil {
48+
return nil, fmt.Errorf("error unmarshalling file: %v", err)
49+
}
50+
51+
serviceAlias := extractServiceAlias(modelPath)
52+
53+
newApi, err := BuildAPI(customAPI.Shapes, serviceAlias)
54+
if err != nil {
55+
return nil, fmt.Errorf("error building api: %v", err)
56+
}
57+
58+
newApi.StrictServiceId = true
59+
60+
err = newApi.Setup()
61+
if err != nil {
62+
return nil, fmt.Errorf("error setting up api: %v", err)
63+
}
64+
65+
return map[string]*api.API{
66+
serviceAlias: newApi,
67+
}, nil
68+
}
69+
70+
// This function tries to translate the API from sdk go v2
71+
// into the struct for sdk go v1
72+
func BuildAPI(shapes map[string]Shape, serviceAlias string) (*api.API, error) {
73+
74+
newApi := api.API{
75+
Metadata: api.Metadata{},
76+
Operations: map[string]*api.Operation{},
77+
Shapes: map[string]*api.Shape{},
78+
}
79+
80+
for shapeName, shape := range shapes {
81+
82+
name := removeNamePrefix(shapeName, serviceAlias)
83+
if shape.Type != "service" && shape.Type != "operation" {
84+
newShape, err := createApiShape(shape)
85+
if err != nil {
86+
return nil, err
87+
}
88+
newApi.Shapes[name] = newShape
89+
}
90+
91+
switch shape.Type {
92+
case "service":
93+
serviceId, ok := shape.Traits["aws.api#service"].(map[string]interface{})["sdkId"]
94+
if !ok {
95+
return nil, errors.New("service id not found")
96+
}
97+
newApi.Metadata.ServiceID = serviceId.(string)
98+
doc, ok := shape.Traits["smithy.api#documentation"]
99+
if !ok {
100+
return nil, errors.New("service documentation not found")
101+
}
102+
newApi.Documentation = api.AppendDocstring("", doc.(string))
103+
case "operation":
104+
newApi.Operations[name] = createApiOperation(shape, name, serviceAlias)
105+
case "structure":
106+
AddMemberRefs(newApi.Shapes[name], shape, serviceAlias)
107+
case "list":
108+
AddMemberRef(newApi.Shapes[name], name, shape, serviceAlias)
109+
case "map":
110+
AddKeyAndValueRef(newApi.Shapes[name], name, shape, serviceAlias)
111+
case "enum":
112+
AddEnumRef(newApi.Shapes[name], shape)
113+
}
114+
115+
}
116+
117+
return &newApi, nil
118+
}
119+
120+
func createApiOperation(shape Shape, name, serviceAlias string) *api.Operation {
121+
122+
newOperation := &api.Operation{
123+
Name: name,
124+
Documentation: api.AppendDocstring("", shape.Traits["smithy.api#documentation"].(string)),
125+
}
126+
127+
if hasPrefix(shape.InputRef.ShapeName, serviceAlias) {
128+
inputName := removeNamePrefix(shape.InputRef.ShapeName, serviceAlias)
129+
newOperation.InputRef = api.ShapeRef{
130+
ShapeName: inputName,
131+
}
132+
}
133+
if hasPrefix(shape.OutputRef.ShapeName, serviceAlias) {
134+
outputName := removeNamePrefix(shape.OutputRef.ShapeName, serviceAlias)
135+
newOperation.OutputRef = api.ShapeRef{
136+
ShapeName: outputName,
137+
}
138+
}
139+
140+
for _, err := range shape.ErrorRefs {
141+
newOperation.ErrorRefs = append(newOperation.ErrorRefs, api.ShapeRef{
142+
ShapeName: removeNamePrefix(err.ShapeName, serviceAlias),
143+
})
144+
}
145+
146+
return newOperation
147+
}
148+
149+
func createApiShape(shape Shape) (*api.Shape, error) {
150+
151+
isException := shape.IsException()
152+
153+
shapeType := shape.Type
154+
if shapeType == "enum" {
155+
shapeType = "string"
156+
}
157+
158+
apiShape := &api.Shape{
159+
Type: shapeType,
160+
Exception: isException,
161+
MemberRefs: make(map[string]*api.ShapeRef),
162+
MemberRef: api.ShapeRef{},
163+
KeyRef: api.ShapeRef{},
164+
ValueRef: api.ShapeRef{},
165+
Required: []string{},
166+
}
167+
val, ok := shape.Traits["smithy.api#default"]
168+
if ok {
169+
apiShape.DefaultValue = &val
170+
}
171+
172+
if isException {
173+
code, ok := shape.Traits["smithy.api#httpError"]
174+
if ok {
175+
switch code := code.(type) {
176+
case float64:
177+
apiShape.ErrorInfo = api.ErrorInfo{
178+
HTTPStatusCode: int(code),
179+
}
180+
case int:
181+
apiShape.ErrorInfo = api.ErrorInfo{
182+
HTTPStatusCode: code,
183+
}
184+
case int64:
185+
apiShape.ErrorInfo = api.ErrorInfo{
186+
HTTPStatusCode: int(code),
187+
}
188+
default:
189+
return nil, fmt.Errorf("status code type not found for exception")
190+
}
191+
}
192+
}
193+
194+
return apiShape, nil
195+
}
196+
197+
func AddMemberRefs(apiShape *api.Shape, shape Shape, serviceAlias string) {
198+
199+
var documentation string
200+
for memberName, member := range shape.MemberRefs {
201+
if !hasPrefix(member.ShapeName, serviceAlias) {
202+
continue
203+
}
204+
shapeNameClean := removeNamePrefix(member.ShapeName, serviceAlias)
205+
if member.Traits["smithy.api#documentation"] != nil {
206+
documentation = api.AppendDocstring("", member.Traits["smithy.api#documentation"].(string))
207+
}
208+
if member.IsRequired() {
209+
apiShape.Required = append(apiShape.Required, memberName)
210+
}
211+
apiShape.MemberRefs[memberName] = &api.ShapeRef{
212+
ShapeName: shapeNameClean,
213+
Documentation: documentation,
214+
}
215+
}
216+
217+
if shape.Traits["smithy.api#documentation"] != nil {
218+
documentation = api.AppendDocstring("", shape.Traits["smithy.api#documentation"].(string))
219+
}
220+
// Add the documentation to the shape
221+
apiShape.Documentation = documentation
222+
}
223+
224+
func AddMemberRef(apiShape *api.Shape, shapeName string, shape Shape, serviceAlias string) {
225+
226+
apiShape.MemberRef = api.ShapeRef{
227+
ShapeName: removeNamePrefix(shape.MemberRef.ShapeName, serviceAlias),
228+
}
229+
}
230+
231+
func AddKeyAndValueRef(apiShape *api.Shape, shapeName string, shape Shape, serviceAlias string) {
232+
233+
apiShape.KeyRef = api.ShapeRef{
234+
ShapeName: removeNamePrefix(shape.KeyRef.ShapeName, serviceAlias),
235+
}
236+
apiShape.ValueRef = api.ShapeRef{
237+
ShapeName: removeNamePrefix(shape.ValueRef.ShapeName, serviceAlias),
238+
}
239+
}
240+
241+
func AddEnumRef(apiShape *api.Shape, shape Shape) {
242+
for memberName := range shape.MemberRefs {
243+
apiShape.Enum = append(apiShape.Enum, memberName)
244+
}
245+
}
246+
247+
func (s ShapeRef) IsRequired() bool {
248+
_, ok := s.Traits["smithy.api#required"]
249+
return ok
250+
}
251+
252+
func (s Shape) IsException() bool {
253+
_, ok := s.Traits["smithy.api#error"]
254+
return ok
255+
}
256+
257+
func hasPrefix(name, alias string) bool {
258+
259+
prefix := fmt.Sprintf("com.amazonaws.%s#", alias)
260+
261+
return strings.HasPrefix(name, prefix)
262+
}
263+
264+
func removeNamePrefix(name, alias string) string {
265+
266+
toTrim := fmt.Sprintf("com.amazonaws.%s#", alias)
267+
268+
newName := strings.TrimPrefix(name, toTrim)
269+
270+
return newName
271+
}
272+
273+
func extractServiceAlias(modelPath string) string {
274+
// Split the path into parts
275+
parts := strings.Split(modelPath, "/")
276+
277+
// Get the last part
278+
lastPart := parts[len(parts)-1]
279+
280+
// Split the last part by "." to get the service alias
281+
serviceAlias := strings.Split(lastPart, ".")[0]
282+
283+
return serviceAlias
284+
}

0 commit comments

Comments
 (0)