added vendors

This commit is contained in:
mickymiek
2018-12-19 15:29:25 +01:00
committed by Huamin Chen
parent 62d65ad0cb
commit 35561301b2
2952 changed files with 1124359 additions and 1 deletions

View File

@ -0,0 +1,38 @@
# disco
This directory contains a tool for working with Google's Discovery API and Discovery Format,
including the ability to convert Discovery Format descriptions to OpenAPI.
Installation:
go get github.com/googleapis/gnostic
go install github.com/googleapis/gnostic/apps/disco
Usage:
disco help
Prints a list of commands and options.
disco list [--raw]
Calls the Google Discovery API and lists available APIs.
The `--raw` option prints the raw results of the Discovery List APIs call.
disco get [<api>] [<version>] [--raw] [--openapi2] [--openapi3] [--features] [--schemas] [--all]
Gets the specified API and version from the Google Discovery API.
`<version>` can be omitted if it is unique.
The `--raw` option saves the raw Discovery Format description.
The `--openapi2` option rewrites the API description in OpenAPI v2.
The `--openapi3` option rewrites the API description in OpenAPI v3.
The `--features` option displays the contents of the `features` sections of discovery documents.
The `--schemas` option displays information about the schemas defined for the API.
The `--all` option runs the other associated operations for all of the APIs available from the Discovery Service.
When `--all` is specified, `<api>` and `<version>` should be omitted.
disco <file> [--openapi2] [--openapi3] [--features] [--schemas]
Applies the specified operations to a local file. See the `get` command for details.

View File

@ -0,0 +1,79 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// 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 main
import (
"encoding/json"
"errors"
"strings"
)
// APIsListServiceURL is the URL for the Google APIs Discovery Service
const APIsListServiceURL = "https://www.googleapis.com/discovery/v1/apis"
// A List represents the results of a call to the apis/list API.
// https://developers.google.com/discovery/v1/reference/apis/list
type List struct {
Kind string `json:"kind"`
DiscoveryVersion string `json:"discoveryVersion"`
APIs []*API `json:"items"`
}
// NewList unmarshals the bytes into a Document.
func NewList(bytes []byte) (*List, error) {
var listResponse List
err := json.Unmarshal(bytes, &listResponse)
return &listResponse, err
}
// An API represents the an API description returned by the apis/list API.
type API struct {
Kind string `json:"kind"`
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
Title string `json:"title"`
Description string `json:"description"`
DiscoveryRestURL string `json:"discoveryRestUrl"`
DiscoveryLink string `json:"discoveryLink"`
Icons map[string]string `json:"icons"`
DocumentationLink string `json:"documentationLink"`
Labels []string `json:"labels"`
Preferred bool `json:"preferred"`
}
// APIWithNameAndVersion returns the API with a specified name and version.
// If version is the empty string, the API name must be unique.
func (a *List) APIWithNameAndVersion(name string, version string) (*API, error) {
var api *API // the API to return
versions := make([]string, 0) // the matching version names
// Scan the list for matching APIs and versions.
for _, item := range a.APIs {
if item.Name == name {
if version == "" || version == item.Version {
api = item
versions = append(versions, item.Version)
}
}
}
switch {
case len(versions) == 0:
return nil, errors.New(name + " was not found.")
case len(versions) > 1:
return nil, errors.New(name + " has multiple versions: " + strings.Join(versions, ", "))
default:
return api, nil
}
}

255
vendor/github.com/googleapis/gnostic/apps/disco/main.go generated vendored Normal file
View File

@ -0,0 +1,255 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// 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 main
import (
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
"github.com/docopt/docopt-go"
"github.com/golang/protobuf/proto"
"github.com/googleapis/gnostic/compiler"
discovery "github.com/googleapis/gnostic/discovery"
)
func main() {
usage := `
Usage:
disco help
disco list [--raw]
disco get [<api>] [<version>] [--raw] [--openapi2] [--openapi3] [--features] [--schemas] [--all]
disco <file> [--openapi2] [--openapi3] [--features] [--schemas]
`
arguments, err := docopt.Parse(usage, nil, false, "Disco 1.0", false)
if err != nil {
log.Fatalf("%+v", err)
}
// Help.
if arguments["help"].(bool) {
fmt.Println("\nRead and process Google's Discovery Format for APIs.")
fmt.Println(usage)
fmt.Println("To learn more about Discovery Format, visit https://developers.google.com/discovery/\n")
}
// List APIs.
if arguments["list"].(bool) {
// Read the list of APIs from the apis/list service.
bytes, err := compiler.FetchFile(APIsListServiceURL)
if err != nil {
log.Fatalf("%+v", err)
}
if arguments["--raw"].(bool) {
ioutil.WriteFile("disco-list.json", bytes, 0644)
} else {
// Unpack the apis/list response.
listResponse, err := NewList(bytes)
if err != nil {
log.Fatalf("%+v", err)
}
// List the APIs.
for _, api := range listResponse.APIs {
fmt.Printf("%s %s\n", api.Name, api.Version)
}
}
}
// Get an API description.
if arguments["get"].(bool) {
// Read the list of APIs from the apis/list service.
bytes, err := compiler.FetchFile(APIsListServiceURL)
if err != nil {
log.Fatalf("%+v", err)
}
// Unpack the apis/list response
listResponse, err := NewList(bytes)
if arguments["--all"].(bool) {
if !arguments["--raw"].(bool) &&
!arguments["--openapi2"].(bool) &&
!arguments["--openapi3"].(bool) &&
!arguments["--features"].(bool) &&
!arguments["--schemas"].(bool) {
log.Fatalf("Please specify an output option.")
}
for _, api := range listResponse.APIs {
log.Printf("%s/%s", api.Name, api.Version)
// Fetch the discovery description of the API.
bytes, err = compiler.FetchFile(api.DiscoveryRestURL)
if err != nil {
log.Printf("%+v", err)
continue
}
// Export any requested formats.
_, err := handleExportArgumentsForBytes(arguments, bytes)
if err != nil {
log.Printf("%+v", err)
continue
}
}
} else {
// Find the matching API
var apiName string
if arguments["<api>"] != nil {
apiName = arguments["<api>"].(string)
}
var apiVersion string
if arguments["<version>"] != nil {
apiVersion = arguments["<version>"].(string)
}
// Get the description of an API.
api, err := listResponse.APIWithNameAndVersion(apiName, apiVersion)
if err != nil {
log.Fatalf("%+v", err)
}
// Fetch the discovery description of the API.
bytes, err = compiler.FetchFile(api.DiscoveryRestURL)
if err != nil {
log.Fatalf("%+v", err)
}
// Export any requested formats.
handled, err := handleExportArgumentsForBytes(arguments, bytes)
if err != nil {
log.Fatalf("%+v", err)
} else if !handled {
// If no action was requested, write the document to stdout.
os.Stdout.Write(bytes)
}
}
}
// Do something with a local API description.
if arguments["<file>"] != nil {
// Read the local file.
filename := arguments["<file>"].(string)
bytes, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatalf("%+v", err)
}
// Export any requested formats.
_, err = handleExportArgumentsForBytes(arguments, bytes)
if err != nil {
log.Fatalf("%+v", err)
}
}
}
func handleExportArgumentsForBytes(arguments map[string]interface{}, bytes []byte) (handled bool, err error) {
// Unpack the discovery document.
info, err := compiler.ReadInfoFromBytes("", bytes)
if err != nil {
return true, err
}
m, ok := compiler.UnpackMap(info)
if !ok {
log.Printf("%s", string(bytes))
return true, errors.New("Invalid input")
}
document, err := discovery.NewDocument(m, compiler.NewContext("$root", nil))
if arguments["--raw"].(bool) {
// Write the Discovery document as a JSON file.
filename := "disco-" + document.Name + "-" + document.Version + ".json"
ioutil.WriteFile(filename, bytes, 0644)
handled = true
}
if arguments["--features"].(bool) {
if len(document.Features) > 0 {
log.Printf("%s/%s features: %s\n",
document.Name,
document.Version,
strings.Join(document.Features, ","))
}
}
if arguments["--schemas"].(bool) {
for _, schema := range document.Schemas.AdditionalProperties {
checkSchema(schema.Name, schema.Value, 0)
}
}
if arguments["--openapi3"].(bool) {
// Generate the OpenAPI 3 equivalent.
openAPIDocument, err := OpenAPIv3(document)
if err != nil {
return handled, err
}
bytes, err = proto.Marshal(openAPIDocument)
if err != nil {
return handled, err
}
filename := "openapi3-" + document.Name + "-" + document.Version + ".pb"
err = ioutil.WriteFile(filename, bytes, 0644)
if err != nil {
return handled, err
}
handled = true
}
if arguments["--openapi2"].(bool) {
// Generate the OpenAPI 2 equivalent.
openAPIDocument, err := OpenAPIv2(document)
if err != nil {
return handled, err
}
bytes, err = proto.Marshal(openAPIDocument)
if err != nil {
return handled, err
}
filename := "openapi2-" + document.Name + "-" + document.Version + ".pb"
err = ioutil.WriteFile(filename, bytes, 0644)
if err != nil {
return handled, err
}
handled = true
}
return handled, err
}
func checkSchema(schemaName string, schema *discovery.Schema, depth int) {
switch schema.Type {
case "string":
case "number":
case "integer":
case "boolean":
case "object": // only objects should have properties...
case "array":
case "null":
log.Printf("NULL TYPE %s %s", schemaName, schema.Type)
case "any":
//log.Printf("ANY TYPE %s/%s %s", schemaName, property.Name, propertySchema.Type)
default:
//log.Printf("UNKNOWN TYPE %s/%s %s", schemaName, property.Name, propertySchema.Type)
}
if len(schema.Properties.AdditionalProperties) > 0 {
if depth > 0 {
log.Printf("ANONYMOUS SCHEMA %s", schemaName)
}
for _, property := range schema.Properties.AdditionalProperties {
propertySchema := property.Value
ref := propertySchema.XRef
if ref != "" {
//log.Printf("REF: %s", ref)
// assert (propertySchema.Type == "")
} else {
checkSchema(schemaName+"/"+property.Name, propertySchema, depth+1)
}
}
}
if schema.AdditionalProperties != nil {
log.Printf("ADDITIONAL PROPERTIES %s", schemaName)
checkSchema(schemaName+"/*", schema.AdditionalProperties, depth+1)
}
}

View File

@ -0,0 +1,287 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// 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 main
import (
"log"
"net/url"
discovery "github.com/googleapis/gnostic/discovery"
openapi2 "github.com/googleapis/gnostic/OpenAPIv2"
)
func addOpenAPI2SchemaForSchema(d *openapi2.Document, name string, schema *discovery.Schema) {
//log.Printf("SCHEMA %s\n", name)
d.Definitions.AdditionalProperties = append(d.Definitions.AdditionalProperties,
&openapi2.NamedSchema{
Name: name,
Value: buildOpenAPI2SchemaForSchema(schema),
})
}
func buildOpenAPI2SchemaForSchema(schema *discovery.Schema) *openapi2.Schema {
s := &openapi2.Schema{}
if description := schema.Description; description != "" {
s.Description = description
}
if typeName := schema.Type; typeName != "" {
s.Type = &openapi2.TypeItem{[]string{typeName}}
}
if ref := schema.XRef; ref != "" {
s.XRef = "#/definitions/" + ref
}
if len(schema.Enum) > 0 {
for _, e := range schema.Enum {
s.Enum = append(s.Enum, &openapi2.Any{Yaml: e})
}
}
if schema.Items != nil {
s2 := buildOpenAPI2SchemaForSchema(schema.Items)
s.Items = &openapi2.ItemsItem{}
s.Items.Schema = append(s.Items.Schema, s2)
}
if schema.Properties != nil {
if len(schema.Properties.AdditionalProperties) > 0 {
s.Properties = &openapi2.Properties{}
for _, pair := range schema.Properties.AdditionalProperties {
s.Properties.AdditionalProperties = append(s.Properties.AdditionalProperties,
&openapi2.NamedSchema{
Name: pair.Name,
Value: buildOpenAPI2SchemaForSchema(pair.Value),
},
)
}
}
}
// assume that all schemas are closed
s.AdditionalProperties = &openapi2.AdditionalPropertiesItem{Oneof: &openapi2.AdditionalPropertiesItem_Boolean{Boolean: false}}
return s
}
func buildOpenAPI2ParameterForParameter(name string, p *discovery.Parameter) *openapi2.Parameter {
//log.Printf("- PARAMETER %+v\n", p.Name)
typeName := p.Type
format := p.Format
location := p.Location
switch location {
case "query":
return &openapi2.Parameter{
Oneof: &openapi2.Parameter_NonBodyParameter{
NonBodyParameter: &openapi2.NonBodyParameter{
Oneof: &openapi2.NonBodyParameter_QueryParameterSubSchema{
QueryParameterSubSchema: &openapi2.QueryParameterSubSchema{
Name: name,
In: "query",
Description: p.Description,
Required: p.Required,
Type: typeName,
Format: format,
},
},
},
},
}
case "path":
return &openapi2.Parameter{
Oneof: &openapi2.Parameter_NonBodyParameter{
NonBodyParameter: &openapi2.NonBodyParameter{
Oneof: &openapi2.NonBodyParameter_PathParameterSubSchema{
PathParameterSubSchema: &openapi2.PathParameterSubSchema{
Name: name,
In: "path",
Description: p.Description,
Required: p.Required,
Type: typeName,
Format: format,
},
},
},
},
}
default:
return nil
}
}
func buildOpenAPI2ParameterForRequest(p *discovery.Request) *openapi2.Parameter {
return &openapi2.Parameter{
Oneof: &openapi2.Parameter_BodyParameter{
BodyParameter: &openapi2.BodyParameter{
Name: "resource",
In: "body",
Description: "",
Schema: &openapi2.Schema{XRef: "#/definitions/" + p.XRef},
},
},
}
}
func buildOpenAPI2ResponseForResponse(response *discovery.Response) *openapi2.Response {
//log.Printf("- RESPONSE %+v\n", schema)
if response == nil {
return &openapi2.Response{
Description: "Successful operation",
}
}
ref := response.XRef
if ref == "" {
log.Printf("WARNING: Unhandled response %+v", response)
}
return &openapi2.Response{
Description: "Successful operation",
Schema: &openapi2.SchemaItem{
Oneof: &openapi2.SchemaItem_Schema{
Schema: &openapi2.Schema{
XRef: "#/definitions/" + ref,
},
},
},
}
}
func buildOpenAPI2OperationForMethod(method *discovery.Method) *openapi2.Operation {
//log.Printf("METHOD %s %s %s %s\n", method.Name, method.path(), method.HTTPMethod, method.ID)
//log.Printf("MAP %+v\n", method.JSONMap)
parameters := make([]*openapi2.ParametersItem, 0)
if method.Parameters != nil {
for _, pair := range method.Parameters.AdditionalProperties {
parameters = append(parameters, &openapi2.ParametersItem{
Oneof: &openapi2.ParametersItem_Parameter{
Parameter: buildOpenAPI2ParameterForParameter(pair.Name, pair.Value),
},
})
}
}
responses := &openapi2.Responses{
ResponseCode: []*openapi2.NamedResponseValue{
&openapi2.NamedResponseValue{
Name: "default",
Value: &openapi2.ResponseValue{
Oneof: &openapi2.ResponseValue_Response{
Response: buildOpenAPI2ResponseForResponse(method.Response),
},
},
},
},
}
if method.Request != nil {
parameter := buildOpenAPI2ParameterForRequest(method.Request)
parameters = append(parameters, &openapi2.ParametersItem{
Oneof: &openapi2.ParametersItem_Parameter{
Parameter: parameter,
},
})
}
return &openapi2.Operation{
Description: method.Description,
OperationId: method.Id,
Parameters: parameters,
Responses: responses,
}
}
func getOpenAPI2PathItemForPath(d *openapi2.Document, path string) *openapi2.PathItem {
// First, try to find a path item with the specified path. If it exists, return it.
for _, item := range d.Paths.Path {
if item.Name == path {
return item.Value
}
}
// Otherwise, create and return a new path item.
pathItem := &openapi2.PathItem{}
d.Paths.Path = append(d.Paths.Path,
&openapi2.NamedPathItem{
Name: path,
Value: pathItem,
},
)
return pathItem
}
func addOpenAPI2PathsForMethod(d *openapi2.Document, name string, method *discovery.Method) {
operation := buildOpenAPI2OperationForMethod(method)
pathItem := getOpenAPI2PathItemForPath(d, pathForMethod(method.Path))
switch method.HttpMethod {
case "GET":
pathItem.Get = operation
case "POST":
pathItem.Post = operation
case "PUT":
pathItem.Put = operation
case "DELETE":
pathItem.Delete = operation
case "PATCH":
pathItem.Patch = operation
default:
log.Printf("WARNING: Unknown HTTP method %s", method.HttpMethod)
}
}
func addOpenAPI2PathsForResource(d *openapi2.Document, name string, resource *discovery.Resource) {
//log.Printf("RESOURCE %s (%s)\n", resource.Name, resource.FullName)
if resource.Methods != nil {
for _, pair := range resource.Methods.AdditionalProperties {
addOpenAPI2PathsForMethod(d, pair.Name, pair.Value)
}
}
if resource.Resources != nil {
for _, pair := range resource.Resources.AdditionalProperties {
addOpenAPI2PathsForResource(d, pair.Name, pair.Value)
}
}
}
func removeTrailingSlash(path string) string {
if len(path) > 1 && path[len(path)-1] == '/' {
return path[0: len(path)-1]
}
return path
}
// OpenAPIv2 returns an OpenAPI v2 representation of this Discovery document
func OpenAPIv2(api *discovery.Document) (*openapi2.Document, error) {
d := &openapi2.Document{}
d.Swagger = "2.0"
d.Info = &openapi2.Info{
Title: api.Title,
Version: api.Version,
Description: api.Description,
}
url, _ := url.Parse(api.RootUrl)
d.Host = url.Host
d.BasePath = removeTrailingSlash(api.BasePath)
d.Schemes = []string{url.Scheme}
d.Consumes = []string{"application/json"}
d.Produces = []string{"application/json"}
d.Paths = &openapi2.Paths{}
d.Definitions = &openapi2.Definitions{}
if api.Schemas != nil {
for _, pair := range api.Schemas.AdditionalProperties {
addOpenAPI2SchemaForSchema(d, pair.Name, pair.Value)
}
}
if api.Methods != nil {
for _, pair := range api.Methods.AdditionalProperties {
addOpenAPI2PathsForMethod(d, pair.Name, pair.Value)
}
}
if api.Resources != nil {
for _, pair := range api.Resources.AdditionalProperties {
addOpenAPI2PathsForResource(d, pair.Name, pair.Value)
}
}
return d, nil
}

View File

@ -0,0 +1,303 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// 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 main
import (
"log"
"net/url"
"strings"
openapi3 "github.com/googleapis/gnostic/OpenAPIv3"
discovery "github.com/googleapis/gnostic/discovery"
)
func pathForMethod(path string) string {
return "/" + strings.Replace(path, "{+", "{", -1)
}
func addOpenAPI3SchemaForSchema(d *openapi3.Document, name string, schema *discovery.Schema) {
d.Components.Schemas.AdditionalProperties = append(d.Components.Schemas.AdditionalProperties,
&openapi3.NamedSchemaOrReference{
Name: name,
Value: buildOpenAPI3SchemaOrReferenceForSchema(schema),
})
}
func buildOpenAPI3SchemaOrReferenceForSchema(schema *discovery.Schema) *openapi3.SchemaOrReference {
if ref := schema.XRef; ref != "" {
return &openapi3.SchemaOrReference{
Oneof: &openapi3.SchemaOrReference_Reference{
Reference: &openapi3.Reference{
XRef: "#/definitions/" + ref,
},
},
}
}
s := &openapi3.Schema{}
if description := schema.Description; description != "" {
s.Description = description
}
if typeName := schema.Type; typeName != "" {
s.Type = typeName
}
if len(schema.Enum) > 0 {
for _, e := range schema.Enum {
s.Enum = append(s.Enum, &openapi3.Any{Yaml: e})
}
}
if schema.Items != nil {
s.Items = &openapi3.ItemsItem{
SchemaOrReference: []*openapi3.SchemaOrReference{buildOpenAPI3SchemaOrReferenceForSchema(schema.Items)},
}
}
if (schema.Properties != nil) && (len(schema.Properties.AdditionalProperties) > 0) {
s.Properties = &openapi3.Properties{}
for _, pair := range schema.Properties.AdditionalProperties {
s.Properties.AdditionalProperties = append(s.Properties.AdditionalProperties,
&openapi3.NamedSchemaOrReference{
Name: pair.Name,
Value: buildOpenAPI3SchemaOrReferenceForSchema(pair.Value),
},
)
}
}
return &openapi3.SchemaOrReference{
Oneof: &openapi3.SchemaOrReference_Schema{
Schema: s,
},
}
}
func buildOpenAPI3ParameterForParameter(name string, p *discovery.Parameter) *openapi3.Parameter {
typeName := p.Type
format := p.Format
location := p.Location
switch location {
case "query", "path":
return &openapi3.Parameter{
Name: name,
In: location,
Description: p.Description,
Required: p.Required,
Schema: &openapi3.SchemaOrReference{
Oneof: &openapi3.SchemaOrReference_Schema{
Schema: &openapi3.Schema{
Type: typeName,
Format: format,
},
},
},
}
default:
return nil
}
}
func buildOpenAPI3RequestBodyForRequest(request *discovery.Request) *openapi3.RequestBody {
ref := request.XRef
if ref == "" {
log.Printf("WARNING: Unhandled request schema %+v", request)
}
return &openapi3.RequestBody{
Content: &openapi3.MediaTypes{
AdditionalProperties: []*openapi3.NamedMediaType{
&openapi3.NamedMediaType{
Name: "application/json",
Value: &openapi3.MediaType{
Schema: &openapi3.SchemaOrReference{
Oneof: &openapi3.SchemaOrReference_Reference{
Reference: &openapi3.Reference{
XRef: "#/definitions/" + ref,
},
},
},
},
},
},
},
}
}
func buildOpenAPI3ResponseForResponse(response *discovery.Response, hasDataWrapper bool) *openapi3.Response {
if response == nil {
return &openapi3.Response{
Description: "Successful operation",
}
} else {
ref := response.XRef
if ref == "" {
log.Printf("WARNING: Unhandled response %+v", response)
}
return &openapi3.Response{
Description: "Successful operation",
Content: &openapi3.MediaTypes{
AdditionalProperties: []*openapi3.NamedMediaType{
&openapi3.NamedMediaType{
Name: "application/json",
Value: &openapi3.MediaType{
Schema: &openapi3.SchemaOrReference{
Oneof: &openapi3.SchemaOrReference_Reference{
Reference: &openapi3.Reference{
XRef: "#/definitions/" + ref,
},
},
},
},
},
},
},
}
}
}
func buildOpenAPI3OperationForMethod(method *discovery.Method, hasDataWrapper bool) *openapi3.Operation {
if method == nil {
return nil
}
parameters := make([]*openapi3.ParameterOrReference, 0)
if method.Parameters != nil {
for _, pair := range method.Parameters.AdditionalProperties {
parameters = append(parameters, &openapi3.ParameterOrReference{
Oneof: &openapi3.ParameterOrReference_Parameter{
Parameter: buildOpenAPI3ParameterForParameter(pair.Name, pair.Value),
},
})
}
}
responses := &openapi3.Responses{
ResponseOrReference: []*openapi3.NamedResponseOrReference{
&openapi3.NamedResponseOrReference{
Name: "default",
Value: &openapi3.ResponseOrReference{
Oneof: &openapi3.ResponseOrReference_Response{
Response: buildOpenAPI3ResponseForResponse(method.Response, hasDataWrapper),
},
},
},
},
}
var requestBodyOrReference *openapi3.RequestBodyOrReference
if method.Request != nil {
requestBody := buildOpenAPI3RequestBodyForRequest(method.Request)
requestBodyOrReference = &openapi3.RequestBodyOrReference{
Oneof: &openapi3.RequestBodyOrReference_RequestBody{
RequestBody: requestBody,
},
}
}
return &openapi3.Operation{
Description: method.Description,
OperationId: method.Id,
Parameters: parameters,
Responses: responses,
RequestBody: requestBodyOrReference,
}
}
func getOpenAPI3PathItemForPath(d *openapi3.Document, path string) *openapi3.PathItem {
// First, try to find a path item with the specified path. If it exists, return it.
for _, item := range d.Paths.Path {
if item.Name == path {
return item.Value
}
}
// Otherwise, create and return a new path item.
pathItem := &openapi3.PathItem{}
d.Paths.Path = append(d.Paths.Path,
&openapi3.NamedPathItem{
Name: path,
Value: pathItem,
},
)
return pathItem
}
func addOpenAPI3PathsForMethod(d *openapi3.Document, name string, method *discovery.Method, hasDataWrapper bool) {
operation := buildOpenAPI3OperationForMethod(method, hasDataWrapper)
pathItem := getOpenAPI3PathItemForPath(d, pathForMethod(method.Path))
switch method.HttpMethod {
case "GET":
pathItem.Get = operation
case "POST":
pathItem.Post = operation
case "PUT":
pathItem.Put = operation
case "DELETE":
pathItem.Delete = operation
case "PATCH":
pathItem.Patch = operation
default:
log.Printf("WARNING: Unknown HTTP method %s", method.HttpMethod)
}
}
func addOpenAPI3PathsForResource(d *openapi3.Document, resource *discovery.Resource, hasDataWrapper bool) {
if resource.Methods != nil {
for _, pair := range resource.Methods.AdditionalProperties {
addOpenAPI3PathsForMethod(d, pair.Name, pair.Value, hasDataWrapper)
}
}
if resource.Resources != nil {
for _, pair := range resource.Resources.AdditionalProperties {
addOpenAPI3PathsForResource(d, pair.Value, hasDataWrapper)
}
}
}
// OpenAPIv3 returns an OpenAPI v3 representation of a Discovery document
func OpenAPIv3(api *discovery.Document) (*openapi3.Document, error) {
d := &openapi3.Document{}
d.Openapi = "3.0"
d.Info = &openapi3.Info{
Title: api.Title,
Version: api.Version,
Description: api.Description,
}
d.Servers = make([]*openapi3.Server, 0)
url, _ := url.Parse(api.RootUrl)
host := url.Host
basePath := api.BasePath
if basePath == "" {
basePath = "/"
}
d.Servers = append(d.Servers, &openapi3.Server{Url: "https://" + host + basePath})
hasDataWrapper := false
for _, feature := range api.Features {
if feature == "dataWrapper" {
hasDataWrapper = true
}
}
d.Components = &openapi3.Components{}
d.Components.Schemas = &openapi3.SchemasOrReferences{}
for _, pair := range api.Schemas.AdditionalProperties {
addOpenAPI3SchemaForSchema(d, pair.Name, pair.Value)
}
d.Paths = &openapi3.Paths{}
if api.Methods != nil {
for _, pair := range api.Methods.AdditionalProperties {
addOpenAPI3PathsForMethod(d, pair.Name, pair.Value, hasDataWrapper)
}
}
for _, pair := range api.Resources.AdditionalProperties {
addOpenAPI3PathsForResource(d, pair.Value, hasDataWrapper)
}
return d, nil
}