diff --git a/go.mod b/go.mod index 1eccff2..390a162 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,8 @@ require ( github.com/buger/jsonparser v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect + github.com/fatih/camelcase v1.0.0 // indirect + github.com/fatih/structtag v1.2.0 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect github.com/go-openapi/swag v0.22.8 // indirect github.com/invopop/yaml v0.2.0 // indirect @@ -25,6 +27,7 @@ require ( github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/twpayne/go-jsonstruct/v3 v3.0.0 // indirect github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect golang.org/x/exp v0.0.0-20240213143201-ec583247a57a // indirect diff --git a/go.sum b/go.sum index c784953..3a1c798 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w= github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q= +github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= +github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -94,6 +98,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/twpayne/go-jsonstruct/v3 v3.0.0 h1:qdhM8Wiq7BPwjrNRK3n1KtLt4IReiXYWUEZEfjixL0s= +github.com/twpayne/go-jsonstruct/v3 v3.0.0/go.mod h1:p+c9NMNNnoc1z+FvWFUQklf0pzFaIlf03CfrLL7Lo2k= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= diff --git a/internal/proxy/generate.go b/internal/proxy/generate.go index e110fca..f0b984a 100644 --- a/internal/proxy/generate.go +++ b/internal/proxy/generate.go @@ -1,8 +1,10 @@ package proxy import ( + "bytes" "context" "embed" + "encoding/json" "fmt" "io/fs" "path" @@ -14,6 +16,7 @@ import ( v3 "github.com/pb33f/libopenapi/datamodel/high/v3" "github.com/pb33f/libopenapi/orderedmap" "github.com/telkomindonesia/oapik/internal/util" + "github.com/twpayne/go-jsonstruct/v3" "golang.org/x/tools/imports" ) @@ -46,6 +49,40 @@ func addTemplateFunc(pe ProxyExtension) { } return } + codegen.TemplateFunctions["writeExtensionType"] = func(ops []codegen.OperationDefinition, name string) (string, error) { + jsGenerator := jsonstruct.NewGenerator( + jsonstruct.WithPackageName("nopackage"), + jsonstruct.WithTypeName(name), + ) + for _, op := range ops { + m := map[string]interface{}{} + for k, v := range op.Spec.Extensions { + m[strings.TrimPrefix(k, "x-")] = v + } + jsGenerator.ObserveValue(m) + } + b, err := jsGenerator.Generate() + if err != nil { + return "", fmt.Errorf("fail to generate type definition %w", err) + } + b = bytes.Replace(b, []byte("package nopackage\n"), []byte{}, 1) + return string(b), err + } + + codegen.TemplateFunctions["writeExtensionData"] = func(op codegen.OperationDefinition) (string, error) { + m := map[string]interface{}{} + for k, v := range op.Spec.Extensions { + m[strings.TrimPrefix(k, "x-")] = v + } + + b, err := json.Marshal(m) + if err != nil { + return "", fmt.Errorf("fail to marshall to json: %w", err) + } + b, err = json.Marshal(string(b)) + + return string(b), err + } } type GenerateOptions struct { diff --git a/internal/proxy/templates/proxy/strict/strict-interface.tmpl b/internal/proxy/templates/proxy/strict/strict-interface.tmpl index 29b6800..41d0d90 100644 --- a/internal/proxy/templates/proxy/strict/strict-interface.tmpl +++ b/internal/proxy/templates/proxy/strict/strict-interface.tmpl @@ -57,4 +57,22 @@ func (s StrictOperationsMap[T]) ToMap() (m map[string]T) { "{{.OperationId}}": s.{{.OperationId | ucFirst}}, {{- end}} } -} \ No newline at end of file +} + +{{ writeExtensionType . "StrictExtensionsStruct" }} + +type StrictOperationsDataStruct struct { + Extension StrictExtensionsStruct +} +var StrictOperationsData = func() (m StrictOperationsMap[StrictOperationsDataStruct]) { +{{- range .}} + { + b := []byte({{ writeExtensionData . }}) + if err := json.Unmarshal(b, &m.{{.OperationId}}.Extension); err != nil { + panic(err) + } + } +{{- end}} + + return +}() \ No newline at end of file diff --git a/internal/proxy/testoutput/oapi-proxy.go b/internal/proxy/testoutput/oapi-proxy.go index 6890e32..f642dec 100644 --- a/internal/proxy/testoutput/oapi-proxy.go +++ b/internal/proxy/testoutput/oapi-proxy.go @@ -5,6 +5,7 @@ package testoutput import ( "context" + "encoding/json" "fmt" "net/http" "net/url" @@ -338,6 +339,53 @@ func (s StrictOperationsMap[T]) ToMap() (m map[string]T) { } } +type StrictExtensionsStruct struct { + Proxy struct { + Inject *struct { + Parameters []struct { + In string `json:"in"` + Name string `json:"name"` + } `json:"parameters"` + } `json:"inject,omitempty"` + Method string `json:"method,omitempty"` + Name string `json:"name"` + Path string `json:"path,omitempty"` + } `json:"proxy"` +} + +type StrictOperationsDataStruct struct { + Extension StrictExtensionsStruct +} + +var StrictOperationsData = func() (m StrictOperationsMap[StrictOperationsDataStruct]) { + { + b := []byte("{\"proxy\":{\"inject\":{\"parameters\":[{\"in\":\"path\",\"name\":\"tenant-id\"}]},\"method\":\"get\",\"name\":\"profile\",\"path\":\"/tenants/{tenant-id}/profiles/{profile-id}\"}}") + if err := json.Unmarshal(b, &m.GetProfile.Extension); err != nil { + panic(err) + } + } + { + b := []byte("{\"proxy\":{\"inject\":{\"parameters\":[{\"in\":\"path\",\"name\":\"tenant-id\"}]},\"method\":\"put\",\"name\":\"profile\",\"path\":\"/tenants/{tenant-id}/profiles/{profile-id}\"}}") + if err := json.Unmarshal(b, &m.PutProfile.Extension); err != nil { + panic(err) + } + } + { + b := []byte("{\"proxy\":{\"name\":\"profile\"}}") + if err := json.Unmarshal(b, &m.ProfileGetProfile.Extension); err != nil { + panic(err) + } + } + { + b := []byte("{\"proxy\":{\"inject\":{\"parameters\":[{\"in\":\"path\",\"name\":\"tenant-id\"}]},\"method\":\"get\",\"name\":\"profile\",\"path\":\"/tenants/{tenant-id}/profiles/{profile-id}\"}}") + if err := json.Unmarshal(b, &m.GetValidatedProfile.Extension); err != nil { + panic(err) + } + } + + return +}() + type StrictHandlerFunc = strictecho.StrictEchoHandlerFunc type StrictMiddlewareFunc = strictecho.StrictEchoMiddlewareFunc diff --git a/internal/proxy/testoutput/oapi-proxy_test.go b/internal/proxy/testoutput/oapi-proxy_test.go index 304b53c..16420bc 100644 --- a/internal/proxy/testoutput/oapi-proxy_test.go +++ b/internal/proxy/testoutput/oapi-proxy_test.go @@ -179,4 +179,7 @@ func TestProxy(t *testing.T) { } }) + t.Run("OperationData", func(t *testing.T) { + assert.Equal(t, "profile", testoutput.StrictOperationsData.GetProfile.Extension.Proxy.Name) + }) }