Skip to content
This repository has been archived by the owner on May 6, 2022. It is now read-only.

Commit

Permalink
generate proxy from oas 3
Browse files Browse the repository at this point in the history
  • Loading branch information
srinandan committed Apr 12, 2020
1 parent 5854b41 commit 9fc2aea
Show file tree
Hide file tree
Showing 10 changed files with 664 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ builds:
- darwin
- windows
ldflags:
- -s -w -a -extldflags "-static" -X main.Version={{.Tag}} -X main.Git={{.Commit}}
- -s -w -a -extldflags "-static" -X main.Version={{.Tag}} -X main.Git={{.Commit}} -trimpath
archives:
- id: apigeecli
format: zip
Expand Down
110 changes: 110 additions & 0 deletions cmd/apis/apiproxydef/apiproxydef.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package apiproxydef

import (
"encoding/xml"
"strconv"
"time"
)

type policiesType struct {
XMLName xml.Name `xml:"Policies"`
Policy []string `xml:"Policy,omitempty"`
}

type proxyEndpointsType struct {
XMLName xml.Name `xml:"ProxyEndpoints"`
ProxyEndpoint []string `xml:"ProxyEndpoint,omitempty"`
}

type targetEndpointsType struct {
XMLName xml.Name `xml:"TargetEndpoints"`
TargetEndpoint []string `xml:"TargetEndpoint,omitempty"`
}

type configurationVersionType struct {
XMLName xml.Name `xml:"ConfigurationVersion,omitempty"`
MajorVersion string `xml:"majorVersion,attr"`
MinorVersion string `xml:"minorVersion,attr"`
}

type apiProxyType struct {
XMLName xml.Name `xml:"APIProxy"`
Name string `xml:"name,attr"`
Revision string `xml:"revision,attr"`
BasePaths string `xml:"Basepaths,omitempty"`
ConfigurationVersion configurationVersionType `xml:"ConfigurationVersion,omitempty"`
CreatedAt string `xml:"CreatedAt,omitempty"`
Description string `xml:"Description,omitempty"`
DisplayName string `xml:"DisplayName,omitempty"`
LastModifiedAt string `xml:"LastModifiedAt,omitempty"`
Policies policiesType `xml:"Policies,omitempty"`
ProxyEndpoints proxyEndpointsType `xml:"ProxyEndpoints,omitempty"`
Resources string `xml:"Resources,omitempty"`
Spec string `xml:"Spec,omitempty"`
TargetServers string `xml:"TargetServers,omitempty"`
TargetEndpoints targetEndpointsType `xml:"TargetEndpoints,omitempty"`
Validate string `xml:"validate,omitempty"`
}

var apiProxy apiProxyType

func SetDisplayName(name string) {
apiProxy.DisplayName = name
apiProxy.Name = name
}

func AddProxyEndpoint(name string) {
apiProxy.ProxyEndpoints.ProxyEndpoint = append(apiProxy.ProxyEndpoints.ProxyEndpoint, name)
}

func AddTargetEndpoint(name string) {
apiProxy.TargetEndpoints.TargetEndpoint = append(apiProxy.TargetEndpoints.TargetEndpoint, name)
}

func SetCreatedAt() {
apiProxy.CreatedAt = strconv.FormatInt((time.Now().UTC().UnixNano())/1000000, 10)
}

func SetLastModifiedAt() {
apiProxy.LastModifiedAt = strconv.FormatInt((time.Now().UTC().UnixNano())/1000000, 10)
}

func AddPolicy(name string) {
apiProxy.Policies.Policy = append(apiProxy.Policies.Policy, name)
}

func SetBasePath(basePath string) {
apiProxy.BasePaths = basePath
}

func SetRevision(revision string) {
apiProxy.Revision = revision
}

func SetDescription(description string) {
apiProxy.Description = description
}

func GetAPIProxy() string {
proxyBody, _ := xml.MarshalIndent(apiProxy, "", " ")
return string(proxyBody)
}

func SetConfigurationVersion() {
apiProxy.ConfigurationVersion.MajorVersion = "4"
apiProxy.ConfigurationVersion.MinorVersion = "0"
}
30 changes: 28 additions & 2 deletions cmd/apis/crtapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/spf13/cobra"
"github.com/srinandan/apigeecli/apiclient"
"github.com/srinandan/apigeecli/client/apis"
proxybundle "github.com/srinandan/apigeecli/cmd/apis/proxybundle"
)

//CreateCmd to create api
Expand All @@ -30,19 +31,44 @@ var CreateCmd = &cobra.Command{
return nil
},
RunE: func(cmd *cobra.Command, args []string) (err error) {
_, err = apis.CreateProxy(name, proxy)
if proxy != "" {
_, err = apis.CreateProxy(name, proxy)
} else if oasDoc != "" {
err = GenerateAPIProxyDefFromOAS(name, oasDoc)
if err != nil {
return err
}

err = proxybundle.GenerateAPIProxyBundle(name)
if err != nil {
return err
}

if importProxy {
_, err = apis.CreateProxy(name, name+".zip")
}

} else {
_, err = apis.CreateProxy(name, "")
}

return
},
}

var proxy string
var proxy, oasDoc string
var importProxy bool

func init() {

CreateCmd.Flags().StringVarP(&name, "name", "n",
"", "API Proxy name")
CreateCmd.Flags().StringVarP(&proxy, "proxy", "p",
"", "API Proxy Bundle path")
CreateCmd.Flags().StringVarP(&oasDoc, "oas", "f",
"", "Open API 3.0 Specification file")
CreateCmd.Flags().BoolVarP(&importProxy, "import", "",
true, "Import API Proxy after generation from spec")

_ = CreateCmd.MarkFlagRequired("name")
}
165 changes: 165 additions & 0 deletions cmd/apis/generateapi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package apis

import (
"fmt"
"net/url"
"regexp"
"strings"

"github.com/getkin/kin-openapi/openapi3"
apiproxy "github.com/srinandan/apigeecli/cmd/apis/apiproxydef"
proxies "github.com/srinandan/apigeecli/cmd/apis/proxies"
target "github.com/srinandan/apigeecli/cmd/apis/targetendpoint"
)

func LoadDocument(filePath string) (doc *openapi3.Swagger, err error) {
doc, err = openapi3.NewSwaggerLoader().LoadSwaggerFromFile(filePath)
return doc, err
}

func GenerateAPIProxyDefFromOAS(name string, filePath string) (err error) {
doc, err := LoadDocument(filePath)
if err != nil {
return err
}

apiproxy.SetDisplayName(name)
if doc.Info != nil {
if doc.Info.Description != "" {
apiproxy.SetDescription(doc.Info.Description)
}
}

apiproxy.SetCreatedAt()
apiproxy.SetLastModifiedAt()
apiproxy.SetConfigurationVersion()
apiproxy.AddTargetEndpoint("default")
apiproxy.AddProxyEndpoint("default")

u, err := GetEndpoint(doc)
if err != nil {
return err
}

apiproxy.SetBasePath(u.Path)

target.NewTargetEndpoint(u.Scheme + "://" + u.Hostname())

proxies.NewProxyEndpoint(u.Path)

GenerateFlows(doc.Paths)

return nil
}

func GetEndpoint(doc *openapi3.Swagger) (u *url.URL, err error) {
if doc.Servers == nil {
return nil, fmt.Errorf("at least one server must be present")
}

return url.Parse(doc.Servers[0].URL)
}

func GetHTTPMethod(pathItem *openapi3.PathItem, keyPath string) map[string]string {

pathMap := make(map[string]string)
alternateOperationId := strings.ReplaceAll(keyPath, "\\", "_")

if pathItem.Get != nil {
if pathItem.Get.OperationID != "" {
pathMap["get"] = pathItem.Get.OperationID
} else {
pathMap["get"] = "get_" + alternateOperationId
}
}

if pathItem.Post != nil {
if pathItem.Post.OperationID != "" {
pathMap["post"] = pathItem.Post.OperationID
} else {
pathMap["post"] = "post_" + alternateOperationId
}
}

if pathItem.Put != nil {
if pathItem.Put.OperationID != "" {
pathMap["put"] = pathItem.Put.OperationID
} else {
pathMap["put"] = "put_" + alternateOperationId
}
}

if pathItem.Patch != nil {
if pathItem.Patch.OperationID != "" {
pathMap["patch"] = pathItem.Patch.OperationID
} else {
pathMap["patch"] = "patch_" + alternateOperationId
}
}

if pathItem.Delete != nil {
if pathItem.Delete.OperationID != "" {
pathMap["delete"] = pathItem.Delete.OperationID
} else {
pathMap["delete"] = "delete_" + alternateOperationId
}
}

if pathItem.Options != nil {
if pathItem.Options.OperationID != "" {
pathMap["options"] = pathItem.Options.OperationID
} else {
pathMap["options"] = "options_" + alternateOperationId
}
}

if pathItem.Trace != nil {
if pathItem.Trace.OperationID != "" {
pathMap["trace"] = pathItem.Trace.OperationID
} else {
pathMap["trace"] = "trace_" + alternateOperationId
}
}

if pathItem.Head != nil {
if pathItem.Head.OperationID != "" {
pathMap["head"] = pathItem.Head.OperationID
} else {
pathMap["head"] = "head_" + alternateOperationId
}
}

return pathMap
}

func GenerateFlows(paths openapi3.Paths) {
for keyPath := range paths {
pathMap := GetHTTPMethod(paths[keyPath], keyPath)
for method, operationId := range pathMap {
proxies.AddFlow(operationId, replacePathWithWildCard(keyPath), method)
}
}
}

func replacePathWithWildCard(keyPath string) string {
re := regexp.MustCompile(`{(.*?)}`)
if strings.ContainsAny(keyPath, "{") {
return re.ReplaceAllLiteralString(keyPath, "*")
} else {
return keyPath
}
}
Loading

0 comments on commit 9fc2aea

Please sign in to comment.