vendor cleanup: remove unused,non-go and test files

This commit is contained in:
Madhu Rajanna
2019-01-16 00:05:52 +05:30
parent 52cf4aa902
commit b10ba188e7
15421 changed files with 17 additions and 4208853 deletions

View File

@ -1,21 +0,0 @@
# IntelliJ IDEA
.idea
# Eclipse
.checkstyle
.project
.settings
# Swift
.build
Packages
# Node
node_modules
package-lock.json
bundle.json
# vi
*.swp
# vscode
.vscode
.DS_Store
*~
Package.resolved
extensions/sample/generated

View File

@ -1,29 +0,0 @@
#!/bin/sh
#
# Install dependencies that aren't available as Ubuntu packages.
#
# Everything goes into $HOME/local.
#
# Scripts should add
# - $HOME/local/bin to PATH
# - $HOME/local/lib to LD_LIBRARY_PATH
#
cd
mkdir -p local
# Install swift
SWIFT_URL=https://swift.org/builds/swift-4.0-branch/ubuntu1404/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-09-01-a/swift-4.0-DEVELOPMENT-SNAPSHOT-2017-09-01-a-ubuntu14.04.tar.gz
echo $SWIFT_URL
curl -fSsL $SWIFT_URL -o swift.tar.gz
tar -xzf swift.tar.gz --strip-components=2 --directory=local
# Install protoc
PROTOC_URL=https://github.com/google/protobuf/releases/download/v3.4.0/protoc-3.4.0-linux-x86_64.zip
echo $PROTOC_URL
curl -fSsL $PROTOC_URL -o protoc.zip
unzip protoc.zip -d local
# Verify installation
find local

View File

@ -1,49 +0,0 @@
# Travis CI build file for OpenAPI Compiler, including Go and Swift plugins
# Use Ubuntu 14.04
dist: trusty
sudo: false
language: go
addons:
apt:
packages:
- clang-3.8
- lldb-3.8
- libicu-dev
- libtool
- libcurl4-openssl-dev
- libbsd-dev
- build-essential
- libssl-dev
- uuid-dev
- curl
- unzip
install:
- ./.travis-install.sh
- export PATH=.:$HOME/local/bin:$PATH
- make
script:
- go test . -v
- pushd plugins/gnostic-go-generator/examples/v2.0/bookstore
- make test
- popd
- pushd plugins/gnostic-go-generator/examples/v2.0/sample
- make test
- popd
- pushd plugins/gnostic-go-generator/examples/v3.0/bookstore
- make test
- popd
- export PATH=.:$HOME/local/bin:$PATH
- export LD_LIBRARY_PATH=$HOME/local/lib
- pushd plugins/gnostic-swift-generator
- make install
- cd examples/bookstore
- make
- .build/debug/Server &
- make test

View File

@ -1,35 +0,0 @@
#!/bin/sh
#
# Copyright 2016 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.
#
go get github.com/golang/protobuf/protoc-gen-go
protoc \
--go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. \
OpenAPIv2/OpenAPIv2.proto
protoc \
-I.:$GOPATH/src \
--go_out=:. \
plugins/plugin.proto
protoc \
--go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. \
OpenAPIv3/OpenAPIv3.proto
protoc \
--go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. \
discovery/discovery.proto

View File

@ -1,35 +0,0 @@
# How to become a contributor and submit your own code
## Contributor License Agreements
We'd love to accept your sample apps and patches! Before we can take them, we
have to jump a couple of legal hurdles.
Please fill out either the individual or corporate Contributor License Agreement
(CLA).
* If you are an individual writing original source code and you're sure you
own the intellectual property, then you'll need to sign an [individual CLA]
(https://developers.google.com/open-source/cla/individual).
* If you work for a company that wants to allow you to contribute your work,
then you'll need to sign a [corporate CLA]
(https://developers.google.com/open-source/cla/corporate).
Follow either of the two links above to access the appropriate CLA and
instructions for how to sign and return it. Once we receive it, we'll be able to
accept your pull requests.
## Contributing A Patch
1. Submit an issue describing your proposed change to the repo in question.
1. The repo owner will respond to your issue promptly.
1. If your proposed change is accepted, and you haven't already done so, sign a
Contributor License Agreement (see details above).
1. Fork the desired repo, develop and test your code changes.
1. Ensure that your code adheres to the existing style in the sample to which
you are contributing. Refer to the
[Google Cloud Platform Samples Style Guide]
(https://github.com/GoogleCloudPlatform/Template/wiki/style.html) for the
recommended coding standards for this organization.
1. Ensure that your code has an appropriate set of unit tests which all pass.
1. Submit a pull request.

View File

@ -1,16 +0,0 @@
build:
go get
go install
cd generate-gnostic; go get; go install
cd apps/disco; go get; go install
cd apps/report; go get; go install
cd apps/petstore-builder; go get; go install
cd plugins/gnostic-summary; go get; go install
cd plugins/gnostic-analyze; go get; go install
cd plugins/gnostic-go-generator; go get; go install
rm -f $(GOPATH)/bin/gnostic-go-client $(GOPATH)/bin/gnostic-go-server
ln -s $(GOPATH)/bin/gnostic-go-generator $(GOPATH)/bin/gnostic-go-client
ln -s $(GOPATH)/bin/gnostic-go-generator $(GOPATH)/bin/gnostic-go-server
cd extensions/sample; make

View File

@ -1,663 +0,0 @@
// 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.
// THIS FILE IS AUTOMATICALLY GENERATED.
syntax = "proto3";
package openapi.v2;
import "google/protobuf/any.proto";
// This option lets the proto compiler generate Java code inside the package
// name (see below) instead of inside an outer class. It creates a simpler
// developer experience by reducing one-level of name nesting and be
// consistent with most programming languages that don't support outer classes.
option java_multiple_files = true;
// The Java outer classname should be the filename in UpperCamelCase. This
// class is only used to hold proto descriptor, so developers don't need to
// work with it directly.
option java_outer_classname = "OpenAPIProto";
// The Java package name must be proto package name with proper prefix.
option java_package = "org.openapi_v2";
// A reasonable prefix for the Objective-C symbols generated from the package.
// It should at a minimum be 3 characters long, all uppercase, and convention
// is to use an abbreviation of the package name. Something short, but
// hopefully unique enough to not conflict with things that may come along in
// the future. 'GPB' is reserved for the protocol buffer implementation itself.
option objc_class_prefix = "OAS";
message AdditionalPropertiesItem {
oneof oneof {
Schema schema = 1;
bool boolean = 2;
}
}
message Any {
google.protobuf.Any value = 1;
string yaml = 2;
}
message ApiKeySecurity {
string type = 1;
string name = 2;
string in = 3;
string description = 4;
repeated NamedAny vendor_extension = 5;
}
message BasicAuthenticationSecurity {
string type = 1;
string description = 2;
repeated NamedAny vendor_extension = 3;
}
message BodyParameter {
// A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed.
string description = 1;
// The name of the parameter.
string name = 2;
// Determines the location of the parameter.
string in = 3;
// Determines whether or not this parameter is required or optional.
bool required = 4;
Schema schema = 5;
repeated NamedAny vendor_extension = 6;
}
// Contact information for the owners of the API.
message Contact {
// The identifying name of the contact person/organization.
string name = 1;
// The URL pointing to the contact information.
string url = 2;
// The email address of the contact person/organization.
string email = 3;
repeated NamedAny vendor_extension = 4;
}
message Default {
repeated NamedAny additional_properties = 1;
}
// One or more JSON objects describing the schemas being consumed and produced by the API.
message Definitions {
repeated NamedSchema additional_properties = 1;
}
message Document {
// The Swagger version of this document.
string swagger = 1;
Info info = 2;
// The host (name or ip) of the API. Example: 'swagger.io'
string host = 3;
// The base path to the API. Example: '/api'.
string base_path = 4;
// The transfer protocol of the API.
repeated string schemes = 5;
// A list of MIME types accepted by the API.
repeated string consumes = 6;
// A list of MIME types the API can produce.
repeated string produces = 7;
Paths paths = 8;
Definitions definitions = 9;
ParameterDefinitions parameters = 10;
ResponseDefinitions responses = 11;
repeated SecurityRequirement security = 12;
SecurityDefinitions security_definitions = 13;
repeated Tag tags = 14;
ExternalDocs external_docs = 15;
repeated NamedAny vendor_extension = 16;
}
message Examples {
repeated NamedAny additional_properties = 1;
}
// information about external documentation
message ExternalDocs {
string description = 1;
string url = 2;
repeated NamedAny vendor_extension = 3;
}
// A deterministic version of a JSON Schema object.
message FileSchema {
string format = 1;
string title = 2;
string description = 3;
Any default = 4;
repeated string required = 5;
string type = 6;
bool read_only = 7;
ExternalDocs external_docs = 8;
Any example = 9;
repeated NamedAny vendor_extension = 10;
}
message FormDataParameterSubSchema {
// Determines whether or not this parameter is required or optional.
bool required = 1;
// Determines the location of the parameter.
string in = 2;
// A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed.
string description = 3;
// The name of the parameter.
string name = 4;
// allows sending a parameter by name only or with an empty value.
bool allow_empty_value = 5;
string type = 6;
string format = 7;
PrimitivesItems items = 8;
string collection_format = 9;
Any default = 10;
double maximum = 11;
bool exclusive_maximum = 12;
double minimum = 13;
bool exclusive_minimum = 14;
int64 max_length = 15;
int64 min_length = 16;
string pattern = 17;
int64 max_items = 18;
int64 min_items = 19;
bool unique_items = 20;
repeated Any enum = 21;
double multiple_of = 22;
repeated NamedAny vendor_extension = 23;
}
message Header {
string type = 1;
string format = 2;
PrimitivesItems items = 3;
string collection_format = 4;
Any default = 5;
double maximum = 6;
bool exclusive_maximum = 7;
double minimum = 8;
bool exclusive_minimum = 9;
int64 max_length = 10;
int64 min_length = 11;
string pattern = 12;
int64 max_items = 13;
int64 min_items = 14;
bool unique_items = 15;
repeated Any enum = 16;
double multiple_of = 17;
string description = 18;
repeated NamedAny vendor_extension = 19;
}
message HeaderParameterSubSchema {
// Determines whether or not this parameter is required or optional.
bool required = 1;
// Determines the location of the parameter.
string in = 2;
// A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed.
string description = 3;
// The name of the parameter.
string name = 4;
string type = 5;
string format = 6;
PrimitivesItems items = 7;
string collection_format = 8;
Any default = 9;
double maximum = 10;
bool exclusive_maximum = 11;
double minimum = 12;
bool exclusive_minimum = 13;
int64 max_length = 14;
int64 min_length = 15;
string pattern = 16;
int64 max_items = 17;
int64 min_items = 18;
bool unique_items = 19;
repeated Any enum = 20;
double multiple_of = 21;
repeated NamedAny vendor_extension = 22;
}
message Headers {
repeated NamedHeader additional_properties = 1;
}
// General information about the API.
message Info {
// A unique and precise title of the API.
string title = 1;
// A semantic version number of the API.
string version = 2;
// A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed.
string description = 3;
// The terms of service for the API.
string terms_of_service = 4;
Contact contact = 5;
License license = 6;
repeated NamedAny vendor_extension = 7;
}
message ItemsItem {
repeated Schema schema = 1;
}
message JsonReference {
string _ref = 1;
string description = 2;
}
message License {
// The name of the license type. It's encouraged to use an OSI compatible license.
string name = 1;
// The URL pointing to the license.
string url = 2;
repeated NamedAny vendor_extension = 3;
}
// Automatically-generated message used to represent maps of Any as ordered (name,value) pairs.
message NamedAny {
// Map key
string name = 1;
// Mapped value
Any value = 2;
}
// Automatically-generated message used to represent maps of Header as ordered (name,value) pairs.
message NamedHeader {
// Map key
string name = 1;
// Mapped value
Header value = 2;
}
// Automatically-generated message used to represent maps of Parameter as ordered (name,value) pairs.
message NamedParameter {
// Map key
string name = 1;
// Mapped value
Parameter value = 2;
}
// Automatically-generated message used to represent maps of PathItem as ordered (name,value) pairs.
message NamedPathItem {
// Map key
string name = 1;
// Mapped value
PathItem value = 2;
}
// Automatically-generated message used to represent maps of Response as ordered (name,value) pairs.
message NamedResponse {
// Map key
string name = 1;
// Mapped value
Response value = 2;
}
// Automatically-generated message used to represent maps of ResponseValue as ordered (name,value) pairs.
message NamedResponseValue {
// Map key
string name = 1;
// Mapped value
ResponseValue value = 2;
}
// Automatically-generated message used to represent maps of Schema as ordered (name,value) pairs.
message NamedSchema {
// Map key
string name = 1;
// Mapped value
Schema value = 2;
}
// Automatically-generated message used to represent maps of SecurityDefinitionsItem as ordered (name,value) pairs.
message NamedSecurityDefinitionsItem {
// Map key
string name = 1;
// Mapped value
SecurityDefinitionsItem value = 2;
}
// Automatically-generated message used to represent maps of string as ordered (name,value) pairs.
message NamedString {
// Map key
string name = 1;
// Mapped value
string value = 2;
}
// Automatically-generated message used to represent maps of StringArray as ordered (name,value) pairs.
message NamedStringArray {
// Map key
string name = 1;
// Mapped value
StringArray value = 2;
}
message NonBodyParameter {
oneof oneof {
HeaderParameterSubSchema header_parameter_sub_schema = 1;
FormDataParameterSubSchema form_data_parameter_sub_schema = 2;
QueryParameterSubSchema query_parameter_sub_schema = 3;
PathParameterSubSchema path_parameter_sub_schema = 4;
}
}
message Oauth2AccessCodeSecurity {
string type = 1;
string flow = 2;
Oauth2Scopes scopes = 3;
string authorization_url = 4;
string token_url = 5;
string description = 6;
repeated NamedAny vendor_extension = 7;
}
message Oauth2ApplicationSecurity {
string type = 1;
string flow = 2;
Oauth2Scopes scopes = 3;
string token_url = 4;
string description = 5;
repeated NamedAny vendor_extension = 6;
}
message Oauth2ImplicitSecurity {
string type = 1;
string flow = 2;
Oauth2Scopes scopes = 3;
string authorization_url = 4;
string description = 5;
repeated NamedAny vendor_extension = 6;
}
message Oauth2PasswordSecurity {
string type = 1;
string flow = 2;
Oauth2Scopes scopes = 3;
string token_url = 4;
string description = 5;
repeated NamedAny vendor_extension = 6;
}
message Oauth2Scopes {
repeated NamedString additional_properties = 1;
}
message Operation {
repeated string tags = 1;
// A brief summary of the operation.
string summary = 2;
// A longer description of the operation, GitHub Flavored Markdown is allowed.
string description = 3;
ExternalDocs external_docs = 4;
// A unique identifier of the operation.
string operation_id = 5;
// A list of MIME types the API can produce.
repeated string produces = 6;
// A list of MIME types the API can consume.
repeated string consumes = 7;
// The parameters needed to send a valid API call.
repeated ParametersItem parameters = 8;
Responses responses = 9;
// The transfer protocol of the API.
repeated string schemes = 10;
bool deprecated = 11;
repeated SecurityRequirement security = 12;
repeated NamedAny vendor_extension = 13;
}
message Parameter {
oneof oneof {
BodyParameter body_parameter = 1;
NonBodyParameter non_body_parameter = 2;
}
}
// One or more JSON representations for parameters
message ParameterDefinitions {
repeated NamedParameter additional_properties = 1;
}
message ParametersItem {
oneof oneof {
Parameter parameter = 1;
JsonReference json_reference = 2;
}
}
message PathItem {
string _ref = 1;
Operation get = 2;
Operation put = 3;
Operation post = 4;
Operation delete = 5;
Operation options = 6;
Operation head = 7;
Operation patch = 8;
// The parameters needed to send a valid API call.
repeated ParametersItem parameters = 9;
repeated NamedAny vendor_extension = 10;
}
message PathParameterSubSchema {
// Determines whether or not this parameter is required or optional.
bool required = 1;
// Determines the location of the parameter.
string in = 2;
// A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed.
string description = 3;
// The name of the parameter.
string name = 4;
string type = 5;
string format = 6;
PrimitivesItems items = 7;
string collection_format = 8;
Any default = 9;
double maximum = 10;
bool exclusive_maximum = 11;
double minimum = 12;
bool exclusive_minimum = 13;
int64 max_length = 14;
int64 min_length = 15;
string pattern = 16;
int64 max_items = 17;
int64 min_items = 18;
bool unique_items = 19;
repeated Any enum = 20;
double multiple_of = 21;
repeated NamedAny vendor_extension = 22;
}
// Relative paths to the individual endpoints. They must be relative to the 'basePath'.
message Paths {
repeated NamedAny vendor_extension = 1;
repeated NamedPathItem path = 2;
}
message PrimitivesItems {
string type = 1;
string format = 2;
PrimitivesItems items = 3;
string collection_format = 4;
Any default = 5;
double maximum = 6;
bool exclusive_maximum = 7;
double minimum = 8;
bool exclusive_minimum = 9;
int64 max_length = 10;
int64 min_length = 11;
string pattern = 12;
int64 max_items = 13;
int64 min_items = 14;
bool unique_items = 15;
repeated Any enum = 16;
double multiple_of = 17;
repeated NamedAny vendor_extension = 18;
}
message Properties {
repeated NamedSchema additional_properties = 1;
}
message QueryParameterSubSchema {
// Determines whether or not this parameter is required or optional.
bool required = 1;
// Determines the location of the parameter.
string in = 2;
// A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed.
string description = 3;
// The name of the parameter.
string name = 4;
// allows sending a parameter by name only or with an empty value.
bool allow_empty_value = 5;
string type = 6;
string format = 7;
PrimitivesItems items = 8;
string collection_format = 9;
Any default = 10;
double maximum = 11;
bool exclusive_maximum = 12;
double minimum = 13;
bool exclusive_minimum = 14;
int64 max_length = 15;
int64 min_length = 16;
string pattern = 17;
int64 max_items = 18;
int64 min_items = 19;
bool unique_items = 20;
repeated Any enum = 21;
double multiple_of = 22;
repeated NamedAny vendor_extension = 23;
}
message Response {
string description = 1;
SchemaItem schema = 2;
Headers headers = 3;
Examples examples = 4;
repeated NamedAny vendor_extension = 5;
}
// One or more JSON representations for parameters
message ResponseDefinitions {
repeated NamedResponse additional_properties = 1;
}
message ResponseValue {
oneof oneof {
Response response = 1;
JsonReference json_reference = 2;
}
}
// Response objects names can either be any valid HTTP status code or 'default'.
message Responses {
repeated NamedResponseValue response_code = 1;
repeated NamedAny vendor_extension = 2;
}
// A deterministic version of a JSON Schema object.
message Schema {
string _ref = 1;
string format = 2;
string title = 3;
string description = 4;
Any default = 5;
double multiple_of = 6;
double maximum = 7;
bool exclusive_maximum = 8;
double minimum = 9;
bool exclusive_minimum = 10;
int64 max_length = 11;
int64 min_length = 12;
string pattern = 13;
int64 max_items = 14;
int64 min_items = 15;
bool unique_items = 16;
int64 max_properties = 17;
int64 min_properties = 18;
repeated string required = 19;
repeated Any enum = 20;
AdditionalPropertiesItem additional_properties = 21;
TypeItem type = 22;
ItemsItem items = 23;
repeated Schema all_of = 24;
Properties properties = 25;
string discriminator = 26;
bool read_only = 27;
Xml xml = 28;
ExternalDocs external_docs = 29;
Any example = 30;
repeated NamedAny vendor_extension = 31;
}
message SchemaItem {
oneof oneof {
Schema schema = 1;
FileSchema file_schema = 2;
}
}
message SecurityDefinitions {
repeated NamedSecurityDefinitionsItem additional_properties = 1;
}
message SecurityDefinitionsItem {
oneof oneof {
BasicAuthenticationSecurity basic_authentication_security = 1;
ApiKeySecurity api_key_security = 2;
Oauth2ImplicitSecurity oauth2_implicit_security = 3;
Oauth2PasswordSecurity oauth2_password_security = 4;
Oauth2ApplicationSecurity oauth2_application_security = 5;
Oauth2AccessCodeSecurity oauth2_access_code_security = 6;
}
}
message SecurityRequirement {
repeated NamedStringArray additional_properties = 1;
}
message StringArray {
repeated string value = 1;
}
message Tag {
string name = 1;
string description = 2;
ExternalDocs external_docs = 3;
repeated NamedAny vendor_extension = 4;
}
message TypeItem {
repeated string value = 1;
}
// Any property starting with x- is valid.
message VendorExtension {
repeated NamedAny additional_properties = 1;
}
message Xml {
string name = 1;
string namespace = 2;
string prefix = 3;
bool attribute = 4;
bool wrapped = 5;
repeated NamedAny vendor_extension = 6;
}

View File

@ -1,16 +0,0 @@
# OpenAPI v2 Protocol Buffer Models
This directory contains a Protocol Buffer-language model
and related code for supporting OpenAPI v2.
Gnostic applications and plugins can use OpenAPIv2.proto
to generate Protocol Buffer support code for their preferred languages.
OpenAPIv2.go is used by Gnostic to read JSON and YAML OpenAPI
descriptions into the Protocol Buffer-based datastructures
generated from OpenAPIv2.proto.
OpenAPIv2.proto and OpenAPIv2.go are generated by the Gnostic
compiler generator, and OpenAPIv2.pb.go is generated by
protoc, the Protocol Buffer compiler, and protoc-gen-go, the
Protocol Buffer Go code generation plugin.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,668 +0,0 @@
// 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.
// THIS FILE IS AUTOMATICALLY GENERATED.
syntax = "proto3";
package openapi.v3;
import "google/protobuf/any.proto";
// This option lets the proto compiler generate Java code inside the package
// name (see below) instead of inside an outer class. It creates a simpler
// developer experience by reducing one-level of name nesting and be
// consistent with most programming languages that don't support outer classes.
option java_multiple_files = true;
// The Java outer classname should be the filename in UpperCamelCase. This
// class is only used to hold proto descriptor, so developers don't need to
// work with it directly.
option java_outer_classname = "OpenAPIProto";
// The Java package name must be proto package name with proper prefix.
option java_package = "org.openapi_v3";
// A reasonable prefix for the Objective-C symbols generated from the package.
// It should at a minimum be 3 characters long, all uppercase, and convention
// is to use an abbreviation of the package name. Something short, but
// hopefully unique enough to not conflict with things that may come along in
// the future. 'GPB' is reserved for the protocol buffer implementation itself.
option objc_class_prefix = "OAS";
message AdditionalPropertiesItem {
oneof oneof {
SchemaOrReference schema_or_reference = 1;
bool boolean = 2;
}
}
message Any {
google.protobuf.Any value = 1;
string yaml = 2;
}
message AnyOrExpression {
oneof oneof {
Any any = 1;
Expression expression = 2;
}
}
message AnysOrExpressions {
repeated NamedAnyOrExpression additional_properties = 1;
}
// A map of possible out-of band callbacks related to the parent operation. Each value in the map is a Path Item Object that describes a set of requests that may be initiated by the API provider and the expected responses. The key value used to identify the callback object is an expression, evaluated at runtime, that identifies a URL to use for the callback operation.
message Callback {
repeated NamedPathItem path = 1;
repeated NamedAny specification_extension = 2;
}
message CallbackOrReference {
oneof oneof {
Callback callback = 1;
Reference reference = 2;
}
}
message CallbacksOrReferences {
repeated NamedCallbackOrReference additional_properties = 1;
}
// Holds a set of reusable objects for different aspects of the OAS. All objects defined within the components object will have no effect on the API unless they are explicitly referenced from properties outside the components object.
message Components {
SchemasOrReferences schemas = 1;
ResponsesOrReferences responses = 2;
ParametersOrReferences parameters = 3;
ExamplesOrReferences examples = 4;
RequestBodiesOrReferences request_bodies = 5;
HeadersOrReferences headers = 6;
SecuritySchemesOrReferences security_schemes = 7;
LinksOrReferences links = 8;
CallbacksOrReferences callbacks = 9;
repeated NamedAny specification_extension = 10;
}
// Contact information for the exposed API.
message Contact {
string name = 1;
string url = 2;
string email = 3;
repeated NamedAny specification_extension = 4;
}
message DefaultType {
oneof oneof {
double number = 1;
bool boolean = 2;
string string = 3;
}
}
// When request bodies or response payloads may be one of a number of different schemas, a `discriminator` object can be used to aid in serialization, deserialization, and validation. The discriminator is a specific object in a schema which is used to inform the consumer of the specification of an alternative schema based on the value associated with it. When using the discriminator, _inline_ schemas will not be considered.
message Discriminator {
string property_name = 1;
Strings mapping = 2;
}
message Document {
string openapi = 1;
Info info = 2;
repeated Server servers = 3;
Paths paths = 4;
Components components = 5;
repeated SecurityRequirement security = 6;
repeated Tag tags = 7;
ExternalDocs external_docs = 8;
repeated NamedAny specification_extension = 9;
}
// A single encoding definition applied to a single schema property.
message Encoding {
string content_type = 1;
HeadersOrReferences headers = 2;
string style = 3;
bool explode = 4;
bool allow_reserved = 5;
repeated NamedAny specification_extension = 6;
}
message Encodings {
repeated NamedEncoding additional_properties = 1;
}
message Example {
string summary = 1;
string description = 2;
Any value = 3;
string external_value = 4;
repeated NamedAny specification_extension = 5;
}
message ExampleOrReference {
oneof oneof {
Example example = 1;
Reference reference = 2;
}
}
message ExamplesOrReferences {
repeated NamedExampleOrReference additional_properties = 1;
}
message Expression {
repeated NamedAny additional_properties = 1;
}
// Allows referencing an external resource for extended documentation.
message ExternalDocs {
string description = 1;
string url = 2;
repeated NamedAny specification_extension = 3;
}
// The Header Object follows the structure of the Parameter Object with the following changes: 1. `name` MUST NOT be specified, it is given in the corresponding `headers` map. 1. `in` MUST NOT be specified, it is implicitly in `header`. 1. All traits that are affected by the location MUST be applicable to a location of `header` (for example, `style`).
message Header {
string description = 1;
bool required = 2;
bool deprecated = 3;
bool allow_empty_value = 4;
string style = 5;
bool explode = 6;
bool allow_reserved = 7;
SchemaOrReference schema = 8;
Any example = 9;
ExamplesOrReferences examples = 10;
MediaTypes content = 11;
repeated NamedAny specification_extension = 12;
}
message HeaderOrReference {
oneof oneof {
Header header = 1;
Reference reference = 2;
}
}
message HeadersOrReferences {
repeated NamedHeaderOrReference additional_properties = 1;
}
// The object provides metadata about the API. The metadata MAY be used by the clients if needed, and MAY be presented in editing or documentation generation tools for convenience.
message Info {
string title = 1;
string description = 2;
string terms_of_service = 3;
Contact contact = 4;
License license = 5;
string version = 6;
repeated NamedAny specification_extension = 7;
}
message ItemsItem {
repeated SchemaOrReference schema_or_reference = 1;
}
// License information for the exposed API.
message License {
string name = 1;
string url = 2;
repeated NamedAny specification_extension = 3;
}
// The `Link object` represents a possible design-time link for a response. The presence of a link does not guarantee the caller's ability to successfully invoke it, rather it provides a known relationship and traversal mechanism between responses and other operations. Unlike _dynamic_ links (i.e. links provided **in** the response payload), the OAS linking mechanism does not require link information in the runtime response. For computing links, and providing instructions to execute them, a runtime expression is used for accessing values in an operation and using them as parameters while invoking the linked operation.
message Link {
string operation_ref = 1;
string operation_id = 2;
AnysOrExpressions parameters = 3;
AnyOrExpression request_body = 4;
string description = 5;
Server server = 6;
repeated NamedAny specification_extension = 7;
}
message LinkOrReference {
oneof oneof {
Link link = 1;
Reference reference = 2;
}
}
message LinksOrReferences {
repeated NamedLinkOrReference additional_properties = 1;
}
// Each Media Type Object provides schema and examples for the media type identified by its key.
message MediaType {
SchemaOrReference schema = 1;
Any example = 2;
ExamplesOrReferences examples = 3;
Encodings encoding = 4;
repeated NamedAny specification_extension = 5;
}
message MediaTypes {
repeated NamedMediaType additional_properties = 1;
}
// Automatically-generated message used to represent maps of Any as ordered (name,value) pairs.
message NamedAny {
// Map key
string name = 1;
// Mapped value
Any value = 2;
}
// Automatically-generated message used to represent maps of AnyOrExpression as ordered (name,value) pairs.
message NamedAnyOrExpression {
// Map key
string name = 1;
// Mapped value
AnyOrExpression value = 2;
}
// Automatically-generated message used to represent maps of CallbackOrReference as ordered (name,value) pairs.
message NamedCallbackOrReference {
// Map key
string name = 1;
// Mapped value
CallbackOrReference value = 2;
}
// Automatically-generated message used to represent maps of Encoding as ordered (name,value) pairs.
message NamedEncoding {
// Map key
string name = 1;
// Mapped value
Encoding value = 2;
}
// Automatically-generated message used to represent maps of ExampleOrReference as ordered (name,value) pairs.
message NamedExampleOrReference {
// Map key
string name = 1;
// Mapped value
ExampleOrReference value = 2;
}
// Automatically-generated message used to represent maps of HeaderOrReference as ordered (name,value) pairs.
message NamedHeaderOrReference {
// Map key
string name = 1;
// Mapped value
HeaderOrReference value = 2;
}
// Automatically-generated message used to represent maps of LinkOrReference as ordered (name,value) pairs.
message NamedLinkOrReference {
// Map key
string name = 1;
// Mapped value
LinkOrReference value = 2;
}
// Automatically-generated message used to represent maps of MediaType as ordered (name,value) pairs.
message NamedMediaType {
// Map key
string name = 1;
// Mapped value
MediaType value = 2;
}
// Automatically-generated message used to represent maps of ParameterOrReference as ordered (name,value) pairs.
message NamedParameterOrReference {
// Map key
string name = 1;
// Mapped value
ParameterOrReference value = 2;
}
// Automatically-generated message used to represent maps of PathItem as ordered (name,value) pairs.
message NamedPathItem {
// Map key
string name = 1;
// Mapped value
PathItem value = 2;
}
// Automatically-generated message used to represent maps of RequestBodyOrReference as ordered (name,value) pairs.
message NamedRequestBodyOrReference {
// Map key
string name = 1;
// Mapped value
RequestBodyOrReference value = 2;
}
// Automatically-generated message used to represent maps of ResponseOrReference as ordered (name,value) pairs.
message NamedResponseOrReference {
// Map key
string name = 1;
// Mapped value
ResponseOrReference value = 2;
}
// Automatically-generated message used to represent maps of SchemaOrReference as ordered (name,value) pairs.
message NamedSchemaOrReference {
// Map key
string name = 1;
// Mapped value
SchemaOrReference value = 2;
}
// Automatically-generated message used to represent maps of SecuritySchemeOrReference as ordered (name,value) pairs.
message NamedSecuritySchemeOrReference {
// Map key
string name = 1;
// Mapped value
SecuritySchemeOrReference value = 2;
}
// Automatically-generated message used to represent maps of ServerVariable as ordered (name,value) pairs.
message NamedServerVariable {
// Map key
string name = 1;
// Mapped value
ServerVariable value = 2;
}
// Automatically-generated message used to represent maps of string as ordered (name,value) pairs.
message NamedString {
// Map key
string name = 1;
// Mapped value
string value = 2;
}
// Configuration details for a supported OAuth Flow
message OauthFlow {
string authorization_url = 1;
string token_url = 2;
string refresh_url = 3;
Strings scopes = 4;
repeated NamedAny specification_extension = 5;
}
// Allows configuration of the supported OAuth Flows.
message OauthFlows {
OauthFlow implicit = 1;
OauthFlow password = 2;
OauthFlow client_credentials = 3;
OauthFlow authorization_code = 4;
repeated NamedAny specification_extension = 5;
}
message Object {
repeated NamedAny additional_properties = 1;
}
// Describes a single API operation on a path.
message Operation {
repeated string tags = 1;
string summary = 2;
string description = 3;
ExternalDocs external_docs = 4;
string operation_id = 5;
repeated ParameterOrReference parameters = 6;
RequestBodyOrReference request_body = 7;
Responses responses = 8;
CallbacksOrReferences callbacks = 9;
bool deprecated = 10;
repeated SecurityRequirement security = 11;
repeated Server servers = 12;
repeated NamedAny specification_extension = 13;
}
// Describes a single operation parameter. A unique parameter is defined by a combination of a name and location.
message Parameter {
string name = 1;
string in = 2;
string description = 3;
bool required = 4;
bool deprecated = 5;
bool allow_empty_value = 6;
string style = 7;
bool explode = 8;
bool allow_reserved = 9;
SchemaOrReference schema = 10;
Any example = 11;
ExamplesOrReferences examples = 12;
MediaTypes content = 13;
repeated NamedAny specification_extension = 14;
}
message ParameterOrReference {
oneof oneof {
Parameter parameter = 1;
Reference reference = 2;
}
}
message ParametersOrReferences {
repeated NamedParameterOrReference additional_properties = 1;
}
// Describes the operations available on a single path. A Path Item MAY be empty, due to ACL constraints. The path itself is still exposed to the documentation viewer but they will not know which operations and parameters are available.
message PathItem {
string _ref = 1;
string summary = 2;
string description = 3;
Operation get = 4;
Operation put = 5;
Operation post = 6;
Operation delete = 7;
Operation options = 8;
Operation head = 9;
Operation patch = 10;
Operation trace = 11;
repeated Server servers = 12;
repeated ParameterOrReference parameters = 13;
repeated NamedAny specification_extension = 14;
}
// Holds the relative paths to the individual endpoints and their operations. The path is appended to the URL from the `Server Object` in order to construct the full URL. The Paths MAY be empty, due to ACL constraints.
message Paths {
repeated NamedPathItem path = 1;
repeated NamedAny specification_extension = 2;
}
message Properties {
repeated NamedSchemaOrReference additional_properties = 1;
}
// A simple object to allow referencing other components in the specification, internally and externally. The Reference Object is defined by JSON Reference and follows the same structure, behavior and rules. For this specification, reference resolution is accomplished as defined by the JSON Reference specification and not by the JSON Schema specification.
message Reference {
string _ref = 1;
}
message RequestBodiesOrReferences {
repeated NamedRequestBodyOrReference additional_properties = 1;
}
// Describes a single request body.
message RequestBody {
string description = 1;
MediaTypes content = 2;
bool required = 3;
repeated NamedAny specification_extension = 4;
}
message RequestBodyOrReference {
oneof oneof {
RequestBody request_body = 1;
Reference reference = 2;
}
}
// Describes a single response from an API Operation, including design-time, static `links` to operations based on the response.
message Response {
string description = 1;
HeadersOrReferences headers = 2;
MediaTypes content = 3;
LinksOrReferences links = 4;
repeated NamedAny specification_extension = 5;
}
message ResponseOrReference {
oneof oneof {
Response response = 1;
Reference reference = 2;
}
}
// A container for the expected responses of an operation. The container maps a HTTP response code to the expected response. The documentation is not necessarily expected to cover all possible HTTP response codes because they may not be known in advance. However, documentation is expected to cover a successful operation response and any known errors. The `default` MAY be used as a default response object for all HTTP codes that are not covered individually by the specification. The `Responses Object` MUST contain at least one response code, and it SHOULD be the response for a successful operation call.
message Responses {
ResponseOrReference default = 1;
repeated NamedResponseOrReference response_or_reference = 2;
repeated NamedAny specification_extension = 3;
}
message ResponsesOrReferences {
repeated NamedResponseOrReference additional_properties = 1;
}
// The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays. This object is an extended subset of the JSON Schema Specification Wright Draft 00. For more information about the properties, see JSON Schema Core and JSON Schema Validation. Unless stated otherwise, the property definitions follow the JSON Schema.
message Schema {
bool nullable = 1;
Discriminator discriminator = 2;
bool read_only = 3;
bool write_only = 4;
Xml xml = 5;
ExternalDocs external_docs = 6;
Any example = 7;
bool deprecated = 8;
string title = 9;
double multiple_of = 10;
double maximum = 11;
bool exclusive_maximum = 12;
double minimum = 13;
bool exclusive_minimum = 14;
int64 max_length = 15;
int64 min_length = 16;
string pattern = 17;
int64 max_items = 18;
int64 min_items = 19;
bool unique_items = 20;
int64 max_properties = 21;
int64 min_properties = 22;
repeated string required = 23;
repeated Any enum = 24;
string type = 25;
repeated SchemaOrReference all_of = 26;
repeated SchemaOrReference one_of = 27;
repeated SchemaOrReference any_of = 28;
Schema not = 29;
ItemsItem items = 30;
Properties properties = 31;
AdditionalPropertiesItem additional_properties = 32;
DefaultType default = 33;
string description = 34;
string format = 35;
repeated NamedAny specification_extension = 36;
}
message SchemaOrReference {
oneof oneof {
Schema schema = 1;
Reference reference = 2;
}
}
message SchemasOrReferences {
repeated NamedSchemaOrReference additional_properties = 1;
}
// Lists the required security schemes to execute this operation. The name used for each property MUST correspond to a security scheme declared in the Security Schemes under the Components Object. Security Requirement Objects that contain multiple schemes require that all schemes MUST be satisfied for a request to be authorized. This enables support for scenarios where multiple query parameters or HTTP headers are required to convey security information. When a list of Security Requirement Objects is defined on the Open API object or Operation Object, only one of Security Requirement Objects in the list needs to be satisfied to authorize the request.
message SecurityRequirement {
}
// Defines a security scheme that can be used by the operations. Supported schemes are HTTP authentication, an API key (either as a header or as a query parameter), OAuth2's common flows (implicit, password, application and access code) as defined in RFC6749, and OpenID Connect Discovery.
message SecurityScheme {
string type = 1;
string description = 2;
string name = 3;
string in = 4;
string scheme = 5;
string bearer_format = 6;
OauthFlows flows = 7;
string open_id_connect_url = 8;
repeated NamedAny specification_extension = 9;
}
message SecuritySchemeOrReference {
oneof oneof {
SecurityScheme security_scheme = 1;
Reference reference = 2;
}
}
message SecuritySchemesOrReferences {
repeated NamedSecuritySchemeOrReference additional_properties = 1;
}
// An object representing a Server.
message Server {
string url = 1;
string description = 2;
ServerVariables variables = 3;
repeated NamedAny specification_extension = 4;
}
// An object representing a Server Variable for server URL template substitution.
message ServerVariable {
repeated string enum = 1;
string default = 2;
string description = 3;
repeated NamedAny specification_extension = 4;
}
message ServerVariables {
repeated NamedServerVariable additional_properties = 1;
}
// Any property starting with x- is valid.
message SpecificationExtension {
oneof oneof {
double number = 1;
bool boolean = 2;
string string = 3;
}
}
message StringArray {
repeated string value = 1;
}
message Strings {
repeated NamedString additional_properties = 1;
}
// Adds metadata to a single tag that is used by the Operation Object. It is not mandatory to have a Tag Object per tag defined in the Operation Object instances.
message Tag {
string name = 1;
string description = 2;
ExternalDocs external_docs = 3;
repeated NamedAny specification_extension = 4;
}
// A metadata object that allows for more fine-tuned XML model definitions. When using arrays, XML element names are *not* inferred (for singular/plural forms) and the `name` property SHOULD be used to add that information. See examples for expected behavior.
message Xml {
string name = 1;
string namespace = 2;
string prefix = 3;
bool attribute = 4;
bool wrapped = 5;
repeated NamedAny specification_extension = 6;
}

View File

@ -1,25 +0,0 @@
# OpenAPI v3 Protocol Buffer Models
This directory contains a Protocol Buffer-language model
and related code for supporting OpenAPI v3.
Gnostic applications and plugins can use OpenAPIv3.proto
to generate Protocol Buffer support code for their preferred
languages.
OpenAPIv3.go is used by Gnostic to read JSON and YAML OpenAPI
descriptions into the Protocol Buffer-based datastructures
generated from OpenAPIv3.proto.
OpenAPIv3.proto and OpenAPIv3.go are generated by the Gnostic
compiler generator, and OpenAPIv3.pb.go is generated by
protoc, the Protocol Buffer compiler, and protoc-gen-go, the
Protocol Buffer Go code generation plugin.
openapi-3.0.json is a preliminary draft JSON schema for OpenAPI 3.0.
It is not the official OpenAPI 3.0 JSON Schema, which at the time
of this commit, does not exist.
The schema-generator directory contains support code which
generates openapi-3.0.json from a draft of the OpenAPI 3.0
specification document (Markdown).

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
# OpenAPI 3.0 Schema Generator
This directory contains a support tool that reads (scrapes) the
Markdown text specification for OpenAPI 3.0 and builds a
corresponding JSON schema.
It also contains "3.0.1.md", a local copy of the OpenAPI specification.
## Disclaimer
This does not generate the official OpenAPI 3.0 JSON Schema, which
at the time of this commit, does not exist.

View File

@ -1,859 +0,0 @@
// 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.
// schema-generator is a support tool that generates the OpenAPI v3 JSON schema.
// Yes, it's gross, but the OpenAPI 3.0 spec, which defines REST APIs with a
// rigorous JSON schema, is itself defined with a Markdown file. Ironic?
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"regexp"
"sort"
"strings"
"unicode"
"unicode/utf8"
"github.com/googleapis/gnostic/jsonschema"
)
// convert the first character of a string to lower case
func lowerFirst(s string) string {
if s == "" {
return ""
}
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToLower(r)) + s[n:]
}
// Section models a section of the OpenAPI specification text document.
type Section struct {
Level int
Text string
Title string
Children []*Section
}
// ReadSection reads a section of the OpenAPI Specification, recursively dividing it into subsections
func ReadSection(text string, level int) (section *Section) {
titlePattern := regexp.MustCompile("^" + strings.Repeat("#", level) + " .*$")
subtitlePattern := regexp.MustCompile("^" + strings.Repeat("#", level+1) + " .*$")
section = &Section{Level: level, Text: text}
lines := strings.Split(string(text), "\n")
subsection := ""
for i, line := range lines {
if i == 0 && titlePattern.Match([]byte(line)) {
section.Title = line
} else if subtitlePattern.Match([]byte(line)) {
// we've found a subsection title.
// if there's a subsection that we've already been reading, save it
if len(subsection) != 0 {
child := ReadSection(subsection, level+1)
section.Children = append(section.Children, child)
}
// start a new subsection
subsection = line + "\n"
} else {
// add to the subsection we've been reading
subsection += line + "\n"
}
}
// if this section has subsections, save the last one
if len(section.Children) > 0 {
child := ReadSection(subsection, level+1)
section.Children = append(section.Children, child)
}
return
}
// Display recursively displays a section of the specification.
func (s *Section) Display(section string) {
if len(s.Children) == 0 {
//fmt.Printf("%s\n", s.Text)
} else {
for i, child := range s.Children {
var subsection string
if section == "" {
subsection = fmt.Sprintf("%d", i)
} else {
subsection = fmt.Sprintf("%s.%d", section, i)
}
fmt.Printf("%-12s %s\n", subsection, child.NiceTitle())
child.Display(subsection)
}
}
}
// remove a link from a string, leaving only the text that follows it
// if there is no link, just return the string
func stripLink(input string) (output string) {
stringPattern := regexp.MustCompile("^(.*)$")
stringWithLinkPattern := regexp.MustCompile("^<a .*</a>(.*)$")
if matches := stringWithLinkPattern.FindSubmatch([]byte(input)); matches != nil {
return string(matches[1])
} else if matches := stringPattern.FindSubmatch([]byte(input)); matches != nil {
return string(matches[1])
} else {
return input
}
}
// NiceTitle returns a nice-to-display title for a section by removing the opening "###" and any links.
func (s *Section) NiceTitle() string {
titlePattern := regexp.MustCompile("^#+ (.*)$")
titleWithLinkPattern := regexp.MustCompile("^#+ <a .*</a>(.*)$")
if matches := titleWithLinkPattern.FindSubmatch([]byte(s.Title)); matches != nil {
return string(matches[1])
} else if matches := titlePattern.FindSubmatch([]byte(s.Title)); matches != nil {
return string(matches[1])
} else {
return ""
}
}
// replace markdown links with their link text (removing the URL part)
func removeMarkdownLinks(input string) (output string) {
markdownLink := regexp.MustCompile("\\[([^\\]\\[]*)\\]\\(([^\\)]*)\\)") // matches [link title](link url)
output = string(markdownLink.ReplaceAll([]byte(input), []byte("$1")))
return
}
// extract the fixed fields from a table in a section
func parseFixedFields(input string, schemaObject *SchemaObject) {
lines := strings.Split(input, "\n")
for _, line := range lines {
// replace escaped bars with "OR", assuming these are used to describe union types
line = strings.Replace(line, " \\| ", " OR ", -1)
// split the table on the remaining bars
parts := strings.Split(line, "|")
if len(parts) > 1 {
fieldName := strings.Trim(stripLink(parts[0]), " ")
if fieldName != "Field Name" && fieldName != "---" {
if len(parts) == 3 || len(parts) == 4 {
// this is what we expect
} else {
log.Printf("ERROR: %+v", parts)
}
typeName := parts[1]
typeName = strings.Replace(typeName, "{expression}", "Expression", -1)
typeName = strings.Trim(typeName, " ")
typeName = strings.Replace(typeName, "`", "", -1)
typeName = removeMarkdownLinks(typeName)
typeName = strings.Replace(typeName, " ", "", -1)
typeName = strings.Replace(typeName, "Object", "", -1)
isArray := false
if typeName[0] == '[' && typeName[len(typeName)-1] == ']' {
typeName = typeName[1 : len(typeName)-1]
isArray = true
}
isMap := false
mapPattern := regexp.MustCompile("^Mapstring,\\[(.*)\\]$")
if matches := mapPattern.FindSubmatch([]byte(typeName)); matches != nil {
typeName = string(matches[1])
isMap = true
} else {
// match map[string,<typename>]
mapPattern2 := regexp.MustCompile("^Map\\[string,(.+)\\]$")
if matches := mapPattern2.FindSubmatch([]byte(typeName)); matches != nil {
typeName = string(matches[1])
isMap = true
}
}
description := strings.Trim(parts[len(parts)-1], " ")
description = removeMarkdownLinks(description)
description = strings.Replace(description, "\n", " ", -1)
requiredLabel1 := "**Required.** "
requiredLabel2 := "**REQUIRED**."
if strings.Contains(description, requiredLabel1) ||
strings.Contains(description, requiredLabel2) {
// only include required values if their "Validity" is "Any" or if no validity is specified
valid := true
if len(parts) == 4 {
validity := parts[2]
if strings.Contains(validity, "Any") {
valid = true
} else {
valid = false
}
}
if valid {
schemaObject.RequiredFields = append(schemaObject.RequiredFields, fieldName)
}
description = strings.Replace(description, requiredLabel1, "", -1)
description = strings.Replace(description, requiredLabel2, "", -1)
}
schemaField := SchemaObjectField{
Name: fieldName,
Type: typeName,
IsArray: isArray,
IsMap: isMap,
Description: description,
}
schemaObject.FixedFields = append(schemaObject.FixedFields, schemaField)
}
}
}
}
// extract the patterned fields from a table in a section
func parsePatternedFields(input string, schemaObject *SchemaObject) {
lines := strings.Split(input, "\n")
for _, line := range lines {
line = strings.Replace(line, " \\| ", " OR ", -1)
parts := strings.Split(line, "|")
if len(parts) > 1 {
fieldName := strings.Trim(stripLink(parts[0]), " ")
fieldName = removeMarkdownLinks(fieldName)
if fieldName == "HTTP Status Code" {
fieldName = "^([0-9X]{3})$"
}
if fieldName != "Field Pattern" && fieldName != "---" {
typeName := parts[1]
typeName = strings.Trim(typeName, " ")
typeName = strings.Replace(typeName, "`", "", -1)
typeName = removeMarkdownLinks(typeName)
typeName = strings.Replace(typeName, " ", "", -1)
typeName = strings.Replace(typeName, "Object", "", -1)
typeName = strings.Replace(typeName, "{expression}", "Expression", -1)
isArray := false
if typeName[0] == '[' && typeName[len(typeName)-1] == ']' {
typeName = typeName[1 : len(typeName)-1]
isArray = true
}
isMap := false
mapPattern := regexp.MustCompile("^Mapstring,\\[(.*)\\]$")
if matches := mapPattern.FindSubmatch([]byte(typeName)); matches != nil {
typeName = string(matches[1])
isMap = true
}
description := strings.Trim(parts[len(parts)-1], " ")
description = removeMarkdownLinks(description)
description = strings.Replace(description, "\n", " ", -1)
schemaField := SchemaObjectField{
Name: fieldName,
Type: typeName,
IsArray: isArray,
IsMap: isMap,
Description: description,
}
schemaObject.PatternedFields = append(schemaObject.PatternedFields, schemaField)
}
}
}
}
// SchemaObjectField describes a field of a schema.
type SchemaObjectField struct {
Name string `json:"name"`
Type string `json:"type"`
IsArray bool `json:"is_array"`
IsMap bool `json:"is_map"`
Description string `json:"description"`
}
// SchemaObject describes a schema.
type SchemaObject struct {
Name string `json:"name"`
ID string `json:"id"`
Description string `json:"description"`
Extendable bool `json:"extendable"`
RequiredFields []string `json:"required"`
FixedFields []SchemaObjectField `json:"fixed"`
PatternedFields []SchemaObjectField `json:"patterned"`
}
// SchemaModel is a collection of schemas.
type SchemaModel struct {
Objects []SchemaObject
}
func (m *SchemaModel) objectWithID(id string) *SchemaObject {
for _, object := range m.Objects {
if object.ID == id {
return &object
}
}
return nil
}
// NewSchemaModel returns a new SchemaModel.
func NewSchemaModel(filename string) (schemaModel *SchemaModel, err error) {
b, err := ioutil.ReadFile("3.0.1.md")
if err != nil {
return nil, err
}
// divide the specification into sections
document := ReadSection(string(b), 1)
document.Display("")
// read object names and their details
specification := document.Children[4] // fragile! the section title is "Specification"
schema := specification.Children[7] // fragile! the section title is "Schema"
anchor := regexp.MustCompile("^#### <a name=\"(.*)Object\"")
schemaObjects := make([]SchemaObject, 0)
for _, section := range schema.Children {
if matches := anchor.FindSubmatch([]byte(section.Title)); matches != nil {
id := string(matches[1])
schemaObject := SchemaObject{
Name: section.NiceTitle(),
ID: id,
RequiredFields: nil,
}
if len(section.Children) > 0 {
description := section.Children[0].Text
description = removeMarkdownLinks(description)
description = strings.Trim(description, " \t\n")
description = strings.Replace(description, "\n", " ", -1)
schemaObject.Description = description
}
// is the object extendable?
if strings.Contains(section.Text, "Specification Extensions") {
schemaObject.Extendable = true
}
// look for fixed fields
for _, child := range section.Children {
if child.NiceTitle() == "Fixed Fields" {
parseFixedFields(child.Text, &schemaObject)
}
}
// look for patterned fields
for _, child := range section.Children {
if child.NiceTitle() == "Patterned Fields" {
parsePatternedFields(child.Text, &schemaObject)
}
}
schemaObjects = append(schemaObjects, schemaObject)
}
}
return &SchemaModel{Objects: schemaObjects}, nil
}
// UnionType represents a union of two types.
type UnionType struct {
Name string
ObjectType1 string
ObjectType2 string
}
var unionTypes map[string]*UnionType
func noteUnionType(typeName, objectType1, objectType2 string) {
if unionTypes == nil {
unionTypes = make(map[string]*UnionType, 0)
}
unionTypes[typeName] = &UnionType{
Name: typeName,
ObjectType1: objectType1,
ObjectType2: objectType2,
}
}
// MapType represents a map of a specified type (with string keys).
type MapType struct {
Name string
ObjectType string
}
var mapTypes map[string]*MapType
func noteMapType(typeName, objectType string) {
if mapTypes == nil {
mapTypes = make(map[string]*MapType, 0)
}
mapTypes[typeName] = &MapType{
Name: typeName,
ObjectType: objectType,
}
}
func definitionNameForType(typeName string) string {
name := typeName
switch typeName {
case "OAuthFlows":
name = "oauthFlows"
case "OAuthFlow":
name = "oauthFlow"
case "XML":
name = "xml"
case "ExternalDocumentation":
name = "externalDocs"
default:
// does the name contain an "OR"
if parts := strings.Split(typeName, "OR"); len(parts) > 1 {
name = lowerFirst(parts[0]) + "Or" + parts[1]
noteUnionType(name, parts[0], parts[1])
} else {
name = lowerFirst(typeName)
}
}
return "#/definitions/" + name
}
func pluralize(name string) string {
if name == "any" {
return "anys"
}
switch name[len(name)-1] {
case 'y':
name = name[0:len(name)-1] + "ies"
case 's':
name = name + "Map"
default:
name = name + "s"
}
return name
}
func definitionNameForMapOfType(typeName string) string {
// pluralize the type name to get the name of an object representing a map of them
var elementTypeName string
var mapTypeName string
if parts := strings.Split(typeName, "OR"); len(parts) > 1 {
elementTypeName = lowerFirst(parts[0]) + "Or" + parts[1]
noteUnionType(elementTypeName, parts[0], parts[1])
mapTypeName = pluralize(lowerFirst(parts[0])) + "Or" + pluralize(parts[1])
} else {
elementTypeName = lowerFirst(typeName)
mapTypeName = pluralize(elementTypeName)
}
noteMapType(mapTypeName, elementTypeName)
return "#/definitions/" + mapTypeName
}
func updateSchemaFieldWithModelField(schemaField *jsonschema.Schema, modelField *SchemaObjectField) {
// fmt.Printf("IN %s:%+v\n", name, schemaField)
// update the attributes of the schema field
if modelField.IsArray {
// is array
itemSchema := &jsonschema.Schema{}
switch modelField.Type {
case "string":
itemSchema.Type = jsonschema.NewStringOrStringArrayWithString("string")
case "boolean":
itemSchema.Type = jsonschema.NewStringOrStringArrayWithString("boolean")
case "primitive":
itemSchema.Ref = stringptr(definitionNameForType("Primitive"))
default:
itemSchema.Ref = stringptr(definitionNameForType(modelField.Type))
}
schemaField.Items = jsonschema.NewSchemaOrSchemaArrayWithSchema(itemSchema)
schemaField.Type = jsonschema.NewStringOrStringArrayWithString("array")
boolValue := true // not sure about this
schemaField.UniqueItems = &boolValue
} else if modelField.IsMap {
schemaField.Ref = stringptr(definitionNameForMapOfType(modelField.Type))
} else {
// is scalar
switch modelField.Type {
case "string":
schemaField.Type = jsonschema.NewStringOrStringArrayWithString("string")
case "boolean":
schemaField.Type = jsonschema.NewStringOrStringArrayWithString("boolean")
case "primitive":
schemaField.Ref = stringptr(definitionNameForType("Primitive"))
default:
schemaField.Ref = stringptr(definitionNameForType(modelField.Type))
}
}
}
func buildSchemaWithModel(modelObject *SchemaObject) (schema *jsonschema.Schema) {
schema = &jsonschema.Schema{}
schema.Type = jsonschema.NewStringOrStringArrayWithString("object")
if modelObject.RequiredFields != nil && len(modelObject.RequiredFields) > 0 {
// copy array
arrayCopy := modelObject.RequiredFields
schema.Required = &arrayCopy
}
schema.AdditionalProperties = jsonschema.NewSchemaOrBooleanWithBoolean(false)
schema.Description = stringptr(modelObject.Description)
// handle fixed fields
if modelObject.FixedFields != nil {
newNamedSchemas := make([]*jsonschema.NamedSchema, 0)
for _, modelField := range modelObject.FixedFields {
schemaField := schema.PropertyWithName(modelField.Name)
if schemaField == nil {
// create and add the schema field
schemaField = &jsonschema.Schema{}
namedSchema := &jsonschema.NamedSchema{Name: modelField.Name, Value: schemaField}
newNamedSchemas = append(newNamedSchemas, namedSchema)
}
updateSchemaFieldWithModelField(schemaField, &modelField)
}
for _, pair := range newNamedSchemas {
if schema.Properties == nil {
properties := make([]*jsonschema.NamedSchema, 0)
schema.Properties = &properties
}
*(schema.Properties) = append(*(schema.Properties), pair)
}
} else {
if schema.Properties != nil {
fmt.Printf("SCHEMA SHOULD NOT HAVE PROPERTIES %s\n", modelObject.ID)
}
}
// handle patterned fields
if modelObject.PatternedFields != nil {
newNamedSchemas := make([]*jsonschema.NamedSchema, 0)
for _, modelField := range modelObject.PatternedFields {
schemaField := schema.PatternPropertyWithName(modelField.Name)
if schemaField == nil {
// create and add the schema field
schemaField = &jsonschema.Schema{}
// Component names should match "^[a-zA-Z0-9\.\-_]+$"
// See https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.md#componentsObject
nameRegex := "^[a-zA-Z0-9\\\\.\\\\-_]+$"
if modelObject.Name == "Scopes Object" {
nameRegex = "^"
} else if modelObject.Name == "Headers Object" {
nameRegex = "^[a-zA-Z0-9!#\\-\\$%&'\\*\\+\\\\\\.\\^_`\\|~]+"
}
propertyName := strings.Replace(modelField.Name, "{name}", nameRegex, -1)
// The field name MUST begin with a slash, see https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.md#paths-object
// JSON Schema for OpenAPI v2 uses "^/" as regex for paths, see https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/schemas/v2.0/schema.json#L173
propertyName = strings.Replace(propertyName, "/{path}", "^/", -1)
// Replace human-friendly (and regex-confusing) description with a blank pattern
propertyName = strings.Replace(propertyName, "{expression}", "^", -1)
propertyName = strings.Replace(propertyName, "{property}", "^", -1)
namedSchema := &jsonschema.NamedSchema{Name: propertyName, Value: schemaField}
newNamedSchemas = append(newNamedSchemas, namedSchema)
}
updateSchemaFieldWithModelField(schemaField, &modelField)
}
for _, pair := range newNamedSchemas {
if schema.PatternProperties == nil {
properties := make([]*jsonschema.NamedSchema, 0)
schema.PatternProperties = &properties
}
*(schema.PatternProperties) = append(*(schema.PatternProperties), pair)
}
} else {
if schema.PatternProperties != nil && !modelObject.Extendable {
fmt.Printf("SCHEMA SHOULD NOT HAVE PATTERN PROPERTIES %s\n", modelObject.ID)
}
}
if modelObject.Extendable {
schemaField := schema.PatternPropertyWithName("^x-")
if schemaField != nil {
schemaField.Ref = stringptr("#/definitions/specificationExtension")
} else {
schemaField = &jsonschema.Schema{}
schemaField.Ref = stringptr("#/definitions/specificationExtension")
namedSchema := &jsonschema.NamedSchema{Name: "^x-", Value: schemaField}
if schema.PatternProperties == nil {
properties := make([]*jsonschema.NamedSchema, 0)
schema.PatternProperties = &properties
}
*(schema.PatternProperties) = append(*(schema.PatternProperties), namedSchema)
}
} else {
schemaField := schema.PatternPropertyWithName("^x-")
if schemaField != nil {
fmt.Printf("INVALID EXTENSION SUPPORT %s:%s\n", modelObject.ID, "^x-")
}
}
return schema
}
// return a pointer to a copy of a passed-in string
func stringptr(input string) (output *string) {
return &input
}
func int64ptr(input int64) (output *int64) {
return &input
}
func arrayOfSchema() *jsonschema.Schema {
return &jsonschema.Schema{
Type: jsonschema.NewStringOrStringArrayWithString("array"),
MinItems: int64ptr(1),
Items: jsonschema.NewSchemaOrSchemaArrayWithSchema(&jsonschema.Schema{Ref: stringptr("#/definitions/schemaOrReference")}),
}
}
func main() {
// read and parse the text specification into a model structure
model, err := NewSchemaModel("3.0.md")
if err != nil {
panic(err)
}
// write the model as JSON (for debugging)
modelJSON, _ := json.MarshalIndent(model, "", " ")
err = ioutil.WriteFile("model.json", modelJSON, 0644)
if err != nil {
panic(err)
}
// build the top-level schema using the "OAS" model
oasModel := model.objectWithID("oas")
if oasModel == nil {
log.Printf("Unable to find OAS model. Has the source document structure changed?")
os.Exit(-1)
}
schema := buildSchemaWithModel(oasModel)
// manually set a few fields
schema.Title = stringptr("A JSON Schema for OpenAPI 3.0.")
schema.ID = stringptr("http://openapis.org/v3/schema.json#")
schema.Schema = stringptr("http://json-schema.org/draft-04/schema#")
// loop over all models and create the corresponding schema objects
definitions := make([]*jsonschema.NamedSchema, 0)
schema.Definitions = &definitions
for _, modelObject := range model.Objects {
if modelObject.ID == "oas" {
continue
}
definitionSchema := buildSchemaWithModel(&modelObject)
name := modelObject.ID
if name == "externalDocumentation" {
name = "externalDocs"
}
*schema.Definitions = append(*schema.Definitions, jsonschema.NewNamedSchema(name, definitionSchema))
}
// copy the properties of headerObject from parameterObject
headerObject := schema.DefinitionWithName("header")
parameterObject := schema.DefinitionWithName("parameter")
if parameterObject != nil {
newArray := make([]*jsonschema.NamedSchema, 0)
for _, property := range *(parameterObject.Properties) {
// we need to remove a few properties...
if property.Name != "name" && property.Name != "in" {
newArray = append(newArray, property)
}
}
headerObject.Properties = &newArray
// "So a shorthand for copying array arr would be tmp := append([]int{}, arr...)"
ppArray := make([]*jsonschema.NamedSchema, 0)
ppArray = append(ppArray, *(parameterObject.PatternProperties)...)
headerObject.PatternProperties = &ppArray
}
// generate implied union types
unionTypeKeys := make([]string, 0, len(unionTypes))
for key := range unionTypes {
unionTypeKeys = append(unionTypeKeys, key)
}
sort.Strings(unionTypeKeys)
for _, unionTypeKey := range unionTypeKeys {
unionType := unionTypes[unionTypeKey]
objectSchema := schema.DefinitionWithName(unionType.Name)
if objectSchema == nil {
objectSchema = &jsonschema.Schema{}
oneOf := make([]*jsonschema.Schema, 0)
oneOf = append(oneOf, &jsonschema.Schema{Ref: stringptr("#/definitions/" + lowerFirst(unionType.ObjectType1))})
oneOf = append(oneOf, &jsonschema.Schema{Ref: stringptr("#/definitions/" + lowerFirst(unionType.ObjectType2))})
objectSchema.OneOf = &oneOf
*schema.Definitions = append(*schema.Definitions, jsonschema.NewNamedSchema(unionType.Name, objectSchema))
}
}
// generate implied map types
mapTypeKeys := make([]string, 0, len(mapTypes))
for key := range mapTypes {
mapTypeKeys = append(mapTypeKeys, key)
}
sort.Strings(mapTypeKeys)
for _, mapTypeKey := range mapTypeKeys {
mapType := mapTypes[mapTypeKey]
objectSchema := schema.DefinitionWithName(mapType.Name)
if objectSchema == nil {
objectSchema = &jsonschema.Schema{}
objectSchema.Type = jsonschema.NewStringOrStringArrayWithString("object")
additionalPropertiesSchema := &jsonschema.Schema{}
if mapType.ObjectType == "string" {
additionalPropertiesSchema.Type = jsonschema.NewStringOrStringArrayWithString("string")
} else {
additionalPropertiesSchema.Ref = stringptr("#/definitions/" + lowerFirst(mapType.ObjectType))
}
objectSchema.AdditionalProperties = jsonschema.NewSchemaOrBooleanWithSchema(additionalPropertiesSchema)
*schema.Definitions = append(*schema.Definitions, jsonschema.NewNamedSchema(mapType.Name, objectSchema))
}
}
// add schema objects for "object", "any", and "expression"
if true {
objectSchema := &jsonschema.Schema{}
objectSchema.Type = jsonschema.NewStringOrStringArrayWithString("object")
objectSchema.AdditionalProperties = jsonschema.NewSchemaOrBooleanWithBoolean(true)
*schema.Definitions = append(*schema.Definitions, jsonschema.NewNamedSchema("object", objectSchema))
}
if true {
objectSchema := &jsonschema.Schema{}
objectSchema.AdditionalProperties = jsonschema.NewSchemaOrBooleanWithBoolean(true)
*schema.Definitions = append(*schema.Definitions, jsonschema.NewNamedSchema("any", objectSchema))
}
if true {
objectSchema := &jsonschema.Schema{}
objectSchema.Type = jsonschema.NewStringOrStringArrayWithString("object")
objectSchema.AdditionalProperties = jsonschema.NewSchemaOrBooleanWithBoolean(true)
*schema.Definitions = append(*schema.Definitions, jsonschema.NewNamedSchema("expression", objectSchema))
}
// add schema objects for "specificationExtension"
if true {
objectSchema := &jsonschema.Schema{}
objectSchema.Description = stringptr("Any property starting with x- is valid.")
oneOf := make([]*jsonschema.Schema, 0)
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("null")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("number")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("boolean")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("string")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("object")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("array")})
objectSchema.OneOf = &oneOf
*schema.Definitions = append(*schema.Definitions, jsonschema.NewNamedSchema("specificationExtension", objectSchema))
}
// add schema objects for "defaultType"
if true {
objectSchema := &jsonschema.Schema{}
oneOf := make([]*jsonschema.Schema, 0)
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("null")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("array")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("object")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("number")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("boolean")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("string")})
objectSchema.OneOf = &oneOf
*schema.Definitions = append(*schema.Definitions, jsonschema.NewNamedSchema("defaultType", objectSchema))
}
// add schema objects for "primitive"
if false { // we don't seem to need these for 3.0 RC2
objectSchema := &jsonschema.Schema{}
oneOf := make([]*jsonschema.Schema, 0)
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("number")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("boolean")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("string")})
objectSchema.OneOf = &oneOf
*schema.Definitions = append(*schema.Definitions, jsonschema.NewNamedSchema("primitive", objectSchema))
}
// force a few more things into the "schema" schema
schemaObject := schema.DefinitionWithName("schema")
schemaObject.CopyOfficialSchemaProperties(
[]string{
"title",
"multipleOf",
"maximum",
"exclusiveMaximum",
"minimum",
"exclusiveMinimum",
"maxLength",
"minLength",
"pattern",
"maxItems",
"minItems",
"uniqueItems",
"maxProperties",
"minProperties",
"required",
"enum",
})
schemaObject.AdditionalProperties = jsonschema.NewSchemaOrBooleanWithBoolean(false)
schemaObject.AddProperty("type", &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("string")})
schemaObject.AddProperty("allOf", arrayOfSchema())
schemaObject.AddProperty("oneOf", arrayOfSchema())
schemaObject.AddProperty("anyOf", arrayOfSchema())
schemaObject.AddProperty("not", &jsonschema.Schema{Ref: stringptr("#/definitions/schema")})
anyOf := make([]*jsonschema.Schema, 0)
anyOf = append(anyOf, &jsonschema.Schema{Ref: stringptr("#/definitions/schemaOrReference")})
anyOf = append(anyOf, arrayOfSchema())
schemaObject.AddProperty("items",
&jsonschema.Schema{AnyOf: &anyOf})
schemaObject.AddProperty("properties", &jsonschema.Schema{
Type: jsonschema.NewStringOrStringArrayWithString("object"),
AdditionalProperties: jsonschema.NewSchemaOrBooleanWithSchema(
&jsonschema.Schema{Ref: stringptr("#/definitions/schemaOrReference")})})
if true { // add additionalProperties schema object
oneOf := make([]*jsonschema.Schema, 0)
oneOf = append(oneOf, &jsonschema.Schema{Ref: stringptr("#/definitions/schemaOrReference")})
oneOf = append(oneOf, &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("boolean")})
schemaObject.AddProperty("additionalProperties", &jsonschema.Schema{OneOf: &oneOf})
}
schemaObject.AddProperty("default", &jsonschema.Schema{Ref: stringptr("#/definitions/defaultType")})
schemaObject.AddProperty("description", &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("string")})
schemaObject.AddProperty("format", &jsonschema.Schema{Type: jsonschema.NewStringOrStringArrayWithString("string")})
// fix the content object
contentObject := schema.DefinitionWithName("content")
if contentObject != nil {
pairs := make([]*jsonschema.NamedSchema, 0)
contentObject.PatternProperties = &pairs
namedSchema := &jsonschema.NamedSchema{Name: "^", Value: &jsonschema.Schema{Ref: stringptr("#/definitions/mediaType")}}
*(contentObject.PatternProperties) = append(*(contentObject.PatternProperties), namedSchema)
}
// fix the contact object
contactObject := schema.DefinitionWithName("contact")
if contactObject != nil {
emailProperty := contactObject.PropertyWithName("email")
if emailProperty != nil {
emailProperty.Format = stringptr("email");
}
urlProperty := contactObject.PropertyWithName("url")
if urlProperty != nil {
urlProperty.Format = stringptr("uri");
}
}
// write the updated schema
output := schema.JSONString()
err = ioutil.WriteFile("schema.json", []byte(output), 0644)
if err != nil {
panic(err)
}
}

View File

@ -1,109 +0,0 @@
[![Build Status](https://travis-ci.org/googleapis/gnostic.svg?branch=master)](https://travis-ci.org/googleapis/gnostic)
# ⨁ gnostic
This repository contains a Go command line tool which converts
JSON and YAML [OpenAPI](https://github.com/OAI/OpenAPI-Specification)
descriptions to and from equivalent Protocol Buffer representations.
[Protocol Buffers](https://developers.google.com/protocol-buffers/)
provide a language-neutral, platform-neutral, extensible mechanism
for serializing structured data.
**gnostic**'s Protocol Buffer models for the OpenAPI Specification
can be used to generate code that includes data structures with
explicit fields for the elements of an OpenAPI description.
This makes it possible for developers to work with OpenAPI
descriptions in type-safe ways, which is particularly useful
in strongly-typed languages like Go and Swift.
**gnostic** reads OpenAPI descriptions into
these generated data structures, reports errors,
resolves internal dependencies, and writes the results
in a binary form that can be used in any language that is
supported by the Protocol Buffer tools.
A plugin interface simplifies integration with API
tools written in a variety of different languages,
and when necessary, Protocol Buffer OpenAPI descriptions
can be reexported as JSON or YAML.
**gnostic** compilation code and OpenAPI Protocol Buffer
models are automatically generated from an
[OpenAPI JSON Schema](https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json).
Source code for the generator is in the [generate-gnostic](generate-gnostic) directory.
## Disclaimer
This is prerelease software and work in progress. Feedback and
contributions are welcome, but we currently make no guarantees of
function or stability.
## Requirements
**gnostic** can be run in any environment that supports [Go](http://golang.org)
and the [Google Protocol Buffer Compiler](https://github.com/google/protobuf).
## Installation
1. Get this package by downloading it with `go get`.
go get github.com/googleapis/gnostic
2. [Optional] Build and run the compiler generator.
This uses the OpenAPI JSON schema to generate a Protocol Buffer language file
that describes the OpenAPI specification and a Go-language file of code that
will read a JSON or YAML OpenAPI representation into the generated protocol
buffers. Pre-generated versions of these files are in the OpenAPIv2 directory.
cd $GOPATH/src/github.com/googleapis/gnostic/generate-gnostic
go install
cd ..
generate-gnostic --v2
3. [Optional] Generate Protocol Buffer support code.
A pre-generated version of this file is checked into the OpenAPIv2 directory.
This step requires a local installation of protoc, the Protocol Buffer Compiler,
and the Go protoc plugin.
You can get protoc [here](https://github.com/google/protobuf).
You can install the plugin with this command:
go get -u github.com/golang/protobuf/protoc-gen-go
Then use the following to recompile the Gnostic Protocol Buffer models:
./COMPILE-PROTOS.sh
4. [Optional] Rebuild **gnostic**. This is only necessary if you've performed steps
2 or 3 above.
go install github.com/googleapis/gnostic
5. Run **gnostic**. This will create a file in the current directory named "petstore.pb" that contains a binary
Protocol Buffer description of a sample API.
gnostic --pb-out=. examples/v2.0/json/petstore.json
6. You can also compile files that you specify with a URL. Here's another way to compile the previous
example. This time we're creating "petstore.text", which contains a textual representation of the
Protocol Buffer description. This is mainly for use in testing and debugging.
gnostic --text-out=petstore.text https://raw.githubusercontent.com/googleapis/gnostic/master/examples/petstore.json
7. For a sample application, see apps/report.
go install github.com/googleapis/gnostic/apps/report
report petstore.pb
8. **gnostic** supports plugins. This builds and runs a sample plugin
that reports some basic information about an API. The "-" causes the plugin to
write its output to stdout.
go install github.com/googleapis/gnostic/plugins/gnostic-go-sample
gnostic examples/v2.0/json/petstore.json --go-sample-out=-
## Copyright
Copyright 2017, Google Inc.
## License
Released under the Apache 2.0 license.

View File

@ -1,38 +0,0 @@
# 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

@ -1,79 +0,0 @@
// 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
}
}

View File

@ -1,255 +0,0 @@
// 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

@ -1,287 +0,0 @@
// 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

@ -1,303 +0,0 @@
// 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
}

View File

@ -1,5 +0,0 @@
# OpenAPI Builder Sample
This directory contains a simple sample application that builds
and exports an OpenAPI 2.0 description of a sample API.

View File

@ -1,82 +0,0 @@
// 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 (
"fmt"
"io/ioutil"
"os"
"path"
"github.com/golang/protobuf/proto"
)
func usage() string {
return fmt.Sprintf(`
Usage: %s [OPTIONS]
Options:
--v2
Generate an OpenAPI v2 description.
--v3
Generate an OpenAPI v3 description.
`, path.Base(os.Args[0]))
}
func main() {
openAPIv2 := false
openAPIv3 := false
for i, arg := range os.Args {
if i == 0 {
continue // skip the tool name
}
if arg == "--v2" {
openAPIv2 = true
} else if arg == "--v3" {
openAPIv3 = true
} else {
fmt.Printf("Unknown option: %s.\n%s\n", arg, usage())
os.Exit(-1)
}
}
if !openAPIv2 && !openAPIv3 {
openAPIv2 = true
}
if openAPIv2 {
document := buildDocumentV2()
bytes, err := proto.Marshal(document)
if err != nil {
panic(err)
}
err = ioutil.WriteFile("petstore-v2.pb", bytes, 0644)
if err != nil {
panic(err)
}
}
if openAPIv3 {
document := buildDocumentV3()
bytes, err := proto.Marshal(document)
if err != nil {
panic(err)
}
err = ioutil.WriteFile("petstore-v3.pb", bytes, 0644)
if err != nil {
panic(err)
}
}
}

View File

@ -1,260 +0,0 @@
// 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 (
v2 "github.com/googleapis/gnostic/OpenAPIv2"
)
func buildDocumentV2() *v2.Document {
d := &v2.Document{}
d.Swagger = "2.0"
d.Info = &v2.Info{
Title: "Swagger Petstore",
Version: "1.0.0",
License: &v2.License{Name: "MIT"},
}
d.Host = "petstore.swagger.io"
d.BasePath = "/v1"
d.Schemes = []string{"http"}
d.Consumes = []string{"application/json"}
d.Produces = []string{"application/json"}
d.Paths = &v2.Paths{}
d.Paths.Path = append(d.Paths.Path,
&v2.NamedPathItem{
Name: "/pets",
Value: &v2.PathItem{
Get: &v2.Operation{
Summary: "List all pets",
OperationId: "listPets",
Tags: []string{"pets"},
Parameters: []*v2.ParametersItem{
&v2.ParametersItem{
Oneof: &v2.ParametersItem_Parameter{
Parameter: &v2.Parameter{
Oneof: &v2.Parameter_NonBodyParameter{
NonBodyParameter: &v2.NonBodyParameter{
Oneof: &v2.NonBodyParameter_QueryParameterSubSchema{
QueryParameterSubSchema: &v2.QueryParameterSubSchema{
Name: "limit",
In: "query",
Description: "How many items to return at one time (max 100)",
Required: false,
Type: "integer",
Format: "int32",
},
},
},
},
},
},
},
},
Responses: &v2.Responses{
ResponseCode: []*v2.NamedResponseValue{
&v2.NamedResponseValue{
Name: "200",
Value: &v2.ResponseValue{
Oneof: &v2.ResponseValue_Response{
Response: &v2.Response{
Description: "An paged array of pets", // [sic] match other examples
Schema: &v2.SchemaItem{
Oneof: &v2.SchemaItem_Schema{
Schema: &v2.Schema{
XRef: "#/definitions/Pets",
},
},
},
Headers: &v2.Headers{
AdditionalProperties: []*v2.NamedHeader{
&v2.NamedHeader{
Name: "x-next",
Value: &v2.Header{
Type: "string",
Description: "A link to the next page of responses",
},
},
},
},
},
},
},
},
&v2.NamedResponseValue{
Name: "default",
Value: &v2.ResponseValue{
Oneof: &v2.ResponseValue_Response{
Response: &v2.Response{
Description: "unexpected error",
Schema: &v2.SchemaItem{
Oneof: &v2.SchemaItem_Schema{
Schema: &v2.Schema{
XRef: "#/definitions/Error",
},
},
},
},
},
},
},
},
},
},
Post: &v2.Operation{
Summary: "Create a pet",
OperationId: "createPets",
Tags: []string{"pets"},
Parameters: []*v2.ParametersItem{},
Responses: &v2.Responses{
ResponseCode: []*v2.NamedResponseValue{
&v2.NamedResponseValue{
Name: "201",
Value: &v2.ResponseValue{
Oneof: &v2.ResponseValue_Response{
Response: &v2.Response{
Description: "Null response",
},
},
},
},
&v2.NamedResponseValue{
Name: "default",
Value: &v2.ResponseValue{
Oneof: &v2.ResponseValue_Response{
Response: &v2.Response{
Description: "unexpected error",
Schema: &v2.SchemaItem{
Oneof: &v2.SchemaItem_Schema{
Schema: &v2.Schema{
XRef: "#/definitions/Error",
},
},
},
},
},
},
},
},
},
},
}})
d.Paths.Path = append(d.Paths.Path,
&v2.NamedPathItem{
Name: "/pets/{petId}",
Value: &v2.PathItem{
Get: &v2.Operation{
Summary: "Info for a specific pet",
OperationId: "showPetById",
Tags: []string{"pets"},
Parameters: []*v2.ParametersItem{
&v2.ParametersItem{
Oneof: &v2.ParametersItem_Parameter{
Parameter: &v2.Parameter{
Oneof: &v2.Parameter_NonBodyParameter{
NonBodyParameter: &v2.NonBodyParameter{
Oneof: &v2.NonBodyParameter_PathParameterSubSchema{
PathParameterSubSchema: &v2.PathParameterSubSchema{
Name: "petId",
In: "path",
Description: "The id of the pet to retrieve",
Required: true,
Type: "string",
},
},
},
},
},
},
},
},
Responses: &v2.Responses{
ResponseCode: []*v2.NamedResponseValue{
&v2.NamedResponseValue{
Name: "200",
Value: &v2.ResponseValue{
Oneof: &v2.ResponseValue_Response{
Response: &v2.Response{
Description: "Expected response to a valid request",
Schema: &v2.SchemaItem{
Oneof: &v2.SchemaItem_Schema{
Schema: &v2.Schema{
XRef: "#/definitions/Pets",
},
},
},
},
},
},
},
&v2.NamedResponseValue{
Name: "default",
Value: &v2.ResponseValue{
Oneof: &v2.ResponseValue_Response{
Response: &v2.Response{
Description: "unexpected error",
Schema: &v2.SchemaItem{
Oneof: &v2.SchemaItem_Schema{
Schema: &v2.Schema{
XRef: "#/definitions/Error",
},
},
},
},
},
},
},
},
},
},
}})
d.Definitions = &v2.Definitions{}
d.Definitions.AdditionalProperties = append(d.Definitions.AdditionalProperties,
&v2.NamedSchema{
Name: "Pet",
Value: &v2.Schema{
Required: []string{"id", "name"},
Properties: &v2.Properties{
AdditionalProperties: []*v2.NamedSchema{
&v2.NamedSchema{Name: "id", Value: &v2.Schema{
Type: &v2.TypeItem{[]string{"integer"}},
Format: "int64"}},
&v2.NamedSchema{Name: "name", Value: &v2.Schema{Type: &v2.TypeItem{[]string{"string"}}}},
&v2.NamedSchema{Name: "tag", Value: &v2.Schema{Type: &v2.TypeItem{[]string{"string"}}}},
},
},
}})
d.Definitions.AdditionalProperties = append(d.Definitions.AdditionalProperties,
&v2.NamedSchema{
Name: "Pets",
Value: &v2.Schema{
Type: &v2.TypeItem{[]string{"array"}},
Items: &v2.ItemsItem{[]*v2.Schema{&v2.Schema{XRef: "#/definitions/Pet"}}},
}})
d.Definitions.AdditionalProperties = append(d.Definitions.AdditionalProperties,
&v2.NamedSchema{
Name: "Error",
Value: &v2.Schema{
Required: []string{"code", "message"},
Properties: &v2.Properties{
AdditionalProperties: []*v2.NamedSchema{
&v2.NamedSchema{Name: "code", Value: &v2.Schema{
Type: &v2.TypeItem{[]string{"integer"}},
Format: "int32"}},
&v2.NamedSchema{Name: "message", Value: &v2.Schema{Type: &v2.TypeItem{[]string{"string"}}}},
},
},
}})
return d
}

View File

@ -1,369 +0,0 @@
// 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 (
v3 "github.com/googleapis/gnostic/OpenAPIv3"
)
func buildDocumentV3() *v3.Document {
d := &v3.Document{}
d.Openapi = "3.0"
d.Info = &v3.Info{
Title: "OpenAPI Petstore",
Version: "1.0.0",
License: &v3.License{Name: "MIT"},
}
d.Servers = append(d.Servers, &v3.Server{
Url: "https://petstore.openapis.org/v1",
Description: "Development server",
})
d.Paths = &v3.Paths{}
d.Paths.Path = append(d.Paths.Path,
&v3.NamedPathItem{
Name: "/pets",
Value: &v3.PathItem{
Get: &v3.Operation{
Summary: "List all pets",
OperationId: "listPets",
Tags: []string{"pets"},
Parameters: []*v3.ParameterOrReference{
&v3.ParameterOrReference{
Oneof: &v3.ParameterOrReference_Parameter{
Parameter: &v3.Parameter{
Name: "limit",
In: "query",
Description: "How many items to return at one time (max 100)",
Required: false,
Schema: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Schema{
Schema: &v3.Schema{
Type: "integer",
Format: "int32",
},
},
},
},
},
},
},
Responses: &v3.Responses{
Default: &v3.ResponseOrReference{
Oneof: &v3.ResponseOrReference_Response{
Response: &v3.Response{
Description: "unexpected error",
Content: &v3.MediaTypes{
AdditionalProperties: []*v3.NamedMediaType{
&v3.NamedMediaType{
Name: "application/json",
Value: &v3.MediaType{
Schema: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Reference{
Reference: &v3.Reference{
XRef: "#/components/schemas/Error",
},
},
},
},
},
},
},
},
},
},
ResponseOrReference: []*v3.NamedResponseOrReference{
&v3.NamedResponseOrReference{
Name: "200",
Value: &v3.ResponseOrReference{
Oneof: &v3.ResponseOrReference_Response{
Response: &v3.Response{
Description: "An paged array of pets", // [sic] match other examples
Content: &v3.MediaTypes{
AdditionalProperties: []*v3.NamedMediaType{
&v3.NamedMediaType{
Name: "application/json",
Value: &v3.MediaType{
Schema: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Reference{
Reference: &v3.Reference{
XRef: "#/components/schemas/Pets",
},
},
},
},
},
},
},
Headers: &v3.HeadersOrReferences{
AdditionalProperties: []*v3.NamedHeaderOrReference{
&v3.NamedHeaderOrReference{
Name: "x-next",
Value: &v3.HeaderOrReference{
Oneof: &v3.HeaderOrReference_Header{
Header: &v3.Header{
Description: "A link to the next page of responses",
Schema: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Schema{
Schema: &v3.Schema{
Type: "string",
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
},
Post: &v3.Operation{
Summary: "Create a pet",
OperationId: "createPets",
Tags: []string{"pets"},
Responses: &v3.Responses{
Default: &v3.ResponseOrReference{
Oneof: &v3.ResponseOrReference_Response{
Response: &v3.Response{
Description: "unexpected error",
Content: &v3.MediaTypes{
AdditionalProperties: []*v3.NamedMediaType{
&v3.NamedMediaType{
Name: "application/json",
Value: &v3.MediaType{
Schema: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Reference{
Reference: &v3.Reference{
XRef: "#/components/schemas/Error",
},
},
},
},
},
},
},
},
},
},
ResponseOrReference: []*v3.NamedResponseOrReference{
&v3.NamedResponseOrReference{
Name: "201",
Value: &v3.ResponseOrReference{
Oneof: &v3.ResponseOrReference_Response{
Response: &v3.Response{
Description: "Null response",
},
},
},
},
},
},
},
}},
&v3.NamedPathItem{
Name: "/pets/{petId}",
Value: &v3.PathItem{
Get: &v3.Operation{
Summary: "Info for a specific pet",
OperationId: "showPetById",
Tags: []string{"pets"},
Parameters: []*v3.ParameterOrReference{
&v3.ParameterOrReference{
Oneof: &v3.ParameterOrReference_Parameter{
Parameter: &v3.Parameter{
Name: "petId",
In: "path",
Description: "The id of the pet to retrieve",
Required: true,
Schema: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Schema{
Schema: &v3.Schema{
Type: "string",
},
},
},
},
},
},
},
Responses: &v3.Responses{
Default: &v3.ResponseOrReference{
Oneof: &v3.ResponseOrReference_Response{
Response: &v3.Response{
Description: "unexpected error",
Content: &v3.MediaTypes{
AdditionalProperties: []*v3.NamedMediaType{
&v3.NamedMediaType{
Name: "application/json",
Value: &v3.MediaType{
Schema: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Reference{
Reference: &v3.Reference{
XRef: "#/components/schemas/Error",
},
},
},
},
},
},
},
},
},
},
ResponseOrReference: []*v3.NamedResponseOrReference{
&v3.NamedResponseOrReference{
Name: "200",
Value: &v3.ResponseOrReference{
Oneof: &v3.ResponseOrReference_Response{
Response: &v3.Response{
Description: "Expected response to a valid request",
Content: &v3.MediaTypes{
AdditionalProperties: []*v3.NamedMediaType{
&v3.NamedMediaType{
Name: "application/json",
Value: &v3.MediaType{
Schema: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Reference{
Reference: &v3.Reference{
XRef: "#/components/schemas/Pets",
},
},
},
},
},
},
},
},
},
},
},
},
},
},
}})
d.Components = &v3.Components{
Schemas: &v3.SchemasOrReferences{
AdditionalProperties: []*v3.NamedSchemaOrReference{
&v3.NamedSchemaOrReference{
Name: "Pet",
Value: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Schema{
Schema: &v3.Schema{
Required: []string{"id", "name"},
Properties: &v3.Properties{
AdditionalProperties: []*v3.NamedSchemaOrReference{
&v3.NamedSchemaOrReference{
Name: "id",
Value: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Schema{
Schema: &v3.Schema{
Type: "integer",
Format: "int64",
},
},
},
},
&v3.NamedSchemaOrReference{
Name: "name",
Value: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Schema{
Schema: &v3.Schema{
Type: "string",
},
},
},
},
&v3.NamedSchemaOrReference{
Name: "tag",
Value: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Schema{
Schema: &v3.Schema{
Type: "string",
},
},
},
},
},
},
},
},
},
},
&v3.NamedSchemaOrReference{
Name: "Pets",
Value: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Schema{
Schema: &v3.Schema{
Type: "array",
Items: &v3.ItemsItem{
SchemaOrReference: []*v3.SchemaOrReference{
&v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Reference{
Reference: &v3.Reference{
XRef: "#/components/schemas/Pet",
},
},
},
},
},
},
},
},
},
&v3.NamedSchemaOrReference{
Name: "Error",
Value: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Schema{
Schema: &v3.Schema{
Required: []string{"code", "message"},
Properties: &v3.Properties{
AdditionalProperties: []*v3.NamedSchemaOrReference{
&v3.NamedSchemaOrReference{
Name: "code",
Value: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Schema{
Schema: &v3.Schema{
Type: "integer",
Format: "int32",
},
},
},
},
&v3.NamedSchemaOrReference{
Name: "message",
Value: &v3.SchemaOrReference{
Oneof: &v3.SchemaOrReference_Schema{
Schema: &v3.Schema{
Type: "string",
},
},
},
},
},
},
},
},
},
},
},
},
}
return d
}

View File

@ -1,5 +0,0 @@
# report-messages tool
This directory contains a command-line tool that provides a text
report listing the messages in a gnostic messages file.

View File

@ -1,69 +0,0 @@
// Copyright 2018 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.
// Filter and display messages produced by gnostic invocations.
package main
import (
"flag"
"fmt"
"io/ioutil"
"os"
"github.com/golang/protobuf/proto"
"github.com/googleapis/gnostic/printer"
plugins "github.com/googleapis/gnostic/plugins"
)
func readMessagesFromFileWithName(filename string) *plugins.Messages {
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Printf("File error: %v\n", err)
os.Exit(1)
}
messages := &plugins.Messages{}
err = proto.Unmarshal(data, messages)
if err != nil {
panic(err)
}
return messages
}
func printMessages(code *printer.Code, messages *plugins.Messages) {
for _, message := range messages.Messages {
line := fmt.Sprintf("%-7s %-14s %s %+v",
message.Level,
message.Code,
message.Text,
message.Keys)
code.Print(line)
}
}
func main() {
flag.Parse()
args := flag.Args()
if len(args) != 1 {
fmt.Printf("Usage: report-messages <file.pb>\n")
return
}
messages := readMessagesFromFileWithName(args[0])
code := &printer.Code{}
printMessages(code, messages)
fmt.Printf("%s", code)
}

View File

@ -1,6 +0,0 @@
# OpenAPI Report Sample
This directory contains a simple sample application that reads a binary
protocol buffer representation of an OpenAPI 2.0 specification that
was generated by gnostic.

View File

@ -1,239 +0,0 @@
// 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.
// report is a demo application that displays information about an
// OpenAPI description.
package main
import (
"flag"
"fmt"
"io/ioutil"
"os"
"github.com/golang/protobuf/proto"
"github.com/googleapis/gnostic/printer"
pb "github.com/googleapis/gnostic/OpenAPIv2"
)
func readDocumentFromFileWithName(filename string) *pb.Document {
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Printf("File error: %v\n", err)
os.Exit(1)
}
document := &pb.Document{}
err = proto.Unmarshal(data, document)
if err != nil {
panic(err)
}
return document
}
func printDocument(code *printer.Code, document *pb.Document) {
code.Print("BasePath: %+v", document.BasePath)
code.Print("Consumes: %+v", document.Consumes)
code.Print("Definitions:")
code.Indent()
if document.Definitions != nil && document.Definitions.AdditionalProperties != nil {
for _, pair := range document.Definitions.AdditionalProperties {
code.Print("%s", pair.Name)
code.Indent()
printSchema(code, pair.Value)
code.Outdent()
}
}
code.Outdent()
code.Print("ExternalDocs: %+v", document.ExternalDocs)
code.Print("Host: %+v", document.Host)
if document.Info != nil {
code.Print("Info:")
code.Indent()
code.Print("Title: %s", document.Info.Title)
code.Print("Description: %s", document.Info.Description)
code.Print("Version: %s", document.Info.Version)
code.Print("TermsOfService: %s", document.Info.TermsOfService)
if document.Info.Contact != nil {
code.Print("Contact Email: %s", document.Info.Contact.Email)
}
if document.Info.License != nil {
code.Print("License Name: %s", document.Info.License.Name)
code.Print("License URL: %s", document.Info.License.Url)
}
code.Outdent()
}
code.Print("Parameters: %+v", document.Parameters)
code.Print("Paths:")
code.Indent()
for _, pair := range document.Paths.Path {
code.Print("%+v", pair.Name)
code.Indent()
v := pair.Value
if v.Get != nil {
code.Print("GET")
code.Indent()
printOperation(code, v.Get)
code.Outdent()
}
if v.Post != nil {
code.Print("POST")
code.Indent()
printOperation(code, v.Post)
code.Outdent()
}
code.Outdent()
}
code.Outdent()
code.Print("Produces: %+v", document.Produces)
code.Print("Responses: %+v", document.Responses)
code.Print("Schemes: %+v", document.Schemes)
code.Print("Security: %+v", document.Security)
if document.SecurityDefinitions != nil {
code.Print("SecurityDefinitions:")
code.Indent()
for _, pair := range document.SecurityDefinitions.AdditionalProperties {
code.Print("%s", pair.Name)
code.Indent()
v := pair.Value
switch t := v.Oneof.(type) {
default:
code.Print("unexpected type %T", t) // %T prints whatever type t has
case *pb.SecurityDefinitionsItem_ApiKeySecurity:
code.Print("ApiKeySecurity: %+v", t)
case *pb.SecurityDefinitionsItem_BasicAuthenticationSecurity:
code.Print("BasicAuthenticationSecurity: %+v", t)
case *pb.SecurityDefinitionsItem_Oauth2AccessCodeSecurity:
code.Print("Oauth2AccessCodeSecurity: %+v", t)
case *pb.SecurityDefinitionsItem_Oauth2ApplicationSecurity:
code.Print("Oauth2ApplicationSecurity: %+v", t)
case *pb.SecurityDefinitionsItem_Oauth2ImplicitSecurity:
code.Print("Oauth2ImplicitSecurity")
code.Indent()
code.Print("AuthorizationUrl: %+v", t.Oauth2ImplicitSecurity.AuthorizationUrl)
code.Print("Flow: %+v", t.Oauth2ImplicitSecurity.Flow)
code.Print("Scopes:")
code.Indent()
for _, pair := range t.Oauth2ImplicitSecurity.Scopes.AdditionalProperties {
code.Print("%s -> %s", pair.Name, pair.Value)
}
code.Outdent()
code.Outdent()
case *pb.SecurityDefinitionsItem_Oauth2PasswordSecurity:
code.Print("Oauth2PasswordSecurity: %+v", t)
}
code.Outdent()
}
code.Outdent()
}
code.Print("Swagger: %+v", document.Swagger)
code.Print("Tags:")
code.Indent()
for _, tag := range document.Tags {
code.Print("Tag:")
code.Indent()
code.Print("Name: %s", tag.Name)
code.Print("Description: %s", tag.Description)
code.Print("ExternalDocs: %s", tag.ExternalDocs)
printVendorExtension(code, tag.VendorExtension)
code.Outdent()
}
code.Outdent()
}
func printOperation(code *printer.Code, operation *pb.Operation) {
code.Print("Consumes: %+v", operation.Consumes)
code.Print("Deprecated: %+v", operation.Deprecated)
code.Print("Description: %+v", operation.Description)
code.Print("ExternalDocs: %+v", operation.ExternalDocs)
code.Print("OperationId: %+v", operation.OperationId)
code.Print("Parameters:")
code.Indent()
for _, item := range operation.Parameters {
switch t := item.Oneof.(type) {
default:
code.Print("unexpected type %T", t) // %T prints whatever type t has
case *pb.ParametersItem_JsonReference:
code.Print("JsonReference: %+v", t)
case *pb.ParametersItem_Parameter:
code.Print("Parameter: %+v", t)
}
}
code.Outdent()
code.Print("Produces: %+v", operation.Produces)
code.Print("Responses:")
code.Indent()
code.Print("ResponseCode:")
code.Indent()
for _, pair := range operation.Responses.ResponseCode {
code.Print("%s %s", pair.Name, pair.Value)
}
code.Outdent()
printVendorExtension(code, operation.Responses.VendorExtension)
code.Outdent()
code.Print("Schemes: %+v", operation.Schemes)
code.Print("Security: %+v", operation.Security)
code.Print("Summary: %+v", operation.Summary)
code.Print("Tags: %+v", operation.Tags)
printVendorExtension(code, operation.VendorExtension)
}
func printSchema(code *printer.Code, schema *pb.Schema) {
//code.Print("%+v", schema)
if schema.Format != "" {
code.Print("Format: %+v", schema.Format)
}
if schema.Properties != nil {
code.Print("Properties")
code.Indent()
for _, pair := range schema.Properties.AdditionalProperties {
code.Print("%s", pair.Name)
code.Indent()
printSchema(code, pair.Value)
code.Outdent()
}
code.Outdent()
}
if schema.Type != nil {
code.Print("Type: %+v", schema.Type)
}
if schema.Xml != nil {
code.Print("Xml: %+v", schema.Xml)
}
printVendorExtension(code, schema.VendorExtension)
}
func printVendorExtension(code *printer.Code, vendorExtension []*pb.NamedAny) {
if len(vendorExtension) > 0 {
code.Print("VendorExtension: %+v", vendorExtension)
}
}
func main() {
flag.Parse()
args := flag.Args()
if len(args) != 1 {
fmt.Printf("Usage: report <file.pb>\n")
return
}
document := readDocumentFromFileWithName(args[0])
code := &printer.Code{}
code.Print("API REPORT")
code.Print("----------")
printDocument(code, document)
fmt.Printf("%s", code)
}

View File

@ -1,3 +0,0 @@
# Compiler support code
This directory contains compiler support code used by Gnostic and Gnostic extensions.

View File

@ -1,16 +0,0 @@
# API Discovery Format
This directory contains a Protocol Buffer-language model
and related code for supporting Google's API Discovery Format.
Gnostic applications and plugins can use Discovery.proto
to generate Protocol Buffer support code for their preferred languages.
Discovery.go is used by Gnostic to read JSON and YAML Discovery
descriptions into the Protocol Buffer-based datastructures
generated from Discovery.proto.
Discovery.proto and Discovery.go are generated by the Gnostic
compiler generator, and Discovery.pb.go is generated by
protoc, the Protocol Buffer compiler, and protoc-gen-go, the
Protocol Buffer Go code generation plugin.

File diff suppressed because it is too large Load Diff

View File

@ -1,451 +0,0 @@
{
"title": "A JSON Schema for the Google API Discovery Format.",
"id": "http://openapis.org/v3/schema.json#",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"description": "This is the root document object of the Discovery Format.",
"required": [
"kind",
"discoveryVersion"
],
"additionalProperties": false,
"properties": {
"kind": {
"type": "string"
},
"discoveryVersion": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"version": {
"type": "string"
},
"revision": {
"type": "string"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"icons": {
"$ref": "#/definitions/icons"
},
"documentationLink": {
"type": "string"
},
"labels": {
"type": "array",
"items": {
"type": "string"
}
},
"protocol": {
"type": "string"
},
"baseUrl": {
"type": "string"
},
"basePath": {
"type": "string"
},
"rootUrl": {
"type": "string"
},
"servicePath": {
"type": "string"
},
"batchPath": {
"type": "string"
},
"parameters": {
"$ref": "#/definitions/parameters"
},
"auth": {
"$ref": "#/definitions/auth"
},
"features": {
"type": "array",
"items": {
"type": "string"
}
},
"schemas": {
"$ref": "#/definitions/schemas"
},
"methods": {
"$ref": "#/definitions/methods"
},
"resources": {
"$ref": "#/definitions/resources"
},
"etag": {
"type": "string"
},
"ownerDomain": {
"type": "string"
},
"ownerName": {
"type": "string"
},
"version_module": {
"type": "boolean"
},
"canonicalName": {
"type": "string"
},
"fullyEncodeReservedExpansion": {
"type": "boolean"
},
"packagePath": {
"type": "string"
}
},
"definitions": {
"icons": {
"type": "object",
"description": "Icons that represent the API.",
"required": [
"x16",
"x32"
],
"additionalProperties": false,
"properties": {
"x16": {
"type": "string"
},
"x32": {
"type": "string"
}
}
},
"parameters": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/parameter"
}
},
"parameter": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
},
"$ref": {
"type": "string"
},
"description": {
"type": "string"
},
"default": {
"type": "string"
},
"required": {
"type": "boolean"
},
"format": {
"type": "string"
},
"pattern": {
"type": "string"
},
"minimum": {
"type": "string"
},
"maximum": {
"type": "string"
},
"enum": {
"type": "array",
"items": {
"type": "string"
}
},
"enumDescriptions": {
"type": "array",
"items": {
"type": "string"
}
},
"repeated": {
"type": "boolean"
},
"location": {
"type": "string"
},
"properties": {
"$ref": "#/definitions/schemas"
},
"additionalProperties": {
"$ref": "#/definitions/schema"
},
"items": {
"$ref": "#/definitions/schema"
},
"annotations": {
"$ref": "#/definitions/annotations"
}
}
},
"auth": {
"type": "object",
"properties": {
"oauth2": {
"type": "object",
"properties": {
"scopes": {
"$ref": "#/definitions/scopes"
}
}
}
}
},
"schemas": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/schema"
}
},
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
},
"description": {
"type": "string"
},
"default": {
"type": "string"
},
"required": {
"type": "boolean"
},
"format": {
"type": "string"
},
"pattern": {
"type": "string"
},
"minimum": {
"type": "string"
},
"maximum": {
"type": "string"
},
"enum": {
"type": "array",
"items": {
"type": "string"
}
},
"enumDescriptions": {
"type": "array",
"items": {
"type": "string"
}
},
"repeated": {
"type": "boolean"
},
"location": {
"type": "string"
},
"properties": {
"$ref": "#/definitions/schemas"
},
"additionalProperties": {
"$ref": "#/definitions/schema"
},
"items": {
"$ref": "#/definitions/schema"
},
"$ref": {
"type": "string"
},
"annotations": {
"$ref": "#/definitions/annotations"
},
"readOnly": {
"type": "boolean"
}
}
},
"methods": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/method"
}
},
"method": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"path": {
"type": "string"
},
"httpMethod": {
"type": "string"
},
"description": {
"type": "string"
},
"parameters": {
"$ref": "#/definitions/parameters"
},
"parameterOrder": {
"type": "array",
"items": {
"type": "string"
}
},
"request": {
"type": "object",
"properties": {
"$ref": {
"type": "string"
},
"parameterName": {
"type": "string"
}
}
},
"response": {
"type": "object",
"properties": {
"$ref": {
"type": "string"
}
}
},
"scopes": {
"type": "array",
"items": {
"type": "string"
}
},
"supportsMediaDownload": {
"type": "boolean"
},
"supportsMediaUpload": {
"type": "boolean"
},
"useMediaDownloadService": {
"type": "boolean"
},
"mediaUpload": {
"$ref": "#/definitions/mediaUpload"
},
"supportsSubscription": {
"type": "boolean"
},
"flatPath": {
"type": "string"
},
"etagRequired": {
"type": "boolean"
}
}
},
"resources": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/resource"
}
},
"resource": {
"type": "object",
"properties": {
"methods": {
"$ref": "#/definitions/methods"
},
"resources": {
"$ref": "#/definitions/resources"
}
}
},
"annotations": {
"type": "object",
"properties": {
"required": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"scopes": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/scope"
}
},
"scope": {
"type": "object",
"properties": {
"description": {
"type": "string"
}
}
},
"mediaUpload": {
"type": "object",
"properties": {
"accept": {
"type": "array",
"items": {
"type": "string"
}
},
"maxSize": {
"type": "string"
},
"protocols": {
"type": "object",
"properties": {
"simple": {
"type": "object",
"properties": {
"multipart": {
"type": "boolean"
},
"path": {
"type": "string"
}
}
},
"resumable": {
"type": "object",
"properties": {
"multipart": {
"type": "boolean"
},
"path": {
"type": "string"
}
}
}
}
},
"supportsSubscription": {
"type": "boolean"
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,265 +0,0 @@
// 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.
// THIS FILE IS AUTOMATICALLY GENERATED.
syntax = "proto3";
package discovery.v1;
import "google/protobuf/any.proto";
// This option lets the proto compiler generate Java code inside the package
// name (see below) instead of inside an outer class. It creates a simpler
// developer experience by reducing one-level of name nesting and be
// consistent with most programming languages that don't support outer classes.
option java_multiple_files = true;
// The Java outer classname should be the filename in UpperCamelCase. This
// class is only used to hold proto descriptor, so developers don't need to
// work with it directly.
option java_outer_classname = "OpenAPIProto";
// The Java package name must be proto package name with proper prefix.
option java_package = "org.discovery_v1";
// A reasonable prefix for the Objective-C symbols generated from the package.
// It should at a minimum be 3 characters long, all uppercase, and convention
// is to use an abbreviation of the package name. Something short, but
// hopefully unique enough to not conflict with things that may come along in
// the future. 'GPB' is reserved for the protocol buffer implementation itself.
option objc_class_prefix = "OAS";
message Annotations {
repeated string required = 1;
}
message Any {
google.protobuf.Any value = 1;
string yaml = 2;
}
message Auth {
Oauth2 oauth2 = 1;
}
message Document {
string kind = 1;
string discovery_version = 2;
string id = 3;
string name = 4;
string version = 5;
string revision = 6;
string title = 7;
string description = 8;
Icons icons = 9;
string documentation_link = 10;
repeated string labels = 11;
string protocol = 12;
string base_url = 13;
string base_path = 14;
string root_url = 15;
string service_path = 16;
string batch_path = 17;
Parameters parameters = 18;
Auth auth = 19;
repeated string features = 20;
Schemas schemas = 21;
Methods methods = 22;
Resources resources = 23;
string etag = 24;
string owner_domain = 25;
string owner_name = 26;
bool version_module = 27;
string canonical_name = 28;
bool fully_encode_reserved_expansion = 29;
string package_path = 30;
}
// Icons that represent the API.
message Icons {
string x16 = 1;
string x32 = 2;
}
message MediaUpload {
repeated string accept = 1;
string max_size = 2;
Protocols protocols = 3;
bool supports_subscription = 4;
}
message Method {
string id = 1;
string path = 2;
string http_method = 3;
string description = 4;
Parameters parameters = 5;
repeated string parameter_order = 6;
Request request = 7;
Response response = 8;
repeated string scopes = 9;
bool supports_media_download = 10;
bool supports_media_upload = 11;
bool use_media_download_service = 12;
MediaUpload media_upload = 13;
bool supports_subscription = 14;
string flat_path = 15;
bool etag_required = 16;
}
message Methods {
repeated NamedMethod additional_properties = 1;
}
// Automatically-generated message used to represent maps of Method as ordered (name,value) pairs.
message NamedMethod {
// Map key
string name = 1;
// Mapped value
Method value = 2;
}
// Automatically-generated message used to represent maps of Parameter as ordered (name,value) pairs.
message NamedParameter {
// Map key
string name = 1;
// Mapped value
Parameter value = 2;
}
// Automatically-generated message used to represent maps of Resource as ordered (name,value) pairs.
message NamedResource {
// Map key
string name = 1;
// Mapped value
Resource value = 2;
}
// Automatically-generated message used to represent maps of Schema as ordered (name,value) pairs.
message NamedSchema {
// Map key
string name = 1;
// Mapped value
Schema value = 2;
}
// Automatically-generated message used to represent maps of Scope as ordered (name,value) pairs.
message NamedScope {
// Map key
string name = 1;
// Mapped value
Scope value = 2;
}
message Oauth2 {
Scopes scopes = 1;
}
message Parameter {
string id = 1;
string type = 2;
string _ref = 3;
string description = 4;
string default = 5;
bool required = 6;
string format = 7;
string pattern = 8;
string minimum = 9;
string maximum = 10;
repeated string enum = 11;
repeated string enum_descriptions = 12;
bool repeated = 13;
string location = 14;
Schemas properties = 15;
Schema additional_properties = 16;
Schema items = 17;
Annotations annotations = 18;
}
message Parameters {
repeated NamedParameter additional_properties = 1;
}
message Protocols {
Simple simple = 1;
Resumable resumable = 2;
}
message Request {
string _ref = 1;
string parameter_name = 2;
}
message Resource {
Methods methods = 1;
Resources resources = 2;
}
message Resources {
repeated NamedResource additional_properties = 1;
}
message Response {
string _ref = 1;
}
message Resumable {
bool multipart = 1;
string path = 2;
}
message Schema {
string id = 1;
string type = 2;
string description = 3;
string default = 4;
bool required = 5;
string format = 6;
string pattern = 7;
string minimum = 8;
string maximum = 9;
repeated string enum = 10;
repeated string enum_descriptions = 11;
bool repeated = 12;
string location = 13;
Schemas properties = 14;
Schema additional_properties = 15;
Schema items = 16;
string _ref = 17;
Annotations annotations = 18;
bool read_only = 19;
}
message Schemas {
repeated NamedSchema additional_properties = 1;
}
message Scope {
string description = 1;
}
message Scopes {
repeated NamedScope additional_properties = 1;
}
message Simple {
bool multipart = 1;
string path = 2;
}
message StringArray {
repeated string value = 1;
}

View File

@ -1,297 +0,0 @@
title: A JSON Schema for the Google API Discovery Format.
id: http://openapis.org/v3/schema.json#
$schema: http://json-schema.org/draft-04/schema#
type: object
description: This is the root document object of the Discovery Format.
required:
- kind
- discoveryVersion
additionalProperties: false
properties:
kind:
type: string
discoveryVersion:
type: string
id:
type: string
name:
type: string
version:
type: string
revision:
type: string
title:
type: string
description:
type: string
icons:
$ref: '#/definitions/icons'
documentationLink:
type: string
labels:
type: array
items:
type: string
protocol:
type: string
baseUrl:
type: string
basePath:
type: string
rootUrl:
type: string
servicePath:
type: string
batchPath:
type: string
parameters:
$ref: '#/definitions/parameters'
auth:
$ref: '#/definitions/auth'
features:
type: array
items:
type: string
schemas:
$ref: '#/definitions/schemas'
methods:
$ref: '#/definitions/methods'
resources:
$ref: '#/definitions/resources'
etag:
type: string
ownerDomain:
type: string
ownerName:
type: string
version_module:
type: boolean
canonicalName:
type: string
fullyEncodeReservedExpansion:
type: boolean
packagePath:
type: string
definitions:
icons:
type: object
description: Icons that represent the API.
required:
- x16
- x32
additionalProperties: false
properties:
x16:
type: string
x32:
type: string
parameters:
type: object
additionalProperties:
$ref: '#/definitions/parameter'
parameter:
type: object
properties:
id:
type: string
type:
type: string
$ref:
type: string
description:
type: string
default:
type: string
required:
type: boolean
format:
type: string
pattern:
type: string
minimum:
type: string
maximum:
type: string
enum:
type: array
items:
type: string
enumDescriptions:
type: array
items:
type: string
repeated:
type: boolean
location:
type: string
properties:
$ref: '#/definitions/schemas'
additionalProperties:
$ref: '#/definitions/schema'
items:
$ref: '#/definitions/schema'
annotations:
$ref: '#/definitions/annotations'
auth:
type: object
properties:
oauth2:
type: object
properties:
scopes:
$ref: '#/definitions/scopes'
schemas:
type: object
additionalProperties:
$ref: '#/definitions/schema'
schema:
type: object
properties:
id:
type: string
type:
type: string
description:
type: string
default:
type: string
required:
type: boolean
format:
type: string
pattern:
type: string
minimum:
type: string
maximum:
type: string
enum:
type: array
items:
type: string
enumDescriptions:
type: array
items:
type: string
repeated:
type: boolean
location:
type: string
properties:
$ref: '#/definitions/schemas'
additionalProperties:
$ref: '#/definitions/schema'
items:
$ref: '#/definitions/schema'
$ref:
type: string
annotations:
$ref: '#/definitions/annotations'
readOnly:
type: boolean
methods:
type: object
additionalProperties:
$ref: '#/definitions/method'
method:
type: object
properties:
id:
type: string
path:
type: string
httpMethod:
type: string
description:
type: string
parameters:
$ref: '#/definitions/parameters'
parameterOrder:
type: array
items:
type: string
request:
type: object
properties:
$ref:
type: string
parameterName:
type: string
response:
type: object
properties:
$ref:
type: string
scopes:
type: array
items:
type: string
supportsMediaDownload:
type: boolean
supportsMediaUpload:
type: boolean
useMediaDownloadService:
type: boolean
mediaUpload:
$ref: '#/definitions/mediaUpload'
supportsSubscription:
type: boolean
flatPath:
type: string
etagRequired:
type: boolean
resources:
type: object
additionalProperties:
$ref: '#/definitions/resource'
resource:
type: object
properties:
methods:
$ref: '#/definitions/methods'
resources:
$ref: '#/definitions/resources'
annotations:
type: object
properties:
required:
type: array
items:
type: string
scopes:
type: object
additionalProperties:
$ref: '#/definitions/scope'
scope:
type: object
properties:
description:
type: string
mediaUpload:
type: object
properties:
accept:
type: array
items:
type: string
maxSize:
type: string
protocols:
type: object
properties:
simple:
type: object
properties:
multipart:
type: boolean
path:
type: string
resumable:
type: object
properties:
multipart:
type: boolean
path:
type: string
supportsSubscription:
type: boolean

View File

@ -1,3 +0,0 @@
# examples
This directory contains example descriptions of APIs.

View File

@ -1,101 +0,0 @@
swagger: "2.0"
info:
title: Swagger Petstore
myproperty: 123
license:
name: MIT
host: petstore.swagger.io
basePath: /v1
schemes:
- http
consumes:
- application/json
produces:
- application/json
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
type: integer
format: int32
myproperty: 123
responses:
"200":
description: An paged array of pets
headers:
x-next:
type: string
description: A link to the next page of responses
schema:
$ref: '#/definitions/Pets'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
post:
summary: Create a pet
operationId: createPets
tags: pets
responses:
"201":
description: Null response
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
type: string
responses:
"200":
description: Expected response to a valid request
schema:
$ref: '#/definitions/Pets'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
definitions:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: '#/definitions/Pet'
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string

View File

@ -1,100 +0,0 @@
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
host: petstore.swagger.io
basePath: /v1
schemes:
- http
consumes:
- application/json
produces:
- application/json
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
type: integer
format: int32
responses:
"200":
description: An paged array of pets
headers:
x-next:
type: string
description: A link to the next page of responses
schema:
$ref: '#/definitions/Pets'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
"201":
description: Null response
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
type: string
responses:
"200":
description: Expected response to a valid request
schema:
$ref: '#/definitions/Pets'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
definitions:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: '#/definitions/Pet'
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string

View File

@ -1,101 +0,0 @@
swagger: "2.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
host: petstore.swagger.io
basePath: /v1
schemes:
- http
consumes:
- application/json
produces:
- application/json
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
type: integer
format: int32
responses:
"200":
description: An paged array of pets
headers:
x-next:
type: string
description: A link to the next page of responses
schema:
$ref: '#/definitions/Pets'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
"201":
description: Null response
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
type: string
responses:
"200":
description: Expected response to a valid request
schema:
$ref: '#/definitions/Pets'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
definitions:
NotAPet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: '#/definitions/Pet'
NotAnError:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string

View File

@ -1,58 +0,0 @@
{
"swagger": "2.0",
"info": {
"title": "Simple API overview",
"version": "v2"
},
"paths": {
"/": {
"get": {
"operationId": "listVersionsv2",
"summary": "List API versions",
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "200 300 response",
"examples": {
"application/json": "{\n \"versions\": [\n {\n \"status\": \"CURRENT\",\n \"updated\": \"2011-01-21T11:33:21Z\",\n \"id\": \"v2.0\",\n \"links\": [\n {\n \"href\": \"http://127.0.0.1:8774/v2/\",\n \"rel\": \"self\"\n }\n ]\n },\n {\n \"status\": \"EXPERIMENTAL\",\n \"updated\": \"2013-07-23T11:33:21Z\",\n \"id\": \"v3.0\",\n \"links\": [\n {\n \"href\": \"http://127.0.0.1:8774/v3/\",\n \"rel\": \"self\"\n }\n ]\n }\n ]\n}"
}
},
"300": {
"description": "200 300 response",
"examples": {
"application/json": "{\n \"versions\": [\n {\n \"status\": \"CURRENT\",\n \"updated\": \"2011-01-21T11:33:21Z\",\n \"id\": \"v2.0\",\n \"links\": [\n {\n \"href\": \"http://127.0.0.1:8774/v2/\",\n \"rel\": \"self\"\n }\n ]\n },\n {\n \"status\": \"EXPERIMENTAL\",\n \"updated\": \"2013-07-23T11:33:21Z\",\n \"id\": \"v3.0\",\n \"links\": [\n {\n \"href\": \"http://127.0.0.1:8774/v3/\",\n \"rel\": \"self\"\n }\n ]\n }\n ]\n}"
}
}
}
}
},
"/v2": {
"get": {
"operationId": "getVersionDetailsv2",
"summary": "Show API version details",
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "200 203 response",
"examples": {
"application/json": "{\n \"version\": {\n \"status\": \"CURRENT\",\n \"updated\": \"2011-01-21T11:33:21Z\",\n \"media-types\": [\n {\n \"base\": \"application/xml\",\n \"type\": \"application/vnd.openstack.compute+xml;version=2\"\n },\n {\n \"base\": \"application/json\",\n \"type\": \"application/vnd.openstack.compute+json;version=2\"\n }\n ],\n \"id\": \"v2.0\",\n \"links\": [\n {\n \"href\": \"http://127.0.0.1:8774/v2/\",\n \"rel\": \"self\"\n },\n {\n \"href\": \"http://docs.openstack.org/api/openstack-compute/2/os-compute-devguide-2.pdf\",\n \"type\": \"application/pdf\",\n \"rel\": \"describedby\"\n },\n {\n \"href\": \"http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl\",\n \"type\": \"application/vnd.sun.wadl+xml\",\n \"rel\": \"describedby\"\n },\n {\n \"href\": \"http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl\",\n \"type\": \"application/vnd.sun.wadl+xml\",\n \"rel\": \"describedby\"\n }\n ]\n }\n}"
}
},
"203": {
"description": "200 203 response",
"examples": {
"application/json": "{\n \"version\": {\n \"status\": \"CURRENT\",\n \"updated\": \"2011-01-21T11:33:21Z\",\n \"media-types\": [\n {\n \"base\": \"application/xml\",\n \"type\": \"application/vnd.openstack.compute+xml;version=2\"\n },\n {\n \"base\": \"application/json\",\n \"type\": \"application/vnd.openstack.compute+json;version=2\"\n }\n ],\n \"id\": \"v2.0\",\n \"links\": [\n {\n \"href\": \"http://23.253.228.211:8774/v2/\",\n \"rel\": \"self\"\n },\n {\n \"href\": \"http://docs.openstack.org/api/openstack-compute/2/os-compute-devguide-2.pdf\",\n \"type\": \"application/pdf\",\n \"rel\": \"describedby\"\n },\n {\n \"href\": \"http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl\",\n \"type\": \"application/vnd.sun.wadl+xml\",\n \"rel\": \"describedby\"\n }\n ]\n }\n}"
}
}
}
}
}
},
"consumes": [
"application/json"
]
}

View File

@ -1,210 +0,0 @@
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "Swagger Petstore",
"description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "Swagger API Team",
"email": "foo@example.com",
"url": "http://madskristensen.net"
},
"license": {
"name": "MIT",
"url": "http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT"
}
},
"host": "petstore.swagger.io",
"basePath": "/api",
"schemes": [
"http"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/pets": {
"get": {
"description": "Returns all pets from the system that the user has access to\nNam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia.\n\nSed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien.\n",
"operationId": "findPets",
"parameters": [
{
"name": "tags",
"in": "query",
"description": "tags to filter by",
"required": false,
"type": "array",
"collectionFormat": "csv",
"items": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"description": "maximum number of results to return",
"required": false,
"type": "integer",
"format": "int32"
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
},
"post": {
"description": "Creates a new pet in the store. Duplicates are allowed",
"operationId": "addPet",
"parameters": [
{
"name": "pet",
"in": "body",
"description": "Pet to add to the store",
"required": true,
"schema": {
"$ref": "#/definitions/NewPet"
}
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"$ref": "#/definitions/Pet"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/pets/{id}": {
"get": {
"description": "Returns a user based on a single ID, if the user does not have access to the pet",
"operationId": "find pet by id",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID of pet to fetch",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"$ref": "#/definitions/Pet"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
},
"delete": {
"description": "deletes a single pet based on the ID supplied",
"operationId": "deletePet",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID of pet to delete",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"204": {
"description": "pet deleted"
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
}
},
"definitions": {
"Pet": {
"type": "object",
"allOf": [
{
"$ref": "#/definitions/NewPet"
},
{
"required": [
"id"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
}
}
}
]
},
"NewPet": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
},
"Error": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
}
}
}
}

View File

@ -1,68 +0,0 @@
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "Swagger Petstore",
"description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "Swagger API Team"
},
"license": {
"name": "MIT"
}
},
"host": "petstore.swagger.io",
"basePath": "/api",
"schemes": [
"http"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/pets": {
"get": {
"description": "Returns all pets from the system that the user has access to",
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "A list of pets.",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
}
}
}
}
},
"definitions": {
"Pet": {
"type": "object",
"required": [
"id",
"name"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
}
}
}

View File

@ -1,16 +0,0 @@
{
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
}
}

View File

@ -1,19 +0,0 @@
{
"type": "object",
"allOf": [
{
"$ref": "Pet.json"
},
{
"required": [
"name"
],
"properties": {
"description": {
"type": "integer",
"format": "int64"
}
}
}
]
}

View File

@ -1,19 +0,0 @@
{
"type": "object",
"required": [
"id",
"name"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
}

View File

@ -1,21 +0,0 @@
{
"tagsParam": {
"name": "tags",
"in": "query",
"description": "tags to filter by",
"required": false,
"type": "array",
"collectionFormat": "csv",
"items": {
"type": "string"
}
},
"limitsParam": {
"name": "limit",
"in": "query",
"description": "maximum number of results to return",
"required": false,
"type": "integer",
"format": "int32"
}
}

View File

@ -1,146 +0,0 @@
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "Swagger Petstore",
"description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
"termsOfService": "http://helloreverb.com/terms/",
"contact": {
"name": "Wordnik API Team",
"email": "foo@example.com",
"url": "http://madskristensen.net"
},
"license": {
"name": "MIT",
"url": "http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT"
}
},
"host": "petstore.swagger.wordnik.com",
"basePath": "/api",
"schemes": [
"http"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/pets": {
"get": {
"description": "Returns all pets from the system that the user has access to\nNam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia.\n\nSed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien.\n",
"operationId": "findPets",
"parameters": [
{
"$ref": "parameters.json#/tagsParam"
},
{
"$ref": "parameters.json#/limitsParam"
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"type": "array",
"items": {
"$ref": "Pet.json"
}
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "../common/Error.json"
}
}
}
},
"post": {
"description": "Creates a new pet in the store. Duplicates are allowed",
"operationId": "addPet",
"parameters": [
{
"name": "pet",
"in": "body",
"description": "Pet to add to the store",
"required": true,
"schema": {
"$ref": "NewPet.json"
}
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"$ref": "Pet.json"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "../common/Error.json"
}
}
}
}
},
"/pets/{id}": {
"get": {
"description": "Returns a user based on a single ID, if the user does not have access to the pet",
"operationId": "find pet by id",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID of pet to fetch",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"$ref": "Pet.json"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "../common/Error.json"
}
}
}
},
"delete": {
"description": "deletes a single pet based on the ID supplied",
"operationId": "deletePet",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID of pet to delete",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"204": {
"description": "pet deleted"
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "../common/Error.json"
}
}
}
}
}
}
}

View File

@ -1,222 +0,0 @@
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "Swagger Petstore",
"description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "Swagger API Team"
},
"license": {
"name": "MIT"
}
},
"host": "petstore.swagger.io",
"basePath": "/api",
"schemes": [
"http"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/pets": {
"get": {
"description": "Returns all pets from the system that the user has access to",
"operationId": "findPets",
"produces": [
"application/json",
"application/xml",
"text/xml",
"text/html"
],
"parameters": [
{
"name": "tags",
"in": "query",
"description": "tags to filter by",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "csv"
},
{
"name": "limit",
"in": "query",
"description": "maximum number of results to return",
"required": false,
"type": "integer",
"format": "int32"
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/ErrorModel"
}
}
}
},
"post": {
"description": "Creates a new pet in the store. Duplicates are allowed",
"operationId": "addPet",
"produces": [
"application/json"
],
"parameters": [
{
"name": "pet",
"in": "body",
"description": "Pet to add to the store",
"required": true,
"schema": {
"$ref": "#/definitions/NewPet"
}
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"$ref": "#/definitions/Pet"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/ErrorModel"
}
}
}
}
},
"/pets/{id}": {
"get": {
"description": "Returns a user based on a single ID, if the user does not have access to the pet",
"operationId": "findPetById",
"produces": [
"application/json",
"application/xml",
"text/xml",
"text/html"
],
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID of pet to fetch",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"$ref": "#/definitions/Pet"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/ErrorModel"
}
}
}
},
"delete": {
"description": "deletes a single pet based on the ID supplied",
"operationId": "deletePet",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID of pet to delete",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"204": {
"description": "pet deleted"
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/ErrorModel"
}
}
}
}
}
},
"definitions": {
"Pet": {
"type": "object",
"allOf": [
{
"$ref": "#/definitions/NewPet"
},
{
"required": [
"id"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
}
}
}
]
},
"NewPet": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
},
"ErrorModel": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
}
}
}
}

View File

@ -1,233 +0,0 @@
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "Swagger Petstore",
"description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "Swagger API Team",
"email": "apiteam@swagger.io",
"url": "http://swagger.io"
},
"license": {
"name": "MIT",
"url": "http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT"
}
},
"externalDocs": {
"description": "find more info here",
"url": "https://swagger.io/about"
},
"host": "petstore.swagger.io",
"basePath": "/api",
"schemes": [
"http"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/pets": {
"get": {
"description": "Returns all pets from the system that the user has access to",
"operationId": "findPets",
"externalDocs": {
"description": "find more info here",
"url": "https://swagger.io/about"
},
"produces": [
"application/json",
"application/xml",
"text/xml",
"text/html"
],
"parameters": [
{
"name": "tags",
"in": "query",
"description": "tags to filter by",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "csv"
},
{
"name": "limit",
"in": "query",
"description": "maximum number of results to return",
"required": false,
"type": "integer",
"format": "int32"
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/ErrorModel"
}
}
}
},
"post": {
"description": "Creates a new pet in the store. Duplicates are allowed",
"operationId": "addPet",
"produces": [
"application/json"
],
"parameters": [
{
"name": "pet",
"in": "body",
"description": "Pet to add to the store",
"required": true,
"schema": {
"$ref": "#/definitions/NewPet"
}
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"$ref": "#/definitions/Pet"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/ErrorModel"
}
}
}
}
},
"/pets/{id}": {
"get": {
"description": "Returns a user based on a single ID, if the user does not have access to the pet",
"operationId": "findPetById",
"produces": [
"application/json",
"application/xml",
"text/xml",
"text/html"
],
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID of pet to fetch",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "pet response",
"schema": {
"$ref": "#/definitions/Pet"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/ErrorModel"
}
}
}
},
"delete": {
"description": "deletes a single pet based on the ID supplied",
"operationId": "deletePet",
"parameters": [
{
"name": "id",
"in": "path",
"description": "ID of pet to delete",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"204": {
"description": "pet deleted"
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/ErrorModel"
}
}
}
}
}
},
"definitions": {
"Pet": {
"type": "object",
"allOf": [
{
"$ref": "#/definitions/NewPet"
},
{
"required": [
"id"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
}
}
}
]
},
"NewPet": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
},
"ErrorModel": {
"type": "object",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
}
}
}
}

View File

@ -1,153 +0,0 @@
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "Swagger Petstore",
"license": {
"name": "MIT"
}
},
"host": "petstore.swagger.io",
"basePath": "/v1",
"schemes": [
"http"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/pets": {
"get": {
"summary": "List all pets",
"operationId": "listPets",
"tags": [
"pets"
],
"parameters": [
{
"name": "limit",
"in": "query",
"description": "How many items to return at one time (max 100)",
"required": false,
"type": "integer",
"format": "int32"
}
],
"responses": {
"200": {
"description": "An paged array of pets",
"headers": {
"x-next": {
"type": "string",
"description": "A link to the next page of responses"
}
},
"schema": {
"$ref": "#/definitions/Pets"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
},
"post": {
"summary": "Create a pet",
"operationId": "createPets",
"tags": [
"pets"
],
"responses": {
"201": {
"description": "Null response"
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/pets/{petId}": {
"get": {
"summary": "Info for a specific pet",
"operationId": "showPetById",
"tags": [
"pets"
],
"parameters": [
{
"name": "petId",
"in": "path",
"required": true,
"description": "The id of the pet to retrieve",
"type": "string"
}
],
"responses": {
"200": {
"description": "Expected response to a valid request",
"schema": {
"$ref": "#/definitions/Pets"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
}
},
"definitions": {
"Pet": {
"required": [
"id",
"name"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
},
"Pets": {
"type": "array",
"items": {
"$ref": "#/definitions/Pet"
}
},
"Error": {
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
}
}
}
}

View File

@ -1,370 +0,0 @@
{
"swagger": "2.0",
"info": {
"title": "Uber API",
"description": "Move your app forward with the Uber API",
"version": "1.0.0"
},
"host": "api.uber.com",
"schemes": [
"https"
],
"basePath": "/v1",
"produces": [
"application/json"
],
"paths": {
"/products": {
"get": {
"summary": "Product Types",
"description": "The Products endpoint returns information about the Uber products offered at a given location. The response includes the display name and other details about each product, and lists the products in the proper display order.",
"parameters": [
{
"name": "latitude",
"in": "query",
"description": "Latitude component of location.",
"required": true,
"type": "number",
"format": "double"
},
{
"name": "longitude",
"in": "query",
"description": "Longitude component of location.",
"required": true,
"type": "number",
"format": "double"
}
],
"tags": [
"Products"
],
"responses": {
"200": {
"description": "An array of products",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Product"
}
}
},
"default": {
"description": "Unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/estimates/price": {
"get": {
"summary": "Price Estimates",
"description": "The Price Estimates endpoint returns an estimated price range for each product offered at a given location. The price estimate is provided as a formatted string with the full price range and the localized currency symbol.<br><br>The response also includes low and high estimates, and the [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code for situations requiring currency conversion. When surge is active for a particular product, its surge_multiplier will be greater than 1, but the price estimate already factors in this multiplier.",
"parameters": [
{
"name": "start_latitude",
"in": "query",
"description": "Latitude component of start location.",
"required": true,
"type": "number",
"format": "double"
},
{
"name": "start_longitude",
"in": "query",
"description": "Longitude component of start location.",
"required": true,
"type": "number",
"format": "double"
},
{
"name": "end_latitude",
"in": "query",
"description": "Latitude component of end location.",
"required": true,
"type": "number",
"format": "double"
},
{
"name": "end_longitude",
"in": "query",
"description": "Longitude component of end location.",
"required": true,
"type": "number",
"format": "double"
}
],
"tags": [
"Estimates"
],
"responses": {
"200": {
"description": "An array of price estimates by product",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/PriceEstimate"
}
}
},
"default": {
"description": "Unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/estimates/time": {
"get": {
"summary": "Time Estimates",
"description": "The Time Estimates endpoint returns ETAs for all products offered at a given location, with the responses expressed as integers in seconds. We recommend that this endpoint be called every minute to provide the most accurate, up-to-date ETAs.",
"parameters": [
{
"name": "start_latitude",
"in": "query",
"description": "Latitude component of start location.",
"required": true,
"type": "number",
"format": "double"
},
{
"name": "start_longitude",
"in": "query",
"description": "Longitude component of start location.",
"required": true,
"type": "number",
"format": "double"
},
{
"name": "customer_uuid",
"in": "query",
"type": "string",
"format": "uuid",
"description": "Unique customer identifier to be used for experience customization."
},
{
"name": "product_id",
"in": "query",
"type": "string",
"description": "Unique identifier representing a specific product for a given latitude & longitude."
}
],
"tags": [
"Estimates"
],
"responses": {
"200": {
"description": "An array of products",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Product"
}
}
},
"default": {
"description": "Unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/me": {
"get": {
"summary": "User Profile",
"description": "The User Profile endpoint returns information about the Uber user that has authorized with the application.",
"tags": [
"User"
],
"responses": {
"200": {
"description": "Profile information for a user",
"schema": {
"$ref": "#/definitions/Profile"
}
},
"default": {
"description": "Unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/history": {
"get": {
"summary": "User Activity",
"description": "The User Activity endpoint returns data about a user's lifetime activity with Uber. The response will include pickup locations and times, dropoff locations and times, the distance of past requests, and information about which products were requested.<br><br>The history array in the response will have a maximum length based on the limit parameter. The response value count may exceed limit, therefore subsequent API requests may be necessary.",
"parameters": [
{
"name": "offset",
"in": "query",
"type": "integer",
"format": "int32",
"description": "Offset the list of returned results by this amount. Default is zero."
},
{
"name": "limit",
"in": "query",
"type": "integer",
"format": "int32",
"description": "Number of items to retrieve. Default is 5, maximum is 100."
}
],
"tags": [
"User"
],
"responses": {
"200": {
"description": "History information for the given user",
"schema": {
"$ref": "#/definitions/Activities"
}
},
"default": {
"description": "Unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
}
},
"definitions": {
"Product": {
"properties": {
"product_id": {
"type": "string",
"description": "Unique identifier representing a specific product for a given latitude & longitude. For example, uberX in San Francisco will have a different product_id than uberX in Los Angeles."
},
"description": {
"type": "string",
"description": "Description of product."
},
"display_name": {
"type": "string",
"description": "Display name of product."
},
"capacity": {
"type": "string",
"description": "Capacity of product. For example, 4 people."
},
"image": {
"type": "string",
"description": "Image URL representing the product."
}
}
},
"PriceEstimate": {
"properties": {
"product_id": {
"type": "string",
"description": "Unique identifier representing a specific product for a given latitude & longitude. For example, uberX in San Francisco will have a different product_id than uberX in Los Angeles"
},
"currency_code": {
"type": "string",
"description": "[ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code."
},
"display_name": {
"type": "string",
"description": "Display name of product."
},
"estimate": {
"type": "string",
"description": "Formatted string of estimate in local currency of the start location. Estimate could be a range, a single number (flat rate) or \"Metered\" for TAXI."
},
"low_estimate": {
"type": "number",
"description": "Lower bound of the estimated price."
},
"high_estimate": {
"type": "number",
"description": "Upper bound of the estimated price."
},
"surge_multiplier": {
"type": "number",
"description": "Expected surge multiplier. Surge is active if surge_multiplier is greater than 1. Price estimate already factors in the surge multiplier."
}
}
},
"Profile": {
"properties": {
"first_name": {
"type": "string",
"description": "First name of the Uber user."
},
"last_name": {
"type": "string",
"description": "Last name of the Uber user."
},
"email": {
"type": "string",
"description": "Email address of the Uber user"
},
"picture": {
"type": "string",
"description": "Image URL of the Uber user."
},
"promo_code": {
"type": "string",
"description": "Promo code of the Uber user."
}
}
},
"Activity": {
"properties": {
"uuid": {
"type": "string",
"description": "Unique identifier for the activity"
}
}
},
"Activities": {
"properties": {
"offset": {
"type": "integer",
"format": "int32",
"description": "Position in pagination."
},
"limit": {
"type": "integer",
"format": "int32",
"description": "Number of items to retrieve (100 max)."
},
"count": {
"type": "integer",
"format": "int32",
"description": "Total number of items available."
},
"history": {
"type": "array",
"items": {
"$ref": "#/definitions/Activity"
}
}
}
},
"Error": {
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"fields": {
"type": "string"
}
}
}
}
}

View File

@ -1,164 +0,0 @@
swagger: "2.0"
info:
title: Simple API overview
version: v2
paths:
/:
get:
operationId: listVersionsv2
summary: List API versions
produces:
- application/json
responses:
"200":
description: |-
200 300 response
examples:
application/json: |-
{
"versions": [
{
"status": "CURRENT",
"updated": "2011-01-21T11:33:21Z",
"id": "v2.0",
"links": [
{
"href": "http://127.0.0.1:8774/v2/",
"rel": "self"
}
]
},
{
"status": "EXPERIMENTAL",
"updated": "2013-07-23T11:33:21Z",
"id": "v3.0",
"links": [
{
"href": "http://127.0.0.1:8774/v3/",
"rel": "self"
}
]
}
]
}
"300":
description: |-
200 300 response
examples:
application/json: |-
{
"versions": [
{
"status": "CURRENT",
"updated": "2011-01-21T11:33:21Z",
"id": "v2.0",
"links": [
{
"href": "http://127.0.0.1:8774/v2/",
"rel": "self"
}
]
},
{
"status": "EXPERIMENTAL",
"updated": "2013-07-23T11:33:21Z",
"id": "v3.0",
"links": [
{
"href": "http://127.0.0.1:8774/v3/",
"rel": "self"
}
]
}
]
}
/v2:
get:
operationId: getVersionDetailsv2
summary: Show API version details
produces:
- application/json
responses:
"200":
description: |-
200 203 response
examples:
application/json: |-
{
"version": {
"status": "CURRENT",
"updated": "2011-01-21T11:33:21Z",
"media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml;version=2"
},
{
"base": "application/json",
"type": "application/vnd.openstack.compute+json;version=2"
}
],
"id": "v2.0",
"links": [
{
"href": "http://127.0.0.1:8774/v2/",
"rel": "self"
},
{
"href": "http://docs.openstack.org/api/openstack-compute/2/os-compute-devguide-2.pdf",
"type": "application/pdf",
"rel": "describedby"
},
{
"href": "http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl",
"type": "application/vnd.sun.wadl+xml",
"rel": "describedby"
},
{
"href": "http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl",
"type": "application/vnd.sun.wadl+xml",
"rel": "describedby"
}
]
}
}
"203":
description: |-
200 203 response
examples:
application/json: |-
{
"version": {
"status": "CURRENT",
"updated": "2011-01-21T11:33:21Z",
"media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml;version=2"
},
{
"base": "application/json",
"type": "application/vnd.openstack.compute+json;version=2"
}
],
"id": "v2.0",
"links": [
{
"href": "http://23.253.228.211:8774/v2/",
"rel": "self"
},
{
"href": "http://docs.openstack.org/api/openstack-compute/2/os-compute-devguide-2.pdf",
"type": "application/pdf",
"rel": "describedby"
},
{
"href": "http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl",
"type": "application/vnd.sun.wadl+xml",
"rel": "describedby"
}
]
}
}
consumes:
- application/json

View File

@ -1,142 +0,0 @@
swagger: "2.0"
info:
version: 1.0.0
title: Swagger Petstore
description: A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification
termsOfService: http://swagger.io/terms/
contact:
name: Swagger API Team
email: foo@example.com
url: http://madskristensen.net
license:
name: MIT
url: http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT
host: petstore.swagger.io
basePath: /api
schemes:
- http
consumes:
- application/json
produces:
- application/json
paths:
/pets:
get:
description: |
Returns all pets from the system that the user has access to
Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia.
Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien.
operationId: findPets
parameters:
- name: tags
in: query
description: tags to filter by
required: false
type: array
collectionFormat: csv
items:
type: string
- name: limit
in: query
description: maximum number of results to return
required: false
type: integer
format: int32
responses:
"200":
description: pet response
schema:
type: array
items:
$ref: '#/definitions/Pet'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
post:
description: Creates a new pet in the store. Duplicates are allowed
operationId: addPet
parameters:
- name: pet
in: body
description: Pet to add to the store
required: true
schema:
$ref: '#/definitions/NewPet'
responses:
"200":
description: pet response
schema:
$ref: '#/definitions/Pet'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
/pets/{id}:
get:
description: Returns a user based on a single ID, if the user does not have access to the pet
operationId: find pet by id
parameters:
- name: id
in: path
description: ID of pet to fetch
required: true
type: integer
format: int64
responses:
"200":
description: pet response
schema:
$ref: '#/definitions/Pet'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
delete:
description: deletes a single pet based on the ID supplied
operationId: deletePet
parameters:
- name: id
in: path
description: ID of pet to delete
required: true
type: integer
format: int64
responses:
"204":
description: pet deleted
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
definitions:
Pet:
allOf:
- $ref: '#/definitions/NewPet'
- required:
- id
properties:
id:
type: integer
format: int64
NewPet:
required:
- name
properties:
name:
type: string
tag:
type: string
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string

View File

@ -1,47 +0,0 @@
---
swagger: "2.0"
info:
version: "1.0.0"
title: "Swagger Petstore"
description: "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification"
termsOfService: "http://swagger.io/terms/"
contact:
name: "Swagger API Team"
license:
name: "MIT"
host: "petstore.swagger.io"
basePath: "/api"
schemes:
- "http"
consumes:
- "application/json"
produces:
- "application/json"
paths:
/pets:
get:
description: "Returns all pets from the system that the user has access to"
produces:
- "application/json"
responses:
"200":
description: "A list of pets."
schema:
type: "array"
items:
$ref: "#/definitions/Pet"
definitions:
Pet:
type: "object"
required:
- "id"
- "name"
properties:
id:
type: "integer"
format: "int64"
name:
type: "string"
tag:
type: "string"

View File

@ -1,10 +0,0 @@
type: object
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string

View File

@ -1,9 +0,0 @@
type: object
allOf:
- $ref: 'Pet.yaml'
- required:
- name
properties:
description:
type: integer
format: int64

View File

@ -1,12 +0,0 @@
type: object
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string

View File

@ -1,16 +0,0 @@
tagsParam:
name: tags
in: query
description: tags to filter by
required: false
type: array
collectionFormat: csv
items:
type: string
limitsParam:
name: limit
in: query
description: maximum number of results to return
required: false
type: integer
format: int32

View File

@ -1,214 +0,0 @@
swagger: "2.0"
info: <
title: "Swagger Petstore"
version: "1.0.0"
description: "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification"
terms_of_service: "http://helloreverb.com/terms/"
contact: <
name: "Wordnik API Team"
url: "http://madskristensen.net"
email: "foo@example.com"
>
license: <
name: "MIT"
url: "http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT"
>
>
host: "petstore.swagger.wordnik.com"
base_path: "/api"
schemes: "http"
consumes: "application/json"
produces: "application/json"
paths: <
path: <
name: "/pets"
value: <
get: <
description: "Returns all pets from the system that the user has access to\nNam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia.\n\nSed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien.\n"
operation_id: "findPets"
parameters: <
json_reference: <
_ref: "parameters.yaml#/tagsParam"
>
>
parameters: <
json_reference: <
_ref: "parameters.yaml#/limitsParam"
>
>
responses: <
response_code: <
name: "200"
value: <
response: <
description: "pet response"
schema: <
schema: <
type: <
value: "array"
>
items: <
schema: <
_ref: "Pet.yaml"
>
>
>
>
>
>
>
response_code: <
name: "default"
value: <
response: <
description: "unexpected error"
schema: <
schema: <
_ref: "../common/Error.yaml"
>
>
>
>
>
>
>
post: <
description: "Creates a new pet in the store. Duplicates are allowed"
operation_id: "addPet"
parameters: <
parameter: <
body_parameter: <
description: "Pet to add to the store"
name: "pet"
in: "body"
required: true
schema: <
_ref: "NewPet.yaml"
>
>
>
>
responses: <
response_code: <
name: "200"
value: <
response: <
description: "pet response"
schema: <
schema: <
_ref: "Pet.yaml"
>
>
>
>
>
response_code: <
name: "default"
value: <
response: <
description: "unexpected error"
schema: <
schema: <
_ref: "../common/Error.yaml"
>
>
>
>
>
>
>
>
>
path: <
name: "/pets/{id}"
value: <
get: <
description: "Returns a user based on a single ID, if the user does not have access to the pet"
operation_id: "find pet by id"
parameters: <
parameter: <
non_body_parameter: <
path_parameter_sub_schema: <
required: true
in: "path"
description: "ID of pet to fetch"
name: "id"
type: "integer"
format: "int64"
>
>
>
>
responses: <
response_code: <
name: "200"
value: <
response: <
description: "pet response"
schema: <
schema: <
_ref: "Pet.yaml"
>
>
>
>
>
response_code: <
name: "default"
value: <
response: <
description: "unexpected error"
schema: <
schema: <
_ref: "../common/Error.yaml"
>
>
>
>
>
>
>
delete: <
description: "deletes a single pet based on the ID supplied"
operation_id: "deletePet"
parameters: <
parameter: <
non_body_parameter: <
path_parameter_sub_schema: <
required: true
in: "path"
description: "ID of pet to delete"
name: "id"
type: "integer"
format: "int64"
>
>
>
>
responses: <
response_code: <
name: "204"
value: <
response: <
description: "pet deleted"
>
>
>
response_code: <
name: "default"
value: <
response: <
description: "unexpected error"
schema: <
schema: <
_ref: "../common/Error.yaml"
>
>
>
>
>
>
>
>
>
>

View File

@ -1,100 +0,0 @@
swagger: "2.0"
info:
version: 1.0.0
title: Swagger Petstore
description: A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification
termsOfService: http://helloreverb.com/terms/
contact:
name: Wordnik API Team
email: foo@example.com
url: http://madskristensen.net
license:
name: MIT
url: http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT
host: petstore.swagger.wordnik.com
basePath: /api
schemes:
- http
consumes:
- application/json
produces:
- application/json
paths:
/pets:
get:
description: |
Returns all pets from the system that the user has access to
Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia.
Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien.
operationId: findPets
parameters:
- $ref: 'parameters.yaml#/tagsParam'
- $ref: 'parameters.yaml#/limitsParam'
responses:
"200":
description: pet response
schema:
type: array
items:
$ref: 'Pet.yaml'
default:
description: unexpected error
schema:
$ref: '../common/Error.yaml'
post:
description: Creates a new pet in the store. Duplicates are allowed
operationId: addPet
parameters:
- name: pet
in: body
description: Pet to add to the store
required: true
schema:
$ref: 'NewPet.yaml'
responses:
"200":
description: pet response
schema:
$ref: 'Pet.yaml'
default:
description: unexpected error
schema:
$ref: '../common/Error.yaml'
/pets/{id}:
get:
description: Returns a user based on a single ID, if the user does not have access to the pet
operationId: find pet by id
parameters:
- name: id
in: path
description: ID of pet to fetch
required: true
type: integer
format: int64
responses:
"200":
description: pet response
schema:
$ref: 'Pet.yaml'
default:
description: unexpected error
schema:
$ref: '../common/Error.yaml'
delete:
description: deletes a single pet based on the ID supplied
operationId: deletePet
parameters:
- name: id
in: path
description: ID of pet to delete
required: true
type: integer
format: int64
responses:
"204":
description: pet deleted
default:
description: unexpected error
schema:
$ref: '../common/Error.yaml'

View File

@ -1,157 +0,0 @@
---
swagger: "2.0"
info:
version: "1.0.0"
title: "Swagger Petstore"
description: "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification"
termsOfService: "http://swagger.io/terms/"
contact:
name: "Swagger API Team"
license:
name: "MIT"
host: "petstore.swagger.io"
basePath: "/api"
schemes:
- "http"
consumes:
- "application/json"
produces:
- "application/json"
paths:
/pets:
get:
description: "Returns all pets from the system that the user has access to"
operationId: "findPets"
produces:
- "application/json"
- "application/xml"
- "text/xml"
- "text/html"
parameters:
-
name: "tags"
in: "query"
description: "tags to filter by"
required: false
type: "array"
items:
type: "string"
collectionFormat: "csv"
-
name: "limit"
in: "query"
description: "maximum number of results to return"
required: false
type: "integer"
format: "int32"
responses:
"200":
description: "pet response"
schema:
type: "array"
items:
$ref: "#/definitions/Pet"
default:
description: "unexpected error"
schema:
$ref: "#/definitions/ErrorModel"
post:
description: "Creates a new pet in the store. Duplicates are allowed"
operationId: "addPet"
produces:
- "application/json"
parameters:
-
name: "pet"
in: "body"
description: "Pet to add to the store"
required: true
schema:
$ref: "#/definitions/NewPet"
responses:
"200":
description: "pet response"
schema:
$ref: "#/definitions/Pet"
default:
description: "unexpected error"
schema:
$ref: "#/definitions/ErrorModel"
/pets/{id}:
get:
description: "Returns a user based on a single ID, if the user does not have access to the pet"
operationId: "findPetById"
produces:
- "application/json"
- "application/xml"
- "text/xml"
- "text/html"
parameters:
-
name: "id"
in: "path"
description: "ID of pet to fetch"
required: true
type: "integer"
format: "int64"
responses:
"200":
description: "pet response"
schema:
$ref: "#/definitions/Pet"
default:
description: "unexpected error"
schema:
$ref: "#/definitions/ErrorModel"
delete:
description: "deletes a single pet based on the ID supplied"
operationId: "deletePet"
parameters:
-
name: "id"
in: "path"
description: "ID of pet to delete"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: "pet deleted"
default:
description: "unexpected error"
schema:
$ref: "#/definitions/ErrorModel"
definitions:
Pet:
type: "object"
allOf:
-
$ref: "#/definitions/NewPet"
-
required:
- "id"
properties:
id:
type: "integer"
format: "int64"
NewPet:
type: "object"
required:
- "name"
properties:
name:
type: "string"
tag:
type: "string"
ErrorModel:
type: "object"
required:
- "code"
- "message"
properties:
code:
type: "integer"
format: "int32"
message:
type: "string"

View File

@ -1,166 +0,0 @@
---
swagger: "2.0"
info:
version: "1.0.0"
title: "Swagger Petstore"
description: "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification"
termsOfService: "http://swagger.io/terms/"
contact:
name: "Swagger API Team"
email: "apiteam@swagger.io"
url: "http://swagger.io"
license:
name: "MIT"
url: "http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT"
externalDocs:
description: "find more info here"
url: "https://swagger.io/about"
host: "petstore.swagger.io"
basePath: "/api"
schemes:
- "http"
consumes:
- "application/json"
produces:
- "application/json"
paths:
/pets:
get:
description: "Returns all pets from the system that the user has access to"
operationId: "findPets"
externalDocs:
description: "find more info here"
url: "https://swagger.io/about"
produces:
- "application/json"
- "application/xml"
- "text/xml"
- "text/html"
parameters:
-
name: "tags"
in: "query"
description: "tags to filter by"
required: false
type: "array"
items:
type: "string"
collectionFormat: "csv"
-
name: "limit"
in: "query"
description: "maximum number of results to return"
required: false
type: "integer"
format: "int32"
responses:
"200":
description: "pet response"
schema:
type: "array"
items:
$ref: "#/definitions/Pet"
default:
description: "unexpected error"
schema:
$ref: "#/definitions/ErrorModel"
post:
description: "Creates a new pet in the store. Duplicates are allowed"
operationId: "addPet"
produces:
- "application/json"
parameters:
-
name: "pet"
in: "body"
description: "Pet to add to the store"
required: true
schema:
$ref: "#/definitions/NewPet"
responses:
"200":
description: "pet response"
schema:
$ref: "#/definitions/Pet"
default:
description: "unexpected error"
schema:
$ref: "#/definitions/ErrorModel"
/pets/{id}:
get:
description: "Returns a user based on a single ID, if the user does not have access to the pet"
operationId: "findPetById"
produces:
- "application/json"
- "application/xml"
- "text/xml"
- "text/html"
parameters:
-
name: "id"
in: "path"
description: "ID of pet to fetch"
required: true
type: "integer"
format: "int64"
responses:
"200":
description: "pet response"
schema:
$ref: "#/definitions/Pet"
default:
description: "unexpected error"
schema:
$ref: "#/definitions/ErrorModel"
delete:
description: "deletes a single pet based on the ID supplied"
operationId: "deletePet"
parameters:
-
name: "id"
in: "path"
description: "ID of pet to delete"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: "pet deleted"
default:
description: "unexpected error"
schema:
$ref: "#/definitions/ErrorModel"
definitions:
Pet:
type: "object"
allOf:
-
$ref: "#/definitions/NewPet"
-
required:
- "id"
properties:
id:
type: "integer"
format: "int64"
NewPet:
type: "object"
required:
- "name"
properties:
name:
type: "string"
tag:
type: "string"
ErrorModel:
type: "object"
required:
- "code"
- "message"
properties:
code:
type: "integer"
format: "int32"
message:
type: "string"

View File

@ -1,101 +0,0 @@
swagger: "2.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
host: petstore.swagger.io
basePath: /v1
schemes:
- http
consumes:
- application/json
produces:
- application/json
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
type: integer
format: int32
responses:
"200":
description: An paged array of pets
headers:
x-next:
type: string
description: A link to the next page of responses
schema:
$ref: '#/definitions/Pets'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
"201":
description: Null response
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
type: string
responses:
"200":
description: Expected response to a valid request
schema:
$ref: '#/definitions/Pets'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
definitions:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: '#/definitions/Pet'
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string

View File

@ -1,273 +0,0 @@
# this is an example of the Uber API
# as a demonstration of an API spec in YAML
swagger: "2.0"
info:
title: Uber API
description: Move your app forward with the Uber API
version: "1.0.0"
# the domain of the service
host: api.uber.com
# array of all schemes that your API supports
schemes:
- https
# will be prefixed to all paths
basePath: /v1
securityDefinitions:
apikey:
type: apiKey
name: server_token
in: query
produces:
- application/json
paths:
/products:
get:
summary: Product Types
description: The Products endpoint returns information about the Uber products offered at a given location. The response includes the display name and other details about each product, and lists the products in the proper display order.
parameters:
- name: latitude
in: query
description: Latitude component of location.
required: true
type: number
format: double
- name: longitude
in: query
description: Longitude component of location.
required: true
type: number
format: double
security:
- apikey: []
tags:
- Products
responses:
"200":
description: An array of products
schema:
type: array
items:
$ref: '#/definitions/Product'
default:
description: Unexpected error
schema:
$ref: '#/definitions/Error'
/estimates/price:
get:
summary: Price Estimates
description: The Price Estimates endpoint returns an estimated price range for each product offered at a given location. The price estimate is provided as a formatted string with the full price range and the localized currency symbol.<br><br>The response also includes low and high estimates, and the [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code for situations requiring currency conversion. When surge is active for a particular product, its surge_multiplier will be greater than 1, but the price estimate already factors in this multiplier.
parameters:
- name: start_latitude
in: query
description: Latitude component of start location.
required: true
type: number
format: double
- name: start_longitude
in: query
description: Longitude component of start location.
required: true
type: number
format: double
- name: end_latitude
in: query
description: Latitude component of end location.
required: true
type: number
format: double
- name: end_longitude
in: query
description: Longitude component of end location.
required: true
type: number
format: double
tags:
- Estimates
responses:
"200":
description: An array of price estimates by product
schema:
type: array
items:
$ref: '#/definitions/PriceEstimate'
default:
description: Unexpected error
schema:
$ref: '#/definitions/Error'
/estimates/time:
get:
summary: Time Estimates
description: The Time Estimates endpoint returns ETAs for all products offered at a given location, with the responses expressed as integers in seconds. We recommend that this endpoint be called every minute to provide the most accurate, up-to-date ETAs.
parameters:
- name: start_latitude
in: query
description: Latitude component of start location.
required: true
type: number
format: double
- name: start_longitude
in: query
description: Longitude component of start location.
required: true
type: number
format: double
- name: customer_uuid
in: query
type: string
format: uuid
description: Unique customer identifier to be used for experience customization.
- name: product_id
in: query
type: string
description: Unique identifier representing a specific product for a given latitude & longitude.
tags:
- Estimates
responses:
"200":
description: An array of products
schema:
type: array
items:
$ref: '#/definitions/Product'
default:
description: Unexpected error
schema:
$ref: '#/definitions/Error'
/me:
get:
summary: User Profile
description: The User Profile endpoint returns information about the Uber user that has authorized with the application.
tags:
- User
responses:
"200":
description: Profile information for a user
schema:
$ref: '#/definitions/Profile'
default:
description: Unexpected error
schema:
$ref: '#/definitions/Error'
/history:
get:
summary: User Activity
description: The User Activity endpoint returns data about a user's lifetime activity with Uber. The response will include pickup locations and times, dropoff locations and times, the distance of past requests, and information about which products were requested.<br><br>The history array in the response will have a maximum length based on the limit parameter. The response value count may exceed limit, therefore subsequent API requests may be necessary.
parameters:
- name: offset
in: query
type: integer
format: int32
description: Offset the list of returned results by this amount. Default is zero.
- name: limit
in: query
type: integer
format: int32
description: Number of items to retrieve. Default is 5, maximum is 100.
tags:
- User
responses:
"200":
description: History information for the given user
schema:
$ref: '#/definitions/Activities'
default:
description: Unexpected error
schema:
$ref: '#/definitions/Error'
definitions:
Product:
properties:
product_id:
type: string
description: Unique identifier representing a specific product for a given latitude & longitude. For example, uberX in San Francisco will have a different product_id than uberX in Los Angeles.
description:
type: string
description: Description of product.
display_name:
type: string
description: Display name of product.
capacity:
type: integer
description: Capacity of product. For example, 4 people.
image:
type: string
description: Image URL representing the product.
ProductList:
properties:
products:
description: Contains the list of products
type: array
items:
$ref: "#/definitions/Product"
PriceEstimate:
properties:
product_id:
type: string
description: Unique identifier representing a specific product for a given latitude & longitude. For example, uberX in San Francisco will have a different product_id than uberX in Los Angeles
currency_code:
type: string
description: "[ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code."
display_name:
type: string
description: Display name of product.
estimate:
type: string
description: Formatted string of estimate in local currency of the start location. Estimate could be a range, a single number (flat rate) or "Metered" for TAXI.
low_estimate:
type: number
description: Lower bound of the estimated price.
high_estimate:
type: number
description: Upper bound of the estimated price.
surge_multiplier:
type: number
description: Expected surge multiplier. Surge is active if surge_multiplier is greater than 1. Price estimate already factors in the surge multiplier.
Profile:
properties:
first_name:
type: string
description: First name of the Uber user.
last_name:
type: string
description: Last name of the Uber user.
email:
type: string
description: Email address of the Uber user
picture:
type: string
description: Image URL of the Uber user.
promo_code:
type: string
description: Promo code of the Uber user.
Activity:
properties:
uuid:
type: string
description: Unique identifier for the activity
Activities:
properties:
offset:
type: integer
format: int32
description: Position in pagination.
limit:
type: integer
format: int32
description: Number of items to retrieve (100 max).
count:
type: integer
format: int32
description: Total number of items available.
history:
type: array
items:
$ref: '#/definitions/Activity'
Error:
properties:
code:
type: integer
format: int32
message:
type: string
fields:
type: string

View File

@ -1,176 +0,0 @@
{
"openapi": "3.0",
"info": {
"version": "1.0.0",
"title": "OpenAPI Petstore",
"license": {
"name": "MIT"
}
},
"servers": [
{
"url": "https://petstore.openapis.org/v1",
"description": "Development server"
}
],
"paths": {
"/pets": {
"get": {
"summary": "List all pets",
"operationId": "listPets",
"tags": [
"pets"
],
"parameters": [
{
"name": "limit",
"in": "query",
"description": "How many items to return at one time (max 100)",
"required": false,
"schema": {
"type": "integer",
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "An paged array of pets",
"headers": {
"x-next": {
"schema": {
"type": "string"
},
"description": "A link to the next page of responses"
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Pets"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
},
"post": {
"summary": "Create a pet",
"operationId": "createPets",
"tags": [
"pets"
],
"responses": {
"201": {
"description": "Null response"
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/pets/{petId}": {
"get": {
"summary": "Info for a specific pet",
"operationId": "showPetById",
"tags": [
"pets"
],
"parameters": [
{
"name": "petId",
"in": "path",
"required": true,
"description": "The id of the pet to retrieve",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Expected response to a valid request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Pets"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Pet": {
"required": [
"id",
"name"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"name": {
"type": "string"
},
"tag": {
"type": "string"
}
}
},
"Pets": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Pet"
}
},
"Error": {
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
}
}
}
}
}

View File

@ -1,110 +0,0 @@
openapi: "3.0"
info:
version: 1.0.0
title: OpenAPI Petstore
license:
name: MIT
servers:
- url: https://petstore.openapis.org/v1
description: Development server
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int32
responses:
"200":
description: An paged array of pets
headers:
x-next:
schema:
type: string
description: A link to the next page of responses
content:
application/json:
schema:
$ref: '#/components/schemas/Pets'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
"201":
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
type: string
responses:
"200":
description: Expected response to a valid request
content:
application/json:
schema:
$ref: '#/components/schemas/Pets'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: '#/components/schemas/Pet'
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string

View File

@ -1,5 +0,0 @@
go get github.com/golang/protobuf/protoc-gen-go
protoc \
--go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. *.proto

View File

@ -1,5 +0,0 @@
# Extensions
This directory contains support code for building Gnostic extensions and associated examples.
Extensions are used to compile vendor or specification extensions into protocol buffer structures.

View File

@ -1,93 +0,0 @@
// 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.
syntax = "proto3";
import "google/protobuf/any.proto";
package openapiextension.v1;
// This option lets the proto compiler generate Java code inside the package
// name (see below) instead of inside an outer class. It creates a simpler
// developer experience by reducing one-level of name nesting and be
// consistent with most programming languages that don't support outer classes.
option java_multiple_files = true;
// The Java outer classname should be the filename in UpperCamelCase. This
// class is only used to hold proto descriptor, so developers don't need to
// work with it directly.
option java_outer_classname = "OpenAPIExtensionV1";
// The Java package name must be proto package name with proper prefix.
option java_package = "org.gnostic.v1";
// A reasonable prefix for the Objective-C symbols generated from the package.
// It should at a minimum be 3 characters long, all uppercase, and convention
// is to use an abbreviation of the package name. Something short, but
// hopefully unique enough to not conflict with things that may come along in
// the future. 'GPB' is reserved for the protocol buffer implementation itself.
//
option objc_class_prefix = "OAE"; // "OpenAPI Extension"
// The version number of OpenAPI compiler.
message Version {
int32 major = 1;
int32 minor = 2;
int32 patch = 3;
// A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should
// be empty for mainline stable releases.
string suffix = 4;
}
// An encoded Request is written to the ExtensionHandler's stdin.
message ExtensionHandlerRequest {
// The OpenAPI descriptions that were explicitly listed on the command line.
// The specifications will appear in the order they are specified to gnostic.
Wrapper wrapper = 1;
// The version number of openapi compiler.
Version compiler_version = 3;
}
// The extensions writes an encoded ExtensionHandlerResponse to stdout.
message ExtensionHandlerResponse {
// true if the extension is handled by the extension handler; false otherwise
bool handled = 1;
// Error message. If non-empty, the extension handling failed.
// The extension handler process should exit with status code zero
// even if it reports an error in this way.
//
// This should be used to indicate errors which prevent the extension from
// operating as intended. Errors which indicate a problem in gnostic
// itself -- such as the input Document being unparseable -- should be
// reported by writing a message to stderr and exiting with a non-zero
// status code.
repeated string error = 2;
// text output
google.protobuf.Any value = 3;
}
message Wrapper {
// version of the OpenAPI specification in which this extension was written.
string version = 1;
// Name of the extension
string extension_name = 2;
// Must be a valid yaml for the proto
string yaml = 3;
}

View File

@ -1,10 +0,0 @@
build:
go get github.com/golang/protobuf/protoc-gen-go
cd ..; ./COMPILE-EXTENSION.sh
generate-gnostic --extension x-sampleone.json --out_dir=$(GOPATH)/src/github.com/googleapis/gnostic/extensions/sample/generated
cd generated/gnostic-x-sampleone/proto; protoc --go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. *.proto
cd generated/gnostic-x-sampleone; go get; go install
generate-gnostic --extension x-sampletwo.json --out_dir=$(GOPATH)/src/github.com/googleapis/gnostic/extensions/sample/generated
cd generated/gnostic-x-sampletwo/proto; protoc --go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. *.proto
cd generated/gnostic-x-sampletwo; go get; go install

View File

@ -1,55 +0,0 @@
{
"definitions": {
"Book": {
"type": "object",
"id": "x-sampleone-book",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "integer"
}
}
},
"Shelf": {
"type": "object",
"id": "x-sampleone-shelf",
"required": [
"foo1",
"bar"
],
"properties": {
"foo1": {
"type": "integer",
"format": "int32"
},
"bar": {
"type": "integer"
}
}
},
"PrimitiveString": {
"type": "string",
"id": "x-sampleone-mysimplestring"
},
"PrimitiveNumber": {
"type": "number",
"id": "x-sampleone-mysimplenumber"
},
"PrimitiveBoolean": {
"type": "boolean",
"id": "x-sampleone-mysimpleboolean"
},
"PrimitiveInt64": {
"type": "string",
"id": "x-sampleone-mysimpleint64"
}
}
}

View File

@ -1,38 +0,0 @@
{
"definitions": {
"Book": {
"type": "object",
"id": "x-sampletwo-book",
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "integer"
}
}
},
"Shelf": {
"type": "object",
"id": "x-sampletwo-shelf",
"required": [
"foo1",
"bar"
],
"properties": {
"foo1": {
"type": "integer",
"format": "int32"
},
"bar": {
"type": "integer"
}
}
}
}
}

View File

@ -1,13 +0,0 @@
# generate-gnostic
## The gnostic compiler generator
This directory contains code that generates a protocol buffer
representation and supporting code for a JSON schema.
It is currently used to build models of OpenAPI specifications
and extensions which are described as "vendor extensions" in
OpenAPI 2.0 and "specification extensions" in OpenAPI 3.0.
For usage information, run the `generate-gnostic` binary with no
options.

View File

@ -1,624 +0,0 @@
// 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"
"log"
"sort"
"strings"
"github.com/googleapis/gnostic/jsonschema"
)
// Domain models a collection of types that is defined by a schema.
type Domain struct {
TypeModels map[string]*TypeModel // models of the types in the domain
Prefix string // type prefix to use
Schema *jsonschema.Schema // top-level schema
TypeNameOverrides map[string]string // a configured mapping from patterns to type names
PropertyNameOverrides map[string]string // a configured mapping from patterns to property names
ObjectTypeRequests map[string]*TypeRequest // anonymous types implied by type instantiation
MapTypeRequests map[string]string // "NamedObject" types that will be used to implement ordered maps
Version string // OpenAPI Version ("v2" or "v3")
}
// NewDomain creates a domain representation.
func NewDomain(schema *jsonschema.Schema, version string) *Domain {
cc := &Domain{}
cc.TypeModels = make(map[string]*TypeModel, 0)
cc.TypeNameOverrides = make(map[string]string, 0)
cc.PropertyNameOverrides = make(map[string]string, 0)
cc.ObjectTypeRequests = make(map[string]*TypeRequest, 0)
cc.MapTypeRequests = make(map[string]string, 0)
cc.Schema = schema
cc.Version = version
return cc
}
// TypeNameForStub returns a capitalized name to use for a generated type.
func (domain *Domain) TypeNameForStub(stub string) string {
return domain.Prefix + strings.ToUpper(stub[0:1]) + stub[1:len(stub)]
}
// typeNameForReference returns a capitalized name to use for a generated type based on a JSON reference
func (domain *Domain) typeNameForReference(reference string) string {
parts := strings.Split(reference, "/")
first := parts[0]
last := parts[len(parts)-1]
if first == "#" {
return domain.TypeNameForStub(last)
}
return "Schema"
}
// propertyNameForReference returns a property name to use for a JSON reference
func (domain *Domain) propertyNameForReference(reference string) *string {
parts := strings.Split(reference, "/")
first := parts[0]
last := parts[len(parts)-1]
if first == "#" {
return &last
}
return nil
}
// arrayItemTypeForSchema determines the item type for arrays defined by a schema
func (domain *Domain) arrayItemTypeForSchema(propertyName string, schema *jsonschema.Schema) string {
// default
itemTypeName := "Any"
if schema.Items != nil {
if schema.Items.SchemaArray != nil {
if len(*(schema.Items.SchemaArray)) > 0 {
ref := (*schema.Items.SchemaArray)[0].Ref
if ref != nil {
itemTypeName = domain.typeNameForReference(*ref)
} else {
types := (*schema.Items.SchemaArray)[0].Type
if types == nil {
// do nothing
} else if (types.StringArray != nil) && len(*(types.StringArray)) == 1 {
itemTypeName = (*types.StringArray)[0]
} else if (types.StringArray != nil) && len(*(types.StringArray)) > 1 {
itemTypeName = fmt.Sprintf("%+v", types.StringArray)
} else if types.String != nil {
itemTypeName = *(types.String)
} else {
itemTypeName = "UNKNOWN"
}
}
}
} else if schema.Items.Schema != nil {
types := schema.Items.Schema.Type
if schema.Items.Schema.Ref != nil {
itemTypeName = domain.typeNameForReference(*schema.Items.Schema.Ref)
} else if schema.Items.Schema.OneOf != nil {
// this type is implied by the "oneOf"
itemTypeName = domain.TypeNameForStub(propertyName + "Item")
domain.ObjectTypeRequests[itemTypeName] =
NewTypeRequest(itemTypeName, propertyName, schema.Items.Schema)
} else if types == nil {
// do nothing
} else if (types.StringArray != nil) && len(*(types.StringArray)) == 1 {
itemTypeName = (*types.StringArray)[0]
} else if (types.StringArray != nil) && len(*(types.StringArray)) > 1 {
itemTypeName = fmt.Sprintf("%+v", types.StringArray)
} else if types.String != nil {
itemTypeName = *(types.String)
} else {
itemTypeName = "UNKNOWN"
}
}
}
return itemTypeName
}
func (domain *Domain) buildTypeProperties(typeModel *TypeModel, schema *jsonschema.Schema) {
if schema.Properties != nil {
for _, pair := range *(schema.Properties) {
propertyName := pair.Name
propertySchema := pair.Value
if propertySchema.Ref != nil {
// the property schema is a reference, so we will add a property with the type of the referenced schema
propertyTypeName := domain.typeNameForReference(*(propertySchema.Ref))
typeProperty := NewTypeProperty()
typeProperty.Name = propertyName
typeProperty.Type = propertyTypeName
typeModel.addProperty(typeProperty)
} else if propertySchema.Type != nil {
// the property schema specifies a type, so add a property with the specified type
if propertySchema.TypeIs("string") {
typeProperty := NewTypePropertyWithNameAndType(propertyName, "string")
if propertySchema.Description != nil {
typeProperty.Description = *propertySchema.Description
}
if propertySchema.Enumeration != nil {
allowedValues := make([]string, 0)
for _, enumValue := range *propertySchema.Enumeration {
if enumValue.String != nil {
allowedValues = append(allowedValues, *enumValue.String)
}
}
typeProperty.StringEnumValues = allowedValues
}
typeModel.addProperty(typeProperty)
} else if propertySchema.TypeIs("boolean") {
typeProperty := NewTypePropertyWithNameAndType(propertyName, "bool")
if propertySchema.Description != nil {
typeProperty.Description = *propertySchema.Description
}
typeModel.addProperty(typeProperty)
} else if propertySchema.TypeIs("number") {
typeProperty := NewTypePropertyWithNameAndType(propertyName, "float")
if propertySchema.Description != nil {
typeProperty.Description = *propertySchema.Description
}
typeModel.addProperty(typeProperty)
} else if propertySchema.TypeIs("integer") {
typeProperty := NewTypePropertyWithNameAndType(propertyName, "int")
if propertySchema.Description != nil {
typeProperty.Description = *propertySchema.Description
}
typeModel.addProperty(typeProperty)
} else if propertySchema.TypeIs("object") {
// the property has an "anonymous" object schema, so define a new type for it and request its creation
anonymousObjectTypeName := domain.TypeNameForStub(propertyName)
domain.ObjectTypeRequests[anonymousObjectTypeName] =
NewTypeRequest(anonymousObjectTypeName, propertyName, propertySchema)
// add a property with the type of the requested type
typeProperty := NewTypePropertyWithNameAndType(propertyName, anonymousObjectTypeName)
if propertySchema.Description != nil {
typeProperty.Description = *propertySchema.Description
}
typeModel.addProperty(typeProperty)
} else if propertySchema.TypeIs("array") {
// the property has an array type, so define it as a repeated property of the specified type
propertyTypeName := domain.arrayItemTypeForSchema(propertyName, propertySchema)
typeProperty := NewTypePropertyWithNameAndType(propertyName, propertyTypeName)
typeProperty.Repeated = true
if propertySchema.Description != nil {
typeProperty.Description = *propertySchema.Description
}
if typeProperty.Type == "string" {
itemSchema := propertySchema.Items.Schema
if itemSchema != nil {
if itemSchema.Enumeration != nil {
allowedValues := make([]string, 0)
for _, enumValue := range *itemSchema.Enumeration {
if enumValue.String != nil {
allowedValues = append(allowedValues, *enumValue.String)
}
}
typeProperty.StringEnumValues = allowedValues
}
}
}
typeModel.addProperty(typeProperty)
} else {
log.Printf("ignoring %+v, which has an unsupported property type '%s'", propertyName, propertySchema.Type.Description())
}
} else if propertySchema.IsEmpty() {
// an empty schema can contain anything, so add an accessor for a generic object
typeName := "Any"
typeProperty := NewTypePropertyWithNameAndType(propertyName, typeName)
typeModel.addProperty(typeProperty)
} else if propertySchema.OneOf != nil {
anonymousObjectTypeName := domain.TypeNameForStub(propertyName + "Item")
domain.ObjectTypeRequests[anonymousObjectTypeName] =
NewTypeRequest(anonymousObjectTypeName, propertyName, propertySchema)
typeProperty := NewTypePropertyWithNameAndType(propertyName, anonymousObjectTypeName)
typeModel.addProperty(typeProperty)
} else if propertySchema.AnyOf != nil {
anonymousObjectTypeName := domain.TypeNameForStub(propertyName + "Item")
domain.ObjectTypeRequests[anonymousObjectTypeName] =
NewTypeRequest(anonymousObjectTypeName, propertyName, propertySchema)
typeProperty := NewTypePropertyWithNameAndType(propertyName, anonymousObjectTypeName)
typeModel.addProperty(typeProperty)
} else {
log.Printf("ignoring %s.%s, which has an unrecognized schema:\n%+v", typeModel.Name, propertyName, propertySchema.String())
}
}
}
}
func (domain *Domain) buildTypeRequirements(typeModel *TypeModel, schema *jsonschema.Schema) {
if schema.Required != nil {
typeModel.Required = (*schema.Required)
}
}
func (domain *Domain) buildPatternPropertyAccessors(typeModel *TypeModel, schema *jsonschema.Schema) {
if schema.PatternProperties != nil {
typeModel.OpenPatterns = make([]string, 0)
for _, pair := range *(schema.PatternProperties) {
propertyPattern := pair.Name
propertySchema := pair.Value
typeModel.OpenPatterns = append(typeModel.OpenPatterns, propertyPattern)
if propertySchema.Ref != nil {
typeName := domain.typeNameForReference(*propertySchema.Ref)
if _, ok := domain.TypeNameOverrides[typeName]; ok {
typeName = domain.TypeNameOverrides[typeName]
}
propertyName := domain.typeNameForReference(*propertySchema.Ref)
if _, ok := domain.PropertyNameOverrides[propertyName]; ok {
propertyName = domain.PropertyNameOverrides[propertyName]
}
propertyTypeName := fmt.Sprintf("Named%s", typeName)
property := NewTypePropertyWithNameTypeAndPattern(propertyName, propertyTypeName, propertyPattern)
property.Implicit = true
property.MapType = typeName
property.Repeated = true
domain.MapTypeRequests[property.MapType] = property.MapType
typeModel.addProperty(property)
}
}
}
}
func (domain *Domain) buildAdditionalPropertyAccessors(typeModel *TypeModel, schema *jsonschema.Schema) {
if schema.AdditionalProperties != nil {
if schema.AdditionalProperties.Boolean != nil {
if *schema.AdditionalProperties.Boolean == true {
typeModel.Open = true
propertyName := "additionalProperties"
typeName := "NamedAny"
property := NewTypePropertyWithNameAndType(propertyName, typeName)
property.Implicit = true
property.MapType = "Any"
property.Repeated = true
domain.MapTypeRequests[property.MapType] = property.MapType
typeModel.addProperty(property)
return
}
} else if schema.AdditionalProperties.Schema != nil {
typeModel.Open = true
schema := schema.AdditionalProperties.Schema
if schema.Ref != nil {
propertyName := "additionalProperties"
mapType := domain.typeNameForReference(*schema.Ref)
typeName := fmt.Sprintf("Named%s", mapType)
property := NewTypePropertyWithNameAndType(propertyName, typeName)
property.Implicit = true
property.MapType = mapType
property.Repeated = true
domain.MapTypeRequests[property.MapType] = property.MapType
typeModel.addProperty(property)
return
} else if schema.Type != nil {
typeName := *schema.Type.String
if typeName == "string" {
propertyName := "additionalProperties"
typeName := "NamedString"
property := NewTypePropertyWithNameAndType(propertyName, typeName)
property.Implicit = true
property.MapType = "string"
property.Repeated = true
domain.MapTypeRequests[property.MapType] = property.MapType
typeModel.addProperty(property)
return
} else if typeName == "array" {
if schema.Items != nil {
itemType := *schema.Items.Schema.Type.String
if itemType == "string" {
propertyName := "additionalProperties"
typeName := "NamedStringArray"
property := NewTypePropertyWithNameAndType(propertyName, typeName)
property.Implicit = true
property.MapType = "StringArray"
property.Repeated = true
domain.MapTypeRequests[property.MapType] = property.MapType
typeModel.addProperty(property)
return
}
}
}
} else if schema.OneOf != nil {
propertyTypeName := domain.TypeNameForStub(typeModel.Name + "Item")
propertyName := "additionalProperties"
typeName := fmt.Sprintf("Named%s", propertyTypeName)
property := NewTypePropertyWithNameAndType(propertyName, typeName)
property.Implicit = true
property.MapType = propertyTypeName
property.Repeated = true
domain.MapTypeRequests[property.MapType] = property.MapType
typeModel.addProperty(property)
domain.ObjectTypeRequests[propertyTypeName] =
NewTypeRequest(propertyTypeName, propertyName, schema)
}
}
}
}
func (domain *Domain) buildOneOfAccessors(typeModel *TypeModel, schema *jsonschema.Schema) {
oneOfs := schema.OneOf
if oneOfs == nil {
return
}
typeModel.Open = true
typeModel.OneOfWrapper = true
for _, oneOf := range *oneOfs {
if oneOf.Ref != nil {
ref := *oneOf.Ref
typeName := domain.typeNameForReference(ref)
propertyName := domain.propertyNameForReference(ref)
if propertyName != nil {
typeProperty := NewTypePropertyWithNameAndType(*propertyName, typeName)
typeModel.addProperty(typeProperty)
}
} else if oneOf.Type != nil && oneOf.Type.String != nil {
switch *oneOf.Type.String {
case "boolean":
typeProperty := NewTypePropertyWithNameAndType("boolean", "bool")
typeModel.addProperty(typeProperty)
case "integer":
typeProperty := NewTypePropertyWithNameAndType("integer", "int")
typeModel.addProperty(typeProperty)
case "number":
typeProperty := NewTypePropertyWithNameAndType("number", "float")
typeModel.addProperty(typeProperty)
case "string":
typeProperty := NewTypePropertyWithNameAndType("string", "string")
typeModel.addProperty(typeProperty)
default:
log.Printf("Unsupported oneOf:\n%+v", oneOf.String())
}
} else {
log.Printf("Unsupported oneOf:\n%+v", oneOf.String())
}
}
}
func schemaIsContainedInArray(s1 *jsonschema.Schema, s2 *jsonschema.Schema) bool {
if s2.TypeIs("array") {
if s2.Items.Schema != nil {
if s1.IsEqual(s2.Items.Schema) {
return true
}
}
}
return false
}
func (domain *Domain) addAnonymousAccessorForSchema(
typeModel *TypeModel,
schema *jsonschema.Schema,
repeated bool) {
ref := schema.Ref
if ref != nil {
typeName := domain.typeNameForReference(*ref)
propertyName := domain.propertyNameForReference(*ref)
if propertyName != nil {
property := NewTypePropertyWithNameAndType(*propertyName, typeName)
property.Repeated = true
typeModel.addProperty(property)
typeModel.IsItemArray = true
}
} else {
typeName := "string"
propertyName := "value"
property := NewTypePropertyWithNameAndType(propertyName, typeName)
property.Repeated = true
typeModel.addProperty(property)
typeModel.IsStringArray = true
}
}
func (domain *Domain) buildAnyOfAccessors(typeModel *TypeModel, schema *jsonschema.Schema) {
anyOfs := schema.AnyOf
if anyOfs == nil {
return
}
if len(*anyOfs) == 2 {
if schemaIsContainedInArray((*anyOfs)[0], (*anyOfs)[1]) {
//log.Printf("ARRAY OF %+v", (*anyOfs)[0].String())
schema := (*anyOfs)[0]
domain.addAnonymousAccessorForSchema(typeModel, schema, true)
} else if schemaIsContainedInArray((*anyOfs)[1], (*anyOfs)[0]) {
//log.Printf("ARRAY OF %+v", (*anyOfs)[1].String())
schema := (*anyOfs)[1]
domain.addAnonymousAccessorForSchema(typeModel, schema, true)
} else {
for _, anyOf := range *anyOfs {
ref := anyOf.Ref
if ref != nil {
typeName := domain.typeNameForReference(*ref)
propertyName := domain.propertyNameForReference(*ref)
if propertyName != nil {
property := NewTypePropertyWithNameAndType(*propertyName, typeName)
typeModel.addProperty(property)
}
} else {
typeName := "bool"
propertyName := "boolean"
property := NewTypePropertyWithNameAndType(propertyName, typeName)
typeModel.addProperty(property)
}
}
}
} else {
log.Printf("Unhandled anyOfs:\n%s", schema.String())
}
}
func (domain *Domain) buildDefaultAccessors(typeModel *TypeModel, schema *jsonschema.Schema) {
typeModel.Open = true
propertyName := "additionalProperties"
typeName := "NamedAny"
property := NewTypePropertyWithNameAndType(propertyName, typeName)
property.MapType = "Any"
property.Repeated = true
domain.MapTypeRequests[property.MapType] = property.MapType
typeModel.addProperty(property)
}
// BuildTypeForDefinition creates a type representation for a schema definition.
func (domain *Domain) BuildTypeForDefinition(
typeName string,
propertyName string,
schema *jsonschema.Schema) *TypeModel {
if (schema.Type == nil) || (*schema.Type.String == "object") {
return domain.buildTypeForDefinitionObject(typeName, propertyName, schema)
}
return nil
}
func (domain *Domain) buildTypeForDefinitionObject(
typeName string,
propertyName string,
schema *jsonschema.Schema) *TypeModel {
typeModel := NewTypeModel()
typeModel.Name = typeName
if schema.IsEmpty() {
domain.buildDefaultAccessors(typeModel, schema)
} else {
if schema.Description != nil {
typeModel.Description = *schema.Description
}
domain.buildTypeProperties(typeModel, schema)
domain.buildTypeRequirements(typeModel, schema)
domain.buildPatternPropertyAccessors(typeModel, schema)
domain.buildAdditionalPropertyAccessors(typeModel, schema)
domain.buildOneOfAccessors(typeModel, schema)
domain.buildAnyOfAccessors(typeModel, schema)
}
return typeModel
}
// Build builds a domain model.
func (domain *Domain) Build() (err error) {
if (domain.Schema == nil) || (domain.Schema.Definitions == nil) {
return errors.New("missing definitions section")
}
// create a type for the top-level schema
typeName := domain.Prefix + "Document"
typeModel := NewTypeModel()
typeModel.Name = typeName
domain.buildTypeProperties(typeModel, domain.Schema)
domain.buildTypeRequirements(typeModel, domain.Schema)
domain.buildPatternPropertyAccessors(typeModel, domain.Schema)
domain.buildAdditionalPropertyAccessors(typeModel, domain.Schema)
domain.buildOneOfAccessors(typeModel, domain.Schema)
domain.buildAnyOfAccessors(typeModel, domain.Schema)
if len(typeModel.Properties) > 0 {
domain.TypeModels[typeName] = typeModel
}
// create a type for each object defined in the schema
if domain.Schema.Definitions != nil {
for _, pair := range *(domain.Schema.Definitions) {
definitionName := pair.Name
definitionSchema := pair.Value
typeName := domain.TypeNameForStub(definitionName)
typeModel := domain.BuildTypeForDefinition(typeName, definitionName, definitionSchema)
if typeModel != nil {
domain.TypeModels[typeName] = typeModel
}
}
}
// iterate over anonymous object types to be instantiated and generate a type for each
for typeName, typeRequest := range domain.ObjectTypeRequests {
domain.TypeModels[typeRequest.Name] =
domain.buildTypeForDefinitionObject(typeName, typeRequest.PropertyName, typeRequest.Schema)
}
// iterate over map item types to be instantiated and generate a type for each
mapTypeNames := make([]string, 0)
for mapTypeName := range domain.MapTypeRequests {
mapTypeNames = append(mapTypeNames, mapTypeName)
}
sort.Strings(mapTypeNames)
for _, mapTypeName := range mapTypeNames {
typeName := "Named" + strings.Title(mapTypeName)
typeModel := NewTypeModel()
typeModel.Name = typeName
typeModel.Description = fmt.Sprintf(
"Automatically-generated message used to represent maps of %s as ordered (name,value) pairs.",
mapTypeName)
typeModel.IsPair = true
typeModel.PairValueType = mapTypeName
nameProperty := NewTypeProperty()
nameProperty.Name = "name"
nameProperty.Type = "string"
nameProperty.Description = "Map key"
typeModel.addProperty(nameProperty)
valueProperty := NewTypeProperty()
valueProperty.Name = "value"
valueProperty.Type = mapTypeName
valueProperty.Description = "Mapped value"
typeModel.addProperty(valueProperty)
domain.TypeModels[typeName] = typeModel
}
// add a type for string arrays
stringArrayType := NewTypeModel()
stringArrayType.Name = "StringArray"
stringProperty := NewTypeProperty()
stringProperty.Name = "value"
stringProperty.Type = "string"
stringProperty.Repeated = true
stringArrayType.addProperty(stringProperty)
domain.TypeModels[stringArrayType.Name] = stringArrayType
// add a type for "Any"
anyType := NewTypeModel()
anyType.Name = "Any"
anyType.Open = true
anyType.IsBlob = true
valueProperty := NewTypeProperty()
valueProperty.Name = "value"
valueProperty.Type = "google.protobuf.Any"
anyType.addProperty(valueProperty)
yamlProperty := NewTypeProperty()
yamlProperty.Name = "yaml"
yamlProperty.Type = "string"
anyType.addProperty(yamlProperty)
domain.TypeModels[anyType.Name] = anyType
return err
}
func (domain *Domain) sortedTypeNames() []string {
typeNames := make([]string, 0)
for typeName := range domain.TypeModels {
typeNames = append(typeNames, typeName)
}
sort.Strings(typeNames)
return typeNames
}
// Description returns a string representation of a domain.
func (domain *Domain) Description() string {
typeNames := domain.sortedTypeNames()
result := ""
for _, typeName := range typeNames {
result += domain.TypeModels[typeName].description()
}
return result
}

View File

@ -1,913 +0,0 @@
// 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 (
"fmt"
"regexp"
"sort"
"strings"
"github.com/googleapis/gnostic/printer"
)
// patternNames hands out unique names for a given string.
type patternNames struct {
prefix string
values map[string]int
last int
specialCase map[string]func(variable string) string
}
// SpecialCaseExpression returns true if the provided regex can be inlined as a faster
// expression.
func (p *patternNames) SpecialCaseExpression(value, variable string) (code string, ok bool) {
fn, ok := p.specialCase[value]
if !ok {
return "", false
}
return fn(variable), ok
}
// VariableName returns the variable name for the given value.
func (p *patternNames) VariableName(value string) string {
num, ok := p.values[value]
if !ok {
if p.values == nil {
p.values = make(map[string]int)
}
num = p.last
p.last++
p.values[value] = num
}
return fmt.Sprintf("%s%d", p.prefix, num)
}
func (p *patternNames) Names() map[string]string {
names := make(map[string]string)
for value, num := range p.values {
names[fmt.Sprintf("%s%d", p.prefix, num)] = value
}
return names
}
// GenerateCompiler generates the compiler code for a domain.
func (domain *Domain) GenerateCompiler(packageName string, license string, imports []string) string {
code := &printer.Code{}
code.Print(license)
code.Print("// THIS FILE IS AUTOMATICALLY GENERATED.\n")
// generate package declaration
code.Print("package %s\n", packageName)
code.Print("import (")
for _, filename := range imports {
code.Print("\"" + filename + "\"")
}
code.Print(")\n")
// generate a simple Version() function
code.Print("// Version returns the package name (and OpenAPI version).")
code.Print("func Version() string {")
code.Print(" return \"%s\"", packageName)
code.Print("}\n")
typeNames := domain.sortedTypeNames()
regexPatterns := &patternNames{
prefix: "pattern",
specialCase: map[string]func(string) string{
"^x-": func(variable string) string { return fmt.Sprintf("strings.HasPrefix(%s, \"x-\")", variable) },
"^/": func(variable string) string { return fmt.Sprintf("strings.HasPrefix(%s, \"/\")", variable) },
"^": func(_ string) string { return "true" },
},
}
// generate NewX() constructor functions for each type
for _, typeName := range typeNames {
domain.generateConstructorForType(code, typeName, regexPatterns)
}
// generate ResolveReferences() methods for each type
for _, typeName := range typeNames {
domain.generateResolveReferencesMethodsForType(code, typeName)
}
// generate ToRawInfo() methods for each type
for _, typeName := range typeNames {
domain.generateToRawInfoMethodForType(code, typeName)
}
domain.generateConstantVariables(code, regexPatterns)
return code.String()
}
func escapeSlashes(pattern string) string {
return strings.Replace(pattern, "\\", "\\\\", -1)
}
var subpatternPattern = regexp.MustCompile("^.*(\\{.*\\}).*$")
func nameForPattern(regexPatterns *patternNames, pattern string) string {
if !strings.HasPrefix(pattern, "^") {
if matches := subpatternPattern.FindStringSubmatch(pattern); matches != nil {
match := string(matches[1])
pattern = strings.Replace(pattern, match, ".*", -1)
}
}
return regexPatterns.VariableName(pattern)
}
func (domain *Domain) generateConstructorForType(code *printer.Code, typeName string, regexPatterns *patternNames) {
code.Print("// New%s creates an object of type %s if possible, returning an error if not.", typeName, typeName)
code.Print("func New%s(in interface{}, context *compiler.Context) (*%s, error) {", typeName, typeName)
code.Print("errors := make([]error, 0)")
typeModel := domain.TypeModels[typeName]
parentTypeName := typeName
if typeModel.IsStringArray {
code.Print("x := &TypeItem{}")
code.Print("switch in := in.(type) {")
code.Print("case string:")
code.Print(" x.Value = make([]string, 0)")
code.Print(" x.Value = append(x.Value, in)")
code.Print("case []interface{}:")
code.Print(" x.Value = make([]string, 0)")
code.Print(" for _, v := range in {")
code.Print(" value, ok := v.(string)")
code.Print(" if ok {")
code.Print(" x.Value = append(x.Value, value)")
code.Print(" } else {")
code.Print(" message := fmt.Sprintf(\"has unexpected value for string array element: %%+v (%%T)\", value, value)")
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print(" }")
code.Print(" }")
code.Print("default:")
code.Print(" message := fmt.Sprintf(\"has unexpected value for string array: %%+v (%%T)\", in, in)")
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print("}")
} else if typeModel.IsItemArray {
if domain.Version == "v2" {
code.Print("x := &ItemsItem{}")
code.Print("m, ok := compiler.UnpackMap(in)")
code.Print("if !ok {")
code.Print(" message := fmt.Sprintf(\"has unexpected value for item array: %%+v (%%T)\", in, in)")
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print("} else {")
code.Print(" x.Schema = make([]*Schema, 0)")
code.Print(" y, err := NewSchema(m, compiler.NewContext(\"<array>\", context))")
code.Print(" if err != nil {")
code.Print(" return nil, err")
code.Print(" }")
code.Print(" x.Schema = append(x.Schema, y)")
code.Print("}")
} else if domain.Version == "v3" {
code.Print("x := &ItemsItem{}")
code.Print("m, ok := compiler.UnpackMap(in)")
code.Print("if !ok {")
code.Print(" message := fmt.Sprintf(\"has unexpected value for item array: %%+v (%%T)\", in, in)")
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print("} else {")
code.Print(" x.SchemaOrReference = make([]*SchemaOrReference, 0)")
code.Print(" y, err := NewSchemaOrReference(m, compiler.NewContext(\"<array>\", context))")
code.Print(" if err != nil {")
code.Print(" return nil, err")
code.Print(" }")
code.Print(" x.SchemaOrReference = append(x.SchemaOrReference, y)")
code.Print("}")
}
} else if typeModel.IsBlob {
code.Print("x := &Any{}")
code.Print("bytes, _ := yaml.Marshal(in)")
code.Print("x.Yaml = string(bytes)")
} else if typeModel.Name == "StringArray" {
code.Print("x := &StringArray{}")
code.Print("a, ok := in.([]interface{})")
code.Print("if !ok {")
code.Print(" message := fmt.Sprintf(\"has unexpected value for StringArray: %%+v (%%T)\", in, in)")
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print("} else {")
code.Print(" x.Value = make([]string, 0)")
code.Print(" for _, s := range a {")
code.Print(" x.Value = append(x.Value, s.(string))")
code.Print(" }")
code.Print("}")
} else if typeModel.Name == "Primitive" {
code.Print(" x := &Primitive{}")
code.Print(" matched := false")
code.Print(" switch in := in.(type) {")
code.Print(" case bool:")
code.Print(" x.Oneof = &Primitive_Boolean{Boolean: in}")
code.Print(" matched = true")
code.Print(" case string:")
code.Print(" x.Oneof = &Primitive_String_{String_: in}")
code.Print(" matched = true")
code.Print(" case int64:")
code.Print(" x.Oneof = &Primitive_Integer{Integer: in}")
code.Print(" matched = true")
code.Print(" case int32:")
code.Print(" x.Oneof = &Primitive_Integer{Integer: int64(in)}")
code.Print(" matched = true")
code.Print(" case int:")
code.Print(" x.Oneof = &Primitive_Integer{Integer: int64(in)}")
code.Print(" matched = true")
code.Print(" case float64:")
code.Print(" x.Oneof = &Primitive_Number{Number: in}")
code.Print(" matched = true")
code.Print(" case float32:")
code.Print(" x.Oneof = &Primitive_Number{Number: float64(in)}")
code.Print(" matched = true")
code.Print(" }")
code.Print(" if matched {")
code.Print(" // since the oneof matched one of its possibilities, discard any matching errors")
code.Print(" errors = make([]error, 0)")
code.Print(" }")
} else if typeModel.Name == "SpecificationExtension" {
code.Print(" x := &SpecificationExtension{}")
code.Print(" matched := false")
code.Print(" switch in := in.(type) {")
code.Print(" case bool:")
code.Print(" x.Oneof = &SpecificationExtension_Boolean{Boolean: in}")
code.Print(" matched = true")
code.Print(" case string:")
code.Print(" x.Oneof = &SpecificationExtension_String_{String_: in}")
code.Print(" matched = true")
code.Print(" case int64:")
code.Print(" x.Oneof = &SpecificationExtension_Number{Number: float64(in)}")
code.Print(" matched = true")
code.Print(" case int32:")
code.Print(" x.Oneof = &SpecificationExtension_Number{Number: float64(in)}")
code.Print(" matched = true")
code.Print(" case int:")
code.Print(" x.Oneof = &SpecificationExtension_Number{Number: float64(in)}")
code.Print(" matched = true")
code.Print(" case float64:")
code.Print(" x.Oneof = &SpecificationExtension_Number{Number: in}")
code.Print(" matched = true")
code.Print(" case float32:")
code.Print(" x.Oneof = &SpecificationExtension_Number{Number: float64(in)}")
code.Print(" matched = true")
code.Print(" }")
code.Print(" if matched {")
code.Print(" // since the oneof matched one of its possibilities, discard any matching errors")
code.Print(" errors = make([]error, 0)")
code.Print(" }")
} else if typeModel.Name == "DefaultType" {
code.Print(" x := &DefaultType{}")
code.Print(" matched := false")
code.Print(" switch in := in.(type) {")
code.Print(" case bool:")
code.Print(" x.Oneof = &DefaultType_Boolean{Boolean: in}")
code.Print(" matched = true")
code.Print(" case string:")
code.Print(" x.Oneof = &DefaultType_String_{String_: in}")
code.Print(" matched = true")
code.Print(" case int64:")
code.Print(" x.Oneof = &DefaultType_Number{Number: float64(in)}")
code.Print(" matched = true")
code.Print(" case int32:")
code.Print(" x.Oneof = &DefaultType_Number{Number: float64(in)}")
code.Print(" matched = true")
code.Print(" case int:")
code.Print(" x.Oneof = &DefaultType_Number{Number: float64(in)}")
code.Print(" matched = true")
code.Print(" case float64:")
code.Print(" x.Oneof = &DefaultType_Number{Number: in}")
code.Print(" matched = true")
code.Print(" case float32:")
code.Print(" x.Oneof = &DefaultType_Number{Number: float64(in)}")
code.Print(" matched = true")
code.Print(" }")
code.Print(" if matched {")
code.Print(" // since the oneof matched one of its possibilities, discard any matching errors")
code.Print(" errors = make([]error, 0)")
code.Print(" }")
} else {
oneOfWrapper := typeModel.OneOfWrapper
code.Print("x := &%s{}", typeName)
if oneOfWrapper {
code.Print("matched := false")
}
unpackAtTop := !oneOfWrapper || len(typeModel.Required) > 0
if unpackAtTop {
code.Print("m, ok := compiler.UnpackMap(in)")
code.Print("if !ok {")
code.Print(" message := fmt.Sprintf(\"has unexpected value: %%+v (%%T)\", in, in)")
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print("} else {")
}
if len(typeModel.Required) > 0 {
// verify that map includes all required keys
keyString := ""
sort.Strings(typeModel.Required)
for _, k := range typeModel.Required {
if keyString != "" {
keyString += ","
}
keyString += "\""
keyString += k
keyString += "\""
}
code.Print("requiredKeys := []string{%s}", keyString)
code.Print("missingKeys := compiler.MissingKeysInMap(m, requiredKeys)")
code.Print("if len(missingKeys) > 0 {")
code.Print(" message := fmt.Sprintf(\"is missing required %%s: %%+v\", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, \", \"))")
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print("}")
}
if !typeModel.Open {
// verify that map has no unspecified keys
allowedKeys := make([]string, 0)
for _, property := range typeModel.Properties {
if !property.Implicit {
allowedKeys = append(allowedKeys, property.Name)
}
}
sort.Strings(allowedKeys)
allowedKeyString := ""
for _, allowedKey := range allowedKeys {
if allowedKeyString != "" {
allowedKeyString += ","
}
allowedKeyString += "\""
allowedKeyString += allowedKey
allowedKeyString += "\""
}
allowedPatternString := ""
if typeModel.OpenPatterns != nil {
for _, pattern := range typeModel.OpenPatterns {
if allowedPatternString != "" {
allowedPatternString += ","
}
allowedPatternString += nameForPattern(regexPatterns, pattern)
}
}
// verify that map includes only allowed keys and patterns
code.Print("allowedKeys := []string{%s}", allowedKeyString)
if len(allowedPatternString) > 0 {
code.Print("allowedPatterns := []*regexp.Regexp{%s}", allowedPatternString)
} else {
code.Print("var allowedPatterns []*regexp.Regexp")
}
code.Print("invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns)")
code.Print("if len(invalidKeys) > 0 {")
code.Print(" message := fmt.Sprintf(\"has invalid %%s: %%+v\", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, \", \"))")
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print("}")
}
var fieldNumber = 0
for _, propertyModel := range typeModel.Properties {
propertyName := propertyModel.Name
fieldNumber++
propertyType := propertyModel.Type
if propertyType == "int" {
propertyType = "int64"
}
var displayName = propertyName
if displayName == "$ref" {
displayName = "_ref"
}
if displayName == "$schema" {
displayName = "_schema"
}
displayName = camelCaseToSnakeCase(displayName)
var line = fmt.Sprintf("%s %s = %d;", propertyType, displayName, fieldNumber)
if propertyModel.Repeated {
line = "repeated " + line
}
code.Print("// " + line)
fieldName := strings.Title(snakeCaseToCamelCase(propertyName))
if propertyName == "$ref" {
fieldName = "XRef"
}
typeModel, typeFound := domain.TypeModels[propertyType]
if typeFound && !typeModel.IsPair {
if propertyModel.Repeated {
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
code.Print("if (v%d != nil) {", fieldNumber)
code.Print(" // repeated %s", typeModel.Name)
code.Print(" x.%s = make([]*%s, 0)", fieldName, typeModel.Name)
code.Print(" a, ok := v%d.([]interface{})", fieldNumber)
code.Print(" if ok {")
code.Print(" for _, item := range a {")
code.Print(" y, err := New%s(item, compiler.NewContext(\"%s\", context))", typeModel.Name, propertyName)
code.Print(" if err != nil {")
code.Print(" errors = append(errors, err)")
code.Print(" }")
code.Print(" x.%s = append(x.%s, y)", fieldName, fieldName)
code.Print(" }")
code.Print(" }")
code.Print("}")
} else {
if oneOfWrapper {
code.Print("{")
if !unpackAtTop {
code.Print(" m, ok := compiler.UnpackMap(in)")
code.Print(" if ok {")
}
code.Print(" // errors might be ok here, they mean we just don't have the right subtype")
code.Print(" t, matchingError := New%s(m, compiler.NewContext(\"%s\", context))", typeModel.Name, propertyName)
code.Print(" if matchingError == nil {")
code.Print(" x.Oneof = &%s_%s{%s: t}", parentTypeName, typeModel.Name, typeModel.Name)
code.Print(" matched = true")
code.Print(" } else {")
code.Print(" errors = append(errors, matchingError)")
code.Print(" }")
if !unpackAtTop {
code.Print(" }")
}
code.Print("}")
} else {
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
code.Print("if (v%d != nil) {", fieldNumber)
code.Print(" var err error")
code.Print(" x.%s, err = New%s(v%d, compiler.NewContext(\"%s\", context))",
fieldName, typeModel.Name, fieldNumber, propertyName)
code.Print(" if err != nil {")
code.Print(" errors = append(errors, err)")
code.Print(" }")
code.Print("}")
}
}
} else if propertyType == "string" {
if propertyModel.Repeated {
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
code.Print("if (v%d != nil) {", fieldNumber)
code.Print(" v, ok := v%d.([]interface{})", fieldNumber)
code.Print(" if ok {")
code.Print(" x.%s = compiler.ConvertInterfaceArrayToStringArray(v)", fieldName)
code.Print(" } else {")
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print("}")
if propertyModel.StringEnumValues != nil {
code.Print("// check for valid enum values")
code.Print("// %+v", propertyModel.StringEnumValues)
stringArrayLiteral := "[]string{"
for i, item := range propertyModel.StringEnumValues {
if i > 0 {
stringArrayLiteral += ","
}
stringArrayLiteral += "\"" + item + "\""
}
stringArrayLiteral += "}"
code.Print("if ok && !compiler.StringArrayContainsValues(%s, x.%s) {", stringArrayLiteral, fieldName)
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v\", v%d)", propertyName, fieldNumber)
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print("}")
}
code.Print("}")
} else {
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
code.Print("if (v%d != nil) {", fieldNumber)
code.Print(" x.%s, ok = v%d.(string)", fieldName, fieldNumber)
code.Print(" if !ok {")
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print(" }")
if propertyModel.StringEnumValues != nil {
code.Print("// check for valid enum values")
code.Print("// %+v", propertyModel.StringEnumValues)
stringArrayLiteral := "[]string{"
for i, item := range propertyModel.StringEnumValues {
if i > 0 {
stringArrayLiteral += ","
}
stringArrayLiteral += "\"" + item + "\""
}
stringArrayLiteral += "}"
code.Print("if ok && !compiler.StringArrayContainsValue(%s, x.%s) {", stringArrayLiteral, fieldName)
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print("}")
}
code.Print("}")
}
} else if propertyType == "float" {
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
code.Print("if (v%d != nil) {", fieldNumber)
code.Print(" switch v%d := v%d.(type) {", fieldNumber, fieldNumber)
code.Print(" case float64:")
code.Print(" x.%s = v%d", fieldName, fieldNumber)
code.Print(" case float32:")
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
code.Print(" case uint64:")
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
code.Print(" case uint32:")
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
code.Print(" case int64:")
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
code.Print(" case int32:")
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
code.Print(" case int:")
code.Print(" x.%s = float64(v%d)", fieldName, fieldNumber)
code.Print(" default:")
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print(" }")
code.Print("}")
} else if propertyType == "int64" {
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
code.Print("if (v%d != nil) {", fieldNumber)
code.Print(" t, ok := v%d.(int)", fieldNumber)
code.Print(" if ok {")
code.Print(" x.%s = int64(t)", fieldName)
code.Print(" } else {")
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print(" }")
code.Print("}")
} else if propertyType == "bool" {
if oneOfWrapper {
propertyName := "Boolean"
code.Print("boolValue, ok := in.(bool)")
code.Print("if ok {")
code.Print(" x.Oneof = &%s_%s{%s: boolValue}", parentTypeName, propertyName, propertyName)
code.Print("}")
} else {
code.Print("v%d := compiler.MapValueForKey(m, \"%s\")", fieldNumber, propertyName)
code.Print("if (v%d != nil) {", fieldNumber)
code.Print(" x.%s, ok = v%d.(bool)", fieldName, fieldNumber)
code.Print(" if !ok {")
code.Print(" message := fmt.Sprintf(\"has unexpected value for %s: %%+v (%%T)\", v%d, v%d)", propertyName, fieldNumber, fieldNumber)
code.Print(" errors = append(errors, compiler.NewError(context, message))")
code.Print(" }")
code.Print("}")
}
} else {
mapTypeName := propertyModel.MapType
if mapTypeName != "" {
code.Print("// MAP: %s %s", mapTypeName, propertyModel.Pattern)
if mapTypeName == "string" {
code.Print("x.%s = make([]*NamedString, 0)", fieldName)
} else {
code.Print("x.%s = make([]*Named%s, 0)", fieldName, mapTypeName)
}
code.Print("for _, item := range m {")
code.Print("k, ok := compiler.StringValue(item.Key)")
code.Print("if ok {")
code.Print("v := item.Value")
if pattern := propertyModel.Pattern; pattern != "" {
if inline, ok := regexPatterns.SpecialCaseExpression(pattern, "k"); ok {
code.Print("if %s {", inline)
} else {
code.Print("if %s.MatchString(k) {", nameForPattern(regexPatterns, pattern))
}
}
code.Print("pair := &Named" + strings.Title(mapTypeName) + "{}")
code.Print("pair.Name = k")
if mapTypeName == "string" {
code.Print("pair.Value = v.(string)")
} else if mapTypeName == "Any" {
code.Print("result := &Any{}")
code.Print("handled, resultFromExt, err := compiler.HandleExtension(context, v, k)")
code.Print("if handled {")
code.Print(" if err != nil {")
code.Print(" errors = append(errors, err)")
code.Print(" } else {")
code.Print(" bytes, _ := yaml.Marshal(v)")
code.Print(" result.Yaml = string(bytes)")
code.Print(" result.Value = resultFromExt")
code.Print(" pair.Value = result")
code.Print(" }")
code.Print("} else {")
code.Print(" pair.Value, err = NewAny(v, compiler.NewContext(k, context))")
code.Print(" if err != nil {")
code.Print(" errors = append(errors, err)")
code.Print(" }")
code.Print("}")
} else {
code.Print("var err error")
code.Print("pair.Value, err = New%s(v, compiler.NewContext(k, context))", mapTypeName)
code.Print("if err != nil {")
code.Print(" errors = append(errors, err)")
code.Print("}")
}
code.Print("x.%s = append(x.%s, pair)", fieldName, fieldName)
if propertyModel.Pattern != "" {
code.Print("}")
}
code.Print("}")
code.Print("}")
} else {
code.Print("// TODO: %s", propertyType)
}
}
}
if unpackAtTop {
code.Print("}")
}
if oneOfWrapper {
code.Print("if matched {")
code.Print(" // since the oneof matched one of its possibilities, discard any matching errors")
code.Print(" errors = make([]error, 0)")
code.Print("}")
}
}
// assumes that the return value is in a variable named "x"
code.Print(" return x, compiler.NewErrorGroupOrNil(errors)")
code.Print("}\n")
}
// ResolveReferences() methods
func (domain *Domain) generateResolveReferencesMethodsForType(code *printer.Code, typeName string) {
code.Print("// ResolveReferences resolves references found inside %s objects.", typeName)
code.Print("func (m *%s) ResolveReferences(root string) (interface{}, error) {", typeName)
code.Print("errors := make([]error, 0)")
typeModel := domain.TypeModels[typeName]
if typeModel.OneOfWrapper {
// call ResolveReferences on whatever is in the Oneof.
for _, propertyModel := range typeModel.Properties {
propertyType := propertyModel.Type
_, typeFound := domain.TypeModels[propertyType]
if typeFound {
code.Print("{")
code.Print("p, ok := m.Oneof.(*%s_%s)", typeName, propertyType)
code.Print("if ok {")
if propertyType == "JsonReference" { // Special case for OpenAPI
code.Print("info, err := p.%s.ResolveReferences(root)", propertyType)
code.Print("if err != nil {")
code.Print(" return nil, err")
code.Print("} else if info != nil {")
code.Print(" n, err := New%s(info, nil)", typeName)
code.Print(" if err != nil {")
code.Print(" return nil, err")
code.Print(" } else if n != nil {")
code.Print(" *m = *n")
code.Print(" return nil, nil")
code.Print(" }")
code.Print("}")
} else {
code.Print("_, err := p.%s.ResolveReferences(root)", propertyType)
code.Print("if err != nil {")
code.Print(" return nil, err")
code.Print("}")
}
code.Print("}")
code.Print("}")
}
}
} else {
for _, propertyModel := range typeModel.Properties {
propertyName := propertyModel.Name
var displayName = propertyName
if displayName == "$ref" {
displayName = "_ref"
}
if displayName == "$schema" {
displayName = "_schema"
}
displayName = camelCaseToSnakeCase(displayName)
fieldName := strings.Title(propertyName)
if propertyName == "$ref" {
fieldName = "XRef"
code.Print("if m.XRef != \"\" {")
//code.Print("log.Printf(\"%s reference to resolve %%+v\", m.XRef)", typeName)
code.Print("info, err := compiler.ReadInfoForRef(root, m.XRef)")
code.Print("if err != nil {")
code.Print(" return nil, err")
code.Print("}")
//code.Print("log.Printf(\"%%+v\", info)")
if len(typeModel.Properties) > 1 {
code.Print("if info != nil {")
code.Print(" replacement, err := New%s(info, nil)", typeName)
code.Print(" if err == nil {")
code.Print(" *m = *replacement")
code.Print(" return m.ResolveReferences(root)")
code.Print(" }")
code.Print("}")
}
code.Print("return info, nil")
code.Print("}")
}
if !propertyModel.Repeated {
propertyType := propertyModel.Type
typeModel, typeFound := domain.TypeModels[propertyType]
if typeFound && !typeModel.IsPair {
code.Print("if m.%s != nil {", fieldName)
code.Print(" _, err := m.%s.ResolveReferences(root)", fieldName)
code.Print(" if err != nil {")
code.Print(" errors = append(errors, err)")
code.Print(" }")
code.Print("}")
}
} else {
propertyType := propertyModel.Type
_, typeFound := domain.TypeModels[propertyType]
if typeFound {
code.Print("for _, item := range m.%s {", fieldName)
code.Print("if item != nil {")
code.Print(" _, err := item.ResolveReferences(root)")
code.Print(" if err != nil {")
code.Print(" errors = append(errors, err)")
code.Print(" }")
code.Print("}")
code.Print("}")
}
}
}
}
code.Print(" return nil, compiler.NewErrorGroupOrNil(errors)")
code.Print("}\n")
}
// ToRawInfo() methods
func (domain *Domain) generateToRawInfoMethodForType(code *printer.Code, typeName string) {
code.Print("// ToRawInfo returns a description of %s suitable for JSON or YAML export.", typeName)
code.Print("func (m *%s) ToRawInfo() interface{} {", typeName)
typeModel := domain.TypeModels[typeName]
if typeName == "Any" {
code.Print("var err error")
code.Print("var info1 []yaml.MapSlice")
code.Print("err = yaml.Unmarshal([]byte(m.Yaml), &info1)")
code.Print("if err == nil {return info1}")
code.Print("var info2 yaml.MapSlice")
code.Print("err = yaml.Unmarshal([]byte(m.Yaml), &info2)")
code.Print("if err == nil {return info2}")
code.Print("var info3 interface{}")
code.Print("err = yaml.Unmarshal([]byte(m.Yaml), &info3)")
code.Print("if err == nil {return info3}")
code.Print("return nil")
} else if typeName == "StringArray" {
code.Print("return m.Value")
} else if typeModel.OneOfWrapper {
code.Print("// ONE OF WRAPPER")
code.Print("// %s", typeModel.Name)
for i, item := range typeModel.Properties {
code.Print("// %+v", *item)
if item.Type == "float" {
code.Print("if v%d, ok := m.GetOneof().(*%s_Number); ok {", i, typeName)
code.Print("return v%d.Number", i)
code.Print("}")
} else if item.Type == "bool" {
code.Print("if v%d, ok := m.GetOneof().(*%s_Boolean); ok {", i, typeName)
code.Print("return v%d.Boolean", i)
code.Print("}")
} else if item.Type == "string" {
code.Print("if v%d, ok := m.GetOneof().(*%s_String_); ok {", i, typeName)
code.Print("return v%d.String_", i)
code.Print("}")
} else {
code.Print("v%d := m.Get%s()", i, item.Type)
code.Print("if v%d != nil {", i)
code.Print(" return v%d.ToRawInfo()", i)
code.Print("}")
}
}
code.Print("return nil")
} else {
code.Print("info := yaml.MapSlice{}")
for _, propertyModel := range typeModel.Properties {
switch propertyModel.Type {
case "string":
propertyName := propertyModel.Name
if !propertyModel.Repeated {
code.Print("if m.%s != \"\" {", propertyModel.FieldName())
code.Print("info = append(info, yaml.MapItem{Key:\"%s\", Value:m.%s})", propertyName, propertyModel.FieldName())
code.Print("}")
} else {
code.Print("if len(m.%s) != 0 {", propertyModel.FieldName())
code.Print("info = append(info, yaml.MapItem{Key:\"%s\", Value:m.%s})", propertyName, propertyModel.FieldName())
code.Print("}")
}
case "bool":
propertyName := propertyModel.Name
if !propertyModel.Repeated {
code.Print("if m.%s != false {", propertyModel.FieldName())
code.Print("info = append(info, yaml.MapItem{Key:\"%s\", Value:m.%s})", propertyName, propertyModel.FieldName())
code.Print("}")
} else {
code.Print("if len(m.%s) != 0 {", propertyModel.FieldName())
code.Print("info = append(info, yaml.MapItem{Key:\"%s\", Value:m.%s})", propertyName, propertyModel.FieldName())
code.Print("}")
}
case "int":
propertyName := propertyModel.Name
if !propertyModel.Repeated {
code.Print("if m.%s != 0 {", propertyModel.FieldName())
code.Print("info = append(info, yaml.MapItem{Key:\"%s\", Value:m.%s})", propertyName, propertyModel.FieldName())
code.Print("}")
} else {
code.Print("if len(m.%s) != 0 {", propertyModel.FieldName())
code.Print("info = append(info, yaml.MapItem{Key:\"%s\", Value:m.%s})", propertyName, propertyModel.FieldName())
code.Print("}")
}
case "float":
propertyName := propertyModel.Name
if !propertyModel.Repeated {
code.Print("if m.%s != 0.0 {", propertyModel.FieldName())
code.Print("info = append(info, yaml.MapItem{Key:\"%s\", Value:m.%s})", propertyName, propertyModel.FieldName())
code.Print("}")
} else {
code.Print("if len(m.%s) != 0 {", propertyModel.FieldName())
code.Print("info = append(info, yaml.MapItem{Key:\"%s\", Value:m.%s})", propertyName, propertyModel.FieldName())
code.Print("}")
}
default:
propertyName := propertyModel.Name
if propertyName == "value" {
code.Print("// %+v", propertyModel)
} else if !propertyModel.Repeated {
code.Print("if m.%s != nil {", propertyModel.FieldName())
if propertyModel.Type == "TypeItem" {
code.Print("if len(m.Type.Value) == 1 {")
code.Print("info = append(info, yaml.MapItem{Key:\"type\", Value:m.Type.Value[0]})")
code.Print("} else {")
code.Print("info = append(info, yaml.MapItem{Key:\"type\", Value:m.Type.Value})")
code.Print("}")
} else if propertyModel.Type == "ItemsItem" {
code.Print("items := make([]interface{}, 0)")
if domain.Version == "v2" {
code.Print("for _, item := range m.Items.Schema {")
} else {
code.Print("for _, item := range m.Items.SchemaOrReference {")
}
code.Print(" items = append(items, item.ToRawInfo())")
code.Print("}")
code.Print("info = append(info, yaml.MapItem{Key:\"items\", Value:items[0]})")
} else {
code.Print("info = append(info, yaml.MapItem{Key:\"%s\", Value:m.%s.ToRawInfo()})",
propertyName, propertyModel.FieldName())
}
code.Print("}")
code.Print("// %+v", propertyModel)
} else if propertyModel.MapType == "string" {
code.Print("// %+v", propertyModel)
} else if propertyModel.MapType != "" {
code.Print("if m.%s != nil {", propertyModel.FieldName())
code.Print("for _, item := range m.%s {", propertyModel.FieldName())
code.Print("info = append(info, yaml.MapItem{Key:item.Name, Value:item.Value.ToRawInfo()})")
code.Print("}")
code.Print("}")
code.Print("// %+v", propertyModel)
} else {
code.Print("if len(m.%s) != 0 {", propertyModel.FieldName())
code.Print("items := make([]interface{}, 0)")
code.Print("for _, item := range m.%s {", propertyModel.FieldName())
code.Print("items = append(items, item.ToRawInfo())")
code.Print("}")
code.Print("info = append(info, yaml.MapItem{Key:\"%s\", Value:items})", propertyName)
code.Print("}")
code.Print("// %+v", propertyModel)
}
}
}
code.Print("return info")
}
code.Print("}\n")
}
func (domain *Domain) generateConstantVariables(code *printer.Code, regexPatterns *patternNames) {
names := regexPatterns.Names()
var sortedNames []string
for name, _ := range names {
sortedNames = append(sortedNames, name)
}
sort.Strings(sortedNames)
code.Print("var (")
for _, name := range sortedNames {
code.Print("%s = regexp.MustCompile(\"%s\")", name, escapeSlashes(names[name]))
}
code.Print(")\n")
}

View File

@ -1,363 +0,0 @@
// 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 (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"runtime"
"sort"
"strings"
"github.com/googleapis/gnostic/compiler"
"github.com/googleapis/gnostic/jsonschema"
"github.com/googleapis/gnostic/printer"
)
var protoOptionsForExtensions = []ProtoOption{
ProtoOption{
Name: "java_multiple_files",
Value: "true",
Comment: "// This option lets the proto compiler generate Java code inside the package\n" +
"// name (see below) instead of inside an outer class. It creates a simpler\n" +
"// developer experience by reducing one-level of name nesting and be\n" +
"// consistent with most programming languages that don't support outer classes.",
},
ProtoOption{
Name: "java_outer_classname",
Value: "VendorExtensionProto",
Comment: "// The Java outer classname should be the filename in UpperCamelCase. This\n" +
"// class is only used to hold proto descriptor, so developers don't need to\n" +
"// work with it directly.",
},
}
const additionalCompilerCodeWithMain = "" +
"func handleExtension(extensionName string, yamlInput string) (bool, proto.Message, error) {\n" +
" switch extensionName {\n" +
" // All supported extensions\n" +
" %s\n" +
" default:\n" +
" return false, nil, nil\n" +
" }\n" +
"}\n" +
"\n" +
"func main() {\n" +
" openapiextension_v1.ProcessExtension(handleExtension)\n" +
"}\n"
const caseStringForObjectTypes = "\n" +
"case \"%s\":\n" +
"var info yaml.MapSlice\n" +
"err := yaml.Unmarshal([]byte(yamlInput), &info)\n" +
"if err != nil {\n" +
" return true, nil, err\n" +
"}\n" +
"newObject, err := %s.New%s(info, compiler.NewContext(\"$root\", nil))\n" +
"return true, newObject, err"
const caseStringForWrapperTypes = "\n" +
"case \"%s\":\n" +
"var info %s\n" +
"err := yaml.Unmarshal([]byte(yamlInput), &info)\n" +
"if err != nil {\n" +
" return true, nil, err\n" +
"}\n" +
"newObject := &wrappers.%s{Value: info}\n" +
"return true, newObject, nil"
// generateMainFile generates the main program for an extension.
func generateMainFile(packageName string, license string, codeBody string, imports []string) string {
code := &printer.Code{}
code.Print(license)
code.Print("// THIS FILE IS AUTOMATICALLY GENERATED.\n")
// generate package declaration
code.Print("package %s\n", packageName)
code.Print("import (")
for _, filename := range imports {
code.Print("\"" + filename + "\"")
}
code.Print(")\n")
code.Print(codeBody)
return code.String()
}
func getBaseFileNameWithoutExt(filePath string) string {
tmp := filepath.Base(filePath)
return tmp[0 : len(tmp)-len(filepath.Ext(tmp))]
}
func toProtoPackageName(input string) string {
var out = ""
nonAlphaNumeric := regexp.MustCompile("[^0-9A-Za-z_]+")
input = nonAlphaNumeric.ReplaceAllString(input, "")
for index, character := range input {
if character >= 'A' && character <= 'Z' {
if index > 0 && input[index-1] != '_' {
out += "_"
}
out += string(character - 'A' + 'a')
} else {
out += string(character)
}
}
return out
}
type primitiveTypeInfo struct {
goTypeName string
wrapperProtoName string
}
var supportedPrimitiveTypeInfos = map[string]primitiveTypeInfo{
"string": primitiveTypeInfo{goTypeName: "string", wrapperProtoName: "StringValue"},
"number": primitiveTypeInfo{goTypeName: "float64", wrapperProtoName: "DoubleValue"},
"integer": primitiveTypeInfo{goTypeName: "int64", wrapperProtoName: "Int64Value"},
"boolean": primitiveTypeInfo{goTypeName: "bool", wrapperProtoName: "BoolValue"},
// TODO: Investigate how to support arrays. For now users will not be allowed to
// create extension handlers for arrays and they will have to use the
// plane yaml string as is.
}
type generatedTypeInfo struct {
schemaName string
// if this is not nil, the schema should be treataed as a primitive type.
optionalPrimitiveTypeInfo *primitiveTypeInfo
}
// GenerateExtension generates the implementation of an extension.
func GenerateExtension(schemaFile string, outDir string) error {
outFileBaseName := getBaseFileNameWithoutExt(schemaFile)
extensionNameWithoutXDashPrefix := outFileBaseName[len("x-"):]
outDir = path.Join(outDir, "gnostic-x-"+extensionNameWithoutXDashPrefix)
protoPackage := toProtoPackageName(extensionNameWithoutXDashPrefix)
protoPackageName := strings.ToLower(protoPackage)
goPackageName := protoPackageName
protoOutDirectory := outDir + "/" + "proto"
var err error
projectRoot := os.Getenv("GOPATH") + "/src/github.com/googleapis/gnostic/"
baseSchema, err := jsonschema.NewSchemaFromFile(projectRoot + "jsonschema/schema.json")
if err != nil {
return err
}
baseSchema.ResolveRefs()
baseSchema.ResolveAllOfs()
openapiSchema, err := jsonschema.NewSchemaFromFile(schemaFile)
if err != nil {
return err
}
openapiSchema.ResolveRefs()
openapiSchema.ResolveAllOfs()
// build a simplified model of the types described by the schema
cc := NewDomain(openapiSchema, "v2") // TODO fix for OpenAPI v3
// create a type for each object defined in the schema
extensionNameToMessageName := make(map[string]generatedTypeInfo)
schemaErrors := make([]error, 0)
supportedPrimitives := make([]string, 0)
for key := range supportedPrimitiveTypeInfos {
supportedPrimitives = append(supportedPrimitives, key)
}
sort.Strings(supportedPrimitives)
if cc.Schema.Definitions != nil {
for _, pair := range *(cc.Schema.Definitions) {
definitionName := pair.Name
definitionSchema := pair.Value
// ensure the id field is set
if definitionSchema.ID == nil || len(*(definitionSchema.ID)) == 0 {
schemaErrors = append(schemaErrors,
fmt.Errorf("schema %s has no 'id' field, which must match the "+
"name of the OpenAPI extension that the schema represents",
definitionName))
} else {
if _, ok := extensionNameToMessageName[*(definitionSchema.ID)]; ok {
schemaErrors = append(schemaErrors,
fmt.Errorf("schema %s and %s have the same 'id' field value",
definitionName, extensionNameToMessageName[*(definitionSchema.ID)].schemaName))
} else if (definitionSchema.Type == nil) || (*definitionSchema.Type.String == "object") {
extensionNameToMessageName[*(definitionSchema.ID)] = generatedTypeInfo{schemaName: definitionName}
} else {
// this is a primitive type
if val, ok := supportedPrimitiveTypeInfos[*definitionSchema.Type.String]; ok {
extensionNameToMessageName[*(definitionSchema.ID)] = generatedTypeInfo{schemaName: definitionName, optionalPrimitiveTypeInfo: &val}
} else {
schemaErrors = append(schemaErrors,
fmt.Errorf("Schema %s has type '%s' which is "+
"not supported. Supported primitive types are "+
"%s.\n", definitionName,
*definitionSchema.Type.String,
supportedPrimitives))
}
}
}
typeName := cc.TypeNameForStub(definitionName)
typeModel := cc.BuildTypeForDefinition(typeName, definitionName, definitionSchema)
if typeModel != nil {
cc.TypeModels[typeName] = typeModel
}
}
}
if len(schemaErrors) > 0 {
// error has been reported.
return compiler.NewErrorGroupOrNil(schemaErrors)
}
err = os.MkdirAll(outDir, os.ModePerm)
if err != nil {
return err
}
err = os.MkdirAll(protoOutDirectory, os.ModePerm)
if err != nil {
return err
}
// generate the protocol buffer description
protoOptions := append(protoOptionsForExtensions,
ProtoOption{Name: "java_package", Value: "org.openapi.extension." + strings.ToLower(protoPackage), Comment: "// The Java package name must be proto package name with proper prefix."},
ProtoOption{Name: "objc_class_prefix", Value: strings.ToLower(protoPackage),
Comment: "// A reasonable prefix for the Objective-C symbols generated from the package.\n" +
"// It should at a minimum be 3 characters long, all uppercase, and convention\n" +
"// is to use an abbreviation of the package name. Something short, but\n" +
"// hopefully unique enough to not conflict with things that may come along in\n" +
"// the future. 'GPB' is reserved for the protocol buffer implementation itself.",
})
proto := cc.generateProto(protoPackageName, License, protoOptions, nil)
protoFilename := path.Join(protoOutDirectory, outFileBaseName+".proto")
err = ioutil.WriteFile(protoFilename, []byte(proto), 0644)
if err != nil {
return err
}
// generate the compiler
compiler := cc.GenerateCompiler(goPackageName, License, []string{
"fmt",
"regexp",
"strings",
"github.com/googleapis/gnostic/compiler",
"gopkg.in/yaml.v2",
})
goFilename := path.Join(protoOutDirectory, outFileBaseName+".go")
err = ioutil.WriteFile(goFilename, []byte(compiler), 0644)
if err != nil {
return err
}
err = exec.Command(runtime.GOROOT()+"/bin/gofmt", "-w", goFilename).Run()
// generate the main file.
outDirRelativeToGoPathSrc := strings.Replace(outDir, path.Join(os.Getenv("GOPATH"), "src")+"/", "", 1)
var extensionNameKeys []string
for k := range extensionNameToMessageName {
extensionNameKeys = append(extensionNameKeys, k)
}
sort.Strings(extensionNameKeys)
wrapperTypeIncluded := false
var cases string
for _, extensionName := range extensionNameKeys {
if extensionNameToMessageName[extensionName].optionalPrimitiveTypeInfo == nil {
cases += fmt.Sprintf(caseStringForObjectTypes, extensionName, goPackageName, extensionNameToMessageName[extensionName].schemaName)
} else {
wrapperTypeIncluded = true
cases += fmt.Sprintf(caseStringForWrapperTypes, extensionName, extensionNameToMessageName[extensionName].optionalPrimitiveTypeInfo.goTypeName, extensionNameToMessageName[extensionName].optionalPrimitiveTypeInfo.wrapperProtoName)
}
}
extMainCode := fmt.Sprintf(additionalCompilerCodeWithMain, cases)
imports := []string{
"github.com/golang/protobuf/proto",
"github.com/googleapis/gnostic/extensions",
"github.com/googleapis/gnostic/compiler",
"gopkg.in/yaml.v2",
outDirRelativeToGoPathSrc + "/" + "proto",
}
if wrapperTypeIncluded {
imports = append(imports, "github.com/golang/protobuf/ptypes/wrappers")
}
main := generateMainFile("main", License, extMainCode, imports)
mainFileName := path.Join(outDir, "main.go")
err = ioutil.WriteFile(mainFileName, []byte(main), 0644)
if err != nil {
return err
}
// format the compiler
return exec.Command(runtime.GOROOT()+"/bin/gofmt", "-w", mainFileName).Run()
}
func processExtensionGenCommandline(usage string) error {
outDir := ""
schameFile := ""
extParamRegex, _ := regexp.Compile("--(.+)=(.+)")
for i, arg := range os.Args {
if i == 0 {
continue // skip the tool name
}
var m [][]byte
if m = extParamRegex.FindSubmatch([]byte(arg)); m != nil {
flagName := string(m[1])
flagValue := string(m[2])
switch flagName {
case "out_dir":
outDir = flagValue
default:
fmt.Printf("Unknown option: %s.\n%s\n", arg, usage)
os.Exit(-1)
}
} else if arg == "--extension" {
continue
} else if arg[0] == '-' {
fmt.Printf("Unknown option: %s.\n%s\n", arg, usage)
os.Exit(-1)
} else {
schameFile = arg
}
}
if schameFile == "" {
fmt.Printf("No input json schema specified.\n%s\n", usage)
os.Exit(-1)
}
if outDir == "" {
fmt.Printf("Missing output directive.\n%s\n", usage)
os.Exit(-1)
}
if !strings.HasPrefix(getBaseFileNameWithoutExt(schameFile), "x-") {
fmt.Printf("Schema file name has to start with 'x-'.\n%s\n", usage)
os.Exit(-1)
}
return GenerateExtension(schameFile, outDir)
}

View File

@ -1,52 +0,0 @@
package main
import (
"io/ioutil"
"os"
"os/exec"
"testing"
)
func TestErrorExtensionGeneratorUnsupportedPrimitive(t *testing.T) {
var err error
output, err := exec.Command(
"generator",
"--extension",
"test/x-unsupportedprimitives.json",
"--out_dir=/tmp",
).Output()
outputFile := "x-unsupportedprimitives.errors"
_ = ioutil.WriteFile(outputFile, output, 0644)
err = exec.Command("diff", outputFile, "test/errors/x-unsupportedprimitives.errors").Run()
if err != nil {
t.Logf("Diff failed: %+v", err)
t.FailNow()
} else {
// if the test succeeded, clean up
os.Remove(outputFile)
}
}
func TestErrorExtensionGeneratorNameCollision(t *testing.T) {
var err error
output, err := exec.Command(
"generator",
"--extension",
"test/x-extension-name-collision.json",
"--out_dir=/tmp",
).Output()
outputFile := "x-extension-name-collision.errors"
_ = ioutil.WriteFile(outputFile, output, 0644)
err = exec.Command("diff", outputFile, "test/errors/x-extension-name-collision.errors").Run()
if err != nil {
t.Logf("Diff failed: %+v", err)
t.FailNow()
} else {
// if the test succeeded, clean up
os.Remove(outputFile)
}
}

View File

@ -1,119 +0,0 @@
// 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 (
"fmt"
"strings"
"github.com/googleapis/gnostic/printer"
)
// ProtoOption represents an option to be added to generated .proto files.
type ProtoOption struct {
Name string
Value string
Comment string
}
func (domain *Domain) generateProto(packageName string, license string, options []ProtoOption, imports []string) string {
code := &printer.Code{}
code.Print(license)
code.Print("// THIS FILE IS AUTOMATICALLY GENERATED.")
code.Print()
code.Print("syntax = \"proto3\";")
code.Print()
code.Print("package " + packageName + ";")
for _, importString := range imports {
code.Print()
code.Print("import \"" + importString + "\";")
}
code.Print()
// generate option declarations
for _, option := range options {
commentLines := strings.Split(option.Comment, "\n")
for _, commentLine := range commentLines {
code.Print(commentLine)
}
line := "option " + option.Name + " = "
if option.Value == "true" || option.Value == "false" {
line += option.Value
} else {
line += "\"" + option.Value + "\""
}
line += ";\n"
code.Print(line)
}
// generate message definitions
typeNames := domain.sortedTypeNames()
for _, typeName := range typeNames {
typeModel := domain.TypeModels[typeName]
if typeModel.Description != "" {
code.Print("// %s", typeModel.Description)
}
code.Print("message %s {", typeName)
code.Indent()
if typeModel.OneOfWrapper {
code.Print("oneof oneof {")
code.Indent()
}
var fieldNumber = 0
for _, propertyModel := range typeModel.Properties {
if propertyModel.Description != "" {
code.Print("// %s", propertyModel.Description)
}
propertyName := propertyModel.Name
fieldNumber++
propertyType := propertyModel.Type
if propertyType == "int" {
propertyType = "int64"
}
if propertyType == "float" {
propertyType = "double"
}
// TODO may be remove this.
if propertyType == "blob" {
propertyType = "string"
}
var displayName = propertyName
if displayName == "$ref" {
displayName = "_ref"
}
if displayName == "$schema" {
displayName = "_schema"
}
displayName = camelCaseToSnakeCase(displayName)
var line = fmt.Sprintf("%s %s = %d;", propertyType, displayName, fieldNumber)
if propertyModel.Repeated {
line = "repeated " + line
}
code.Print(line)
}
if typeModel.OneOfWrapper {
code.Outdent()
code.Print("}")
}
code.Outdent()
code.Print("}")
code.Print()
}
return code.String()
}

View File

@ -1,55 +0,0 @@
// 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 (
"strings"
"unicode"
)
// Returns a "snake case" form of a camel-cased string.
func camelCaseToSnakeCase(input string) string {
out := ""
for index, runeValue := range input {
//fmt.Printf("%#U starts at byte position %d\n", runeValue, index)
if runeValue >= 'A' && runeValue <= 'Z' {
if index > 0 {
out += "_"
}
out += string(runeValue - 'A' + 'a')
} else {
out += string(runeValue)
}
}
return out
}
func snakeCaseToCamelCase(input string) string {
out := ""
words := strings.Split(input, "_")
for i, word := range words {
if (i > 0) && len(word) > 0 {
w := []rune(word)
w[0] = unicode.ToUpper(w[0])
out += string(w)
} else {
out += word
}
}
return out
}

View File

@ -1,257 +0,0 @@
// 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.
// generator generates Protocol Buffer models and support code from
// JSON Schemas. It is used to generate representations of the
// OpenAPI Specification and vendor and specification extensions
// that are added by third-party OpenAPI authors.
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path"
"runtime"
"strings"
"github.com/googleapis/gnostic/jsonschema"
)
// License is the software license applied to generated code.
const License = "" +
"// Copyright 2017 Google Inc. All Rights Reserved.\n" +
"//\n" +
"// Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
"// you may not use this file except in compliance with the License.\n" +
"// You may obtain a copy of the License at\n" +
"//\n" +
"// http://www.apache.org/licenses/LICENSE-2.0\n" +
"//\n" +
"// Unless required by applicable law or agreed to in writing, software\n" +
"// distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
"// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
"// See the License for the specific language governing permissions and\n" +
"// limitations under the License.\n"
func protoOptions(packageName string) []ProtoOption {
return []ProtoOption{
ProtoOption{
Name: "java_multiple_files",
Value: "true",
Comment: "// This option lets the proto compiler generate Java code inside the package\n" +
"// name (see below) instead of inside an outer class. It creates a simpler\n" +
"// developer experience by reducing one-level of name nesting and be\n" +
"// consistent with most programming languages that don't support outer classes.",
},
ProtoOption{
Name: "java_outer_classname",
Value: "OpenAPIProto",
Comment: "// The Java outer classname should be the filename in UpperCamelCase. This\n" +
"// class is only used to hold proto descriptor, so developers don't need to\n" +
"// work with it directly.",
},
ProtoOption{
Name: "java_package",
Value: "org." + packageName,
Comment: "// The Java package name must be proto package name with proper prefix.",
},
ProtoOption{
Name: "objc_class_prefix",
Value: "OAS",
Comment: "// A reasonable prefix for the Objective-C symbols generated from the package.\n" +
"// It should at a minimum be 3 characters long, all uppercase, and convention\n" +
"// is to use an abbreviation of the package name. Something short, but\n" +
"// hopefully unique enough to not conflict with things that may come along in\n" +
"// the future. 'GPB' is reserved for the protocol buffer implementation itself.",
},
}
}
func generateOpenAPIModel(version string) error {
var input string
var filename string
var protoPackageName string
switch version {
case "v2":
input = "openapi-2.0.json"
filename = "OpenAPIv2"
protoPackageName = "openapi.v2"
case "v3":
input = "openapi-3.0.json"
filename = "OpenAPIv3"
protoPackageName = "openapi.v3"
case "discovery":
input = "discovery.json"
filename = "discovery"
protoPackageName = "discovery.v1"
default:
return fmt.Errorf("Unknown OpenAPI version %s", version)
}
goPackageName := strings.Replace(protoPackageName, ".", "_", -1)
projectRoot := os.Getenv("GOPATH") + "/src/github.com/googleapis/gnostic/"
baseSchema, err := jsonschema.NewSchemaFromFile(projectRoot + "jsonschema/schema.json")
if err != nil {
return err
}
baseSchema.ResolveRefs()
baseSchema.ResolveAllOfs()
openapiSchema, err := jsonschema.NewSchemaFromFile(projectRoot + filename + "/" + input)
if err != nil {
return err
}
openapiSchema.ResolveRefs()
openapiSchema.ResolveAllOfs()
// build a simplified model of the types described by the schema
cc := NewDomain(openapiSchema, version)
// generators will map these patterns to the associated property names
// these pattern names are a bit of a hack until we find a more automated way to obtain them
switch version {
case "v2":
cc.TypeNameOverrides = map[string]string{
"VendorExtension": "Any",
}
cc.PropertyNameOverrides = map[string]string{
"PathItem": "Path",
"ResponseValue": "ResponseCode",
}
case "v3":
cc.TypeNameOverrides = map[string]string{
"SpecificationExtension": "Any",
}
cc.PropertyNameOverrides = map[string]string{
"PathItem": "Path",
"ResponseValue": "ResponseCode",
}
case "discovery":
cc.TypeNameOverrides = map[string]string{}
cc.PropertyNameOverrides = map[string]string{}
default:
return fmt.Errorf("Unknown OpenAPI version %s", version)
}
err = cc.Build()
if err != nil {
return err
}
if true {
log.Printf("Type Model:\n%s", cc.Description())
}
// ensure that the target directory exists
err = os.MkdirAll(projectRoot+filename, 0755)
if err != nil {
return err
}
// generate the protocol buffer description
log.Printf("Generating protocol buffer description")
proto := cc.generateProto(protoPackageName, License,
protoOptions(goPackageName), []string{"google/protobuf/any.proto"})
protoFileName := projectRoot + filename + "/" + filename + ".proto"
err = ioutil.WriteFile(protoFileName, []byte(proto), 0644)
if err != nil {
return err
}
// generate the compiler
log.Printf("Generating compiler support code")
compiler := cc.GenerateCompiler(goPackageName, License, []string{
"fmt",
"gopkg.in/yaml.v2",
"strings",
"regexp",
"github.com/googleapis/gnostic/compiler",
})
goFileName := projectRoot + filename + "/" + filename + ".go"
err = ioutil.WriteFile(goFileName, []byte(compiler), 0644)
if err != nil {
return err
}
// format the compiler
log.Printf("Formatting compiler support code")
return exec.Command(runtime.GOROOT()+"/bin/gofmt", "-w", goFileName).Run()
}
func usage() string {
return fmt.Sprintf(`
Usage: %s [OPTIONS]
Options:
--v2
Generate Protocol Buffer representation and support code for OpenAPI v2.
Files are read from and written to appropriate locations in the gnostic
project directory.
--v3
Generate Protocol Buffer representation and support code for OpenAPI v3
Files are read from and written to appropriate locations in the gnostic
project directory.
--extension EXTENSION_SCHEMA [EXTENSIONOPTIONS]
Generate a gnostic extension that reads a set of OpenAPI extensions.
EXTENSION_SCHEMA is the json schema for the OpenAPI extensions to be
supported.
EXTENSION_OPTIONS
--out_dir=PATH: Location for writing extension models and support code.
`, path.Base(os.Args[0]))
}
func main() {
var openapiVersion = ""
var generateExtensions = false
for i, arg := range os.Args {
if i == 0 {
continue // skip the tool name
}
if arg == "--v2" {
openapiVersion = "v2"
} else if arg == "--v3" {
openapiVersion = "v3"
} else if arg == "--discovery" {
openapiVersion = "discovery"
} else if arg == "--extension" {
generateExtensions = true
break
} else {
fmt.Printf("Unknown option: %s.\n%s\n", arg, usage())
os.Exit(-1)
}
}
if openapiVersion != "" {
err := generateOpenAPIModel(openapiVersion)
if err != nil {
fmt.Printf("%+v\n", err)
}
} else if generateExtensions {
err := processExtensionGenCommandline(usage())
if err != nil {
fmt.Printf("%+v\n", err)
}
} else {
fmt.Printf("%s\n", usage())
}
}

View File

@ -1,2 +0,0 @@
Schema SampleCompanyTwoPrimitiveString and SampleCompanyOnePrimitiveString have the same 'id' field value.

View File

@ -1,2 +0,0 @@
Schema SampleCompanyOnePrimitiveString has type 'unsupportedtype' which is not supported. Supported primitive types are [boolean integer number string].

View File

@ -1,12 +0,0 @@
{
"definitions": {
"SampleCompanyOnePrimitiveString": {
"type": "string",
"id": "x-samplecompanyone-mystr"
},
"SampleCompanyTwoPrimitiveString": {
"type": "string",
"id": "x-samplecompanyone-mystr"
}
}
}

View File

@ -1,8 +0,0 @@
{
"definitions": {
"SampleCompanyOnePrimitiveString": {
"type": "unsupportedtype",
"id": "x-samplecompanyone-mystr"
}
}
}

View File

@ -1,132 +0,0 @@
// 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 (
"fmt"
"strings"
"github.com/googleapis/gnostic/jsonschema"
)
/// Type Modeling
// TypeRequest models types that we encounter during model-building that have no named schema.
type TypeRequest struct {
Name string // name of type to be created
PropertyName string // name of a property that refers to this type
Schema *jsonschema.Schema // schema for type
OneOfWrapper bool // true if the type wraps "oneOfs"
}
// NewTypeRequest creates a TypeRequest.
func NewTypeRequest(name string, propertyName string, schema *jsonschema.Schema) *TypeRequest {
return &TypeRequest{Name: name, PropertyName: propertyName, Schema: schema}
}
// TypeProperty models type properties, eg. fields.
type TypeProperty struct {
Name string // name of property
Type string // type for property (scalar or message type)
StringEnumValues []string // possible values if this is an enumerated string type
MapType string // if this property is for a map, the name of the mapped type
Repeated bool // true if this property is repeated (an array)
Pattern string // if the property is a pattern property, names must match this pattern.
Implicit bool // true if this property is implied by a pattern or "additional properties" property
Description string // if present, the "description" field in the schema
}
func (typeProperty *TypeProperty) description() string {
result := ""
if typeProperty.Description != "" {
result += fmt.Sprintf("\t// %+s\n", typeProperty.Description)
}
if typeProperty.Repeated {
result += fmt.Sprintf("\t%s %s repeated %s\n", typeProperty.Name, typeProperty.Type, typeProperty.Pattern)
} else {
result += fmt.Sprintf("\t%s %s %s \n", typeProperty.Name, typeProperty.Type, typeProperty.Pattern)
}
return result
}
// NewTypeProperty creates a TypeProperty
func NewTypeProperty() *TypeProperty {
return &TypeProperty{}
}
// NewTypePropertyWithNameAndType creates a TypeProperty
func NewTypePropertyWithNameAndType(name string, typeName string) *TypeProperty {
return &TypeProperty{Name: name, Type: typeName}
}
// NewTypePropertyWithNameTypeAndPattern creates a TypeProperty
func NewTypePropertyWithNameTypeAndPattern(name string, typeName string, pattern string) *TypeProperty {
return &TypeProperty{Name: name, Type: typeName, Pattern: pattern}
}
// FieldName returns the message field name to use for a property.
func (typeProperty *TypeProperty) FieldName() string {
propertyName := typeProperty.Name
if propertyName == "$ref" {
return "XRef"
}
return strings.Title(snakeCaseToCamelCase(propertyName))
}
// TypeModel models types.
type TypeModel struct {
Name string // type name
Properties []*TypeProperty // slice of properties
Required []string // required property names
OneOfWrapper bool // true if this type wraps "oneof" properties
Open bool // open types can have keys outside the specified set
OpenPatterns []string // patterns for properties that we allow
IsStringArray bool // ugly override
IsItemArray bool // ugly override
IsBlob bool // ugly override
IsPair bool // type is a name-value pair used to support ordered maps
PairValueType string // type for pair values (valid if IsPair == true)
Description string // if present, the "description" field in the schema
}
func (typeModel *TypeModel) addProperty(property *TypeProperty) {
if typeModel.Properties == nil {
typeModel.Properties = make([]*TypeProperty, 0)
}
typeModel.Properties = append(typeModel.Properties, property)
}
func (typeModel *TypeModel) description() string {
result := ""
if typeModel.Description != "" {
result += fmt.Sprintf("// %+s\n", typeModel.Description)
}
var wrapperinfo string
if typeModel.OneOfWrapper {
wrapperinfo = " oneof wrapper"
}
result += fmt.Sprintf("%+s%s\n", typeModel.Name, wrapperinfo)
for _, property := range typeModel.Properties {
result += property.description()
}
return result
}
// NewTypeModel creates a TypeModel.
func NewTypeModel() *TypeModel {
typeModel := &TypeModel{}
typeModel.Properties = make([]*TypeProperty, 0)
return typeModel
}

View File

@ -1,610 +0,0 @@
// 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.
//go:generate ./COMPILE-PROTOS.sh
// Gnostic is a tool for building better REST APIs through knowledge.
//
// Gnostic reads declarative descriptions of REST APIs that conform
// to the OpenAPI Specification, reports errors, resolves internal
// dependencies, and puts the results in a binary form that can
// be used in any language that is supported by the Protocol Buffer
// tools.
//
// Gnostic models are validated and typed. This allows API tool
// developers to focus on their product and not worry about input
// validation and type checking.
//
// Gnostic calls plugins that implement a variety of API implementation
// and support features including generation of client and server
// support code.
package main
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"time"
"github.com/golang/protobuf/proto"
"github.com/googleapis/gnostic/OpenAPIv2"
"github.com/googleapis/gnostic/OpenAPIv3"
"github.com/googleapis/gnostic/compiler"
"github.com/googleapis/gnostic/discovery"
"github.com/googleapis/gnostic/jsonwriter"
plugins "github.com/googleapis/gnostic/plugins"
surface "github.com/googleapis/gnostic/surface"
"gopkg.in/yaml.v2"
)
const ( // Source Format
SourceFormatUnknown = 0
SourceFormatOpenAPI2 = 2
SourceFormatOpenAPI3 = 3
SourceFormatDiscovery = 4
)
// Determine the version of an OpenAPI description read from JSON or YAML.
func getOpenAPIVersionFromInfo(info interface{}) int {
m, ok := compiler.UnpackMap(info)
if !ok {
return SourceFormatUnknown
}
swagger, ok := compiler.MapValueForKey(m, "swagger").(string)
if ok && strings.HasPrefix(swagger, "2.0") {
return SourceFormatOpenAPI2
}
openapi, ok := compiler.MapValueForKey(m, "openapi").(string)
if ok && strings.HasPrefix(openapi, "3.0") {
return SourceFormatOpenAPI3
}
kind, ok := compiler.MapValueForKey(m, "kind").(string)
if ok && kind == "discovery#restDescription" {
return SourceFormatDiscovery
}
return SourceFormatUnknown
}
const (
pluginPrefix = "gnostic-"
extensionPrefix = "gnostic-x-"
)
type pluginCall struct {
Name string
Invocation string
}
// Invokes a plugin.
func (p *pluginCall) perform(document proto.Message, sourceFormat int, sourceName string, timePlugins bool) ([]*plugins.Message, error) {
if p.Name != "" {
request := &plugins.Request{}
// Infer the name of the executable by adding the prefix.
executableName := pluginPrefix + p.Name
// Validate invocation string with regular expression.
invocation := p.Invocation
//
// Plugin invocations must consist of
// zero or more comma-separated key=value pairs followed by a path.
// If pairs are present, a colon separates them from the path.
// Keys and values must be alphanumeric strings and may contain
// dashes, underscores, periods, or forward slashes.
// A path can contain any characters other than the separators ',', ':', and '='.
//
invocationRegex := regexp.MustCompile(`^([\w-_\/\.]+=[\w-_\/\.]+(,[\w-_\/\.]+=[\w-_\/\.]+)*:)?[^,:=]+$`)
if !invocationRegex.Match([]byte(p.Invocation)) {
return nil, fmt.Errorf("Invalid invocation of %s: %s", executableName, invocation)
}
invocationParts := strings.Split(p.Invocation, ":")
var outputLocation string
switch len(invocationParts) {
case 1:
outputLocation = invocationParts[0]
case 2:
parameters := strings.Split(invocationParts[0], ",")
for _, keyvalue := range parameters {
pair := strings.Split(keyvalue, "=")
if len(pair) == 2 {
request.Parameters = append(request.Parameters, &plugins.Parameter{Name: pair[0], Value: pair[1]})
}
}
outputLocation = invocationParts[1]
default:
// badly-formed request
outputLocation = invocationParts[len(invocationParts)-1]
}
version := &plugins.Version{}
version.Major = 0
version.Minor = 1
version.Patch = 0
request.CompilerVersion = version
request.OutputPath = outputLocation
request.SourceName = sourceName
switch sourceFormat {
case SourceFormatOpenAPI2:
request.AddModel("openapi.v2.Document", document)
// include experimental API surface model
surfaceModel, err := surface.NewModelFromOpenAPI2(document.(*openapi_v2.Document))
if err == nil {
request.AddModel("surface.v1.Model", surfaceModel)
}
case SourceFormatOpenAPI3:
request.AddModel("openapi.v3.Document", document)
// include experimental API surface model
surfaceModel, err := surface.NewModelFromOpenAPI3(document.(*openapi_v3.Document))
if err == nil {
request.AddModel("surface.v1.Model", surfaceModel)
}
case SourceFormatDiscovery:
request.AddModel("discovery.v1.Document", document)
default:
}
requestBytes, _ := proto.Marshal(request)
cmd := exec.Command(executableName, "-plugin")
cmd.Stdin = bytes.NewReader(requestBytes)
cmd.Stderr = os.Stderr
pluginStartTime := time.Now()
output, err := cmd.Output()
pluginElapsedTime := time.Since(pluginStartTime)
if timePlugins {
fmt.Printf("> %s (%s)\n", executableName, pluginElapsedTime)
}
if err != nil {
return nil, err
}
response := &plugins.Response{}
err = proto.Unmarshal(output, response)
if err != nil {
// Gnostic expects plugins to only write the
// response message to stdout. Be sure that
// any logging messages are written to stderr only.
return nil, errors.New("Invalid plugin response (plugins must write log messages to stderr, not stdout).")
}
plugins.HandleResponse(response, outputLocation)
return response.Messages, nil
}
return nil, nil
}
func isFile(path string) bool {
fileInfo, err := os.Stat(path)
if err != nil {
return false
}
return !fileInfo.IsDir()
}
func isDirectory(path string) bool {
fileInfo, err := os.Stat(path)
if err != nil {
return false
}
return fileInfo.IsDir()
}
// Write bytes to a named file.
// Certain names have special meaning:
// ! writes nothing
// - writes to stdout
// = writes to stderr
// If a directory name is given, the file is written there with
// a name derived from the source and extension arguments.
func writeFile(name string, bytes []byte, source string, extension string) {
var writer io.Writer
if name == "!" {
return
} else if name == "-" {
writer = os.Stdout
} else if name == "=" {
writer = os.Stderr
} else if isDirectory(name) {
base := filepath.Base(source)
// Remove the original source extension.
base = base[0 : len(base)-len(filepath.Ext(base))]
// Build the path that puts the result in the passed-in directory.
filename := name + "/" + base + "." + extension
file, _ := os.Create(filename)
defer file.Close()
writer = file
} else {
file, _ := os.Create(name)
defer file.Close()
writer = file
}
writer.Write(bytes)
if name == "-" || name == "=" {
writer.Write([]byte("\n"))
}
}
// The Gnostic structure holds global state information for gnostic.
type Gnostic struct {
usage string
sourceName string
binaryOutputPath string
textOutputPath string
yamlOutputPath string
jsonOutputPath string
errorOutputPath string
messageOutputPath string
resolveReferences bool
pluginCalls []*pluginCall
extensionHandlers []compiler.ExtensionHandler
sourceFormat int
timePlugins bool
}
// Initialize a structure to store global application state.
func newGnostic() *Gnostic {
g := &Gnostic{}
// Option fields initialize to their default values.
g.usage = `
Usage: gnostic SOURCE [OPTIONS]
SOURCE is the filename or URL of an API description.
Options:
--pb-out=PATH Write a binary proto to the specified location.
--text-out=PATH Write a text proto to the specified location.
--json-out=PATH Write a json API description to the specified location.
--yaml-out=PATH Write a yaml API description to the specified location.
--errors-out=PATH Write compilation errors to the specified location.
--messages-out=PATH Write messages generated by plugins to the specified
location. Messages from all plugin invocations are
written to a single common file.
--PLUGIN-out=PATH Run the plugin named gnostic-PLUGIN and write results
to the specified location.
--PLUGIN Run the plugin named gnostic-PLUGIN but don't write any
results. Used for plugins that return messages only.
PLUGIN must not match any other gnostic option.
--x-EXTENSION Use the extension named gnostic-x-EXTENSION
to process OpenAPI specification extensions.
--resolve-refs Explicitly resolve $ref references.
This could have problems with recursive definitions.
--time-plugins Report plugin runtimes.
`
// Initialize internal structures.
g.pluginCalls = make([]*pluginCall, 0)
g.extensionHandlers = make([]compiler.ExtensionHandler, 0)
return g
}
// Parse command-line options.
func (g *Gnostic) readOptions() {
// plugin processing matches patterns of the form "--PLUGIN-out=PATH" and "--PLUGIN_out=PATH"
pluginRegex := regexp.MustCompile("--(.+)[-_]out=(.+)")
// extension processing matches patterns of the form "--x-EXTENSION"
extensionRegex := regexp.MustCompile("--x-(.+)")
for i, arg := range os.Args {
if i == 0 {
continue // skip the tool name
}
var m [][]byte
if m = pluginRegex.FindSubmatch([]byte(arg)); m != nil {
pluginName := string(m[1])
invocation := string(m[2])
switch pluginName {
case "pb":
g.binaryOutputPath = invocation
case "text":
g.textOutputPath = invocation
case "json":
g.jsonOutputPath = invocation
case "yaml":
g.yamlOutputPath = invocation
case "errors":
g.errorOutputPath = invocation
case "messages":
g.messageOutputPath = invocation
default:
p := &pluginCall{Name: pluginName, Invocation: invocation}
g.pluginCalls = append(g.pluginCalls, p)
}
} else if m = extensionRegex.FindSubmatch([]byte(arg)); m != nil {
extensionName := string(m[1])
extensionHandler := compiler.ExtensionHandler{Name: extensionPrefix + extensionName}
g.extensionHandlers = append(g.extensionHandlers, extensionHandler)
} else if arg == "--resolve-refs" {
g.resolveReferences = true
} else if arg == "--time-plugins" {
g.timePlugins = true
} else if arg[0] == '-' && arg[1] == '-' {
// try letting the option specify a plugin with no output files (or unwanted output files)
// this is useful for calling plugins like linters that only return messages
p := &pluginCall{Name: arg[2:len(arg)], Invocation: "!"}
g.pluginCalls = append(g.pluginCalls, p)
} else if arg[0] == '-' {
fmt.Fprintf(os.Stderr, "Unknown option: %s.\n%s\n", arg, g.usage)
os.Exit(-1)
} else {
g.sourceName = arg
}
}
}
// Validate command-line options.
func (g *Gnostic) validateOptions() {
if g.binaryOutputPath == "" &&
g.textOutputPath == "" &&
g.yamlOutputPath == "" &&
g.jsonOutputPath == "" &&
g.errorOutputPath == "" &&
len(g.pluginCalls) == 0 {
fmt.Fprintf(os.Stderr, "Missing output directives.\n%s\n", g.usage)
os.Exit(-1)
}
if g.sourceName == "" {
fmt.Fprintf(os.Stderr, "No input specified.\n%s\n", g.usage)
os.Exit(-1)
}
// If we get here and the error output is unspecified, write errors to stderr.
if g.errorOutputPath == "" {
g.errorOutputPath = "="
}
}
// Generate an error message to be written to stderr or a file.
func (g *Gnostic) errorBytes(err error) []byte {
return []byte("Errors reading " + g.sourceName + "\n" + err.Error())
}
// Read an OpenAPI description from YAML or JSON.
func (g *Gnostic) readOpenAPIText(bytes []byte) (message proto.Message, err error) {
info, err := compiler.ReadInfoFromBytes(g.sourceName, bytes)
if err != nil {
return nil, err
}
// Determine the OpenAPI version.
g.sourceFormat = getOpenAPIVersionFromInfo(info)
if g.sourceFormat == SourceFormatUnknown {
return nil, errors.New("unable to identify OpenAPI version")
}
// Compile to the proto model.
if g.sourceFormat == SourceFormatOpenAPI2 {
document, err := openapi_v2.NewDocument(info, compiler.NewContextWithExtensions("$root", nil, &g.extensionHandlers))
if err != nil {
return nil, err
}
message = document
} else if g.sourceFormat == SourceFormatOpenAPI3 {
document, err := openapi_v3.NewDocument(info, compiler.NewContextWithExtensions("$root", nil, &g.extensionHandlers))
if err != nil {
return nil, err
}
message = document
} else {
document, err := discovery_v1.NewDocument(info, compiler.NewContextWithExtensions("$root", nil, &g.extensionHandlers))
if err != nil {
return nil, err
}
message = document
}
return message, err
}
// Read an OpenAPI binary file.
func (g *Gnostic) readOpenAPIBinary(data []byte) (message proto.Message, err error) {
// try to read an OpenAPI v3 document
documentV3 := &openapi_v3.Document{}
err = proto.Unmarshal(data, documentV3)
if err == nil && strings.HasPrefix(documentV3.Openapi, "3.0") {
g.sourceFormat = SourceFormatOpenAPI3
return documentV3, nil
}
// if that failed, try to read an OpenAPI v2 document
documentV2 := &openapi_v2.Document{}
err = proto.Unmarshal(data, documentV2)
if err == nil && strings.HasPrefix(documentV2.Swagger, "2.0") {
g.sourceFormat = SourceFormatOpenAPI2
return documentV2, nil
}
// if that failed, try to read a Discovery Format document
discoveryDocument := &discovery_v1.Document{}
err = proto.Unmarshal(data, discoveryDocument)
if err == nil { // && strings.HasPrefix(documentV2.Swagger, "2.0") {
g.sourceFormat = SourceFormatDiscovery
return discoveryDocument, nil
}
return nil, err
}
// Write a binary pb representation.
func (g *Gnostic) writeBinaryOutput(message proto.Message) {
protoBytes, err := proto.Marshal(message)
if err != nil {
writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors")
defer os.Exit(-1)
} else {
writeFile(g.binaryOutputPath, protoBytes, g.sourceName, "pb")
}
}
// Write a text pb representation.
func (g *Gnostic) writeTextOutput(message proto.Message) {
bytes := []byte(proto.MarshalTextString(message))
writeFile(g.textOutputPath, bytes, g.sourceName, "text")
}
// Write JSON/YAML OpenAPI representations.
func (g *Gnostic) writeJSONYAMLOutput(message proto.Message) {
// Convert the OpenAPI document into an exportable MapSlice.
var rawInfo yaml.MapSlice
var ok bool
var err error
if g.sourceFormat == SourceFormatOpenAPI2 {
document := message.(*openapi_v2.Document)
rawInfo, ok = document.ToRawInfo().(yaml.MapSlice)
if !ok {
rawInfo = nil
}
} else if g.sourceFormat == SourceFormatOpenAPI3 {
document := message.(*openapi_v3.Document)
rawInfo, ok = document.ToRawInfo().(yaml.MapSlice)
if !ok {
rawInfo = nil
}
} else if g.sourceFormat == SourceFormatDiscovery {
document := message.(*discovery_v1.Document)
rawInfo, ok = document.ToRawInfo().(yaml.MapSlice)
if !ok {
rawInfo = nil
}
}
// Optionally write description in yaml format.
if g.yamlOutputPath != "" {
var bytes []byte
if rawInfo != nil {
bytes, err = yaml.Marshal(rawInfo)
if err != nil {
fmt.Fprintf(os.Stderr, "Error generating yaml output %s\n", err.Error())
}
writeFile(g.yamlOutputPath, bytes, g.sourceName, "yaml")
} else {
fmt.Fprintf(os.Stderr, "No yaml output available.\n")
}
}
// Optionally write description in json format.
if g.jsonOutputPath != "" {
var bytes []byte
if rawInfo != nil {
bytes, _ = jsonwriter.Marshal(rawInfo)
if err != nil {
fmt.Fprintf(os.Stderr, "Error generating json output %s\n", err.Error())
}
writeFile(g.jsonOutputPath, bytes, g.sourceName, "json")
} else {
fmt.Fprintf(os.Stderr, "No json output available.\n")
}
}
}
// Write messages.
func (g *Gnostic) writeMessagesOutput(message proto.Message) {
protoBytes, err := proto.Marshal(message)
if err != nil {
writeFile(g.messageOutputPath, g.errorBytes(err), g.sourceName, "errors")
defer os.Exit(-1)
} else {
writeFile(g.messageOutputPath, protoBytes, g.sourceName, "messages.pb")
}
}
// Perform all actions specified in the command-line options.
func (g *Gnostic) performActions(message proto.Message) (err error) {
// Optionally resolve internal references.
if g.resolveReferences {
if g.sourceFormat == SourceFormatOpenAPI2 {
document := message.(*openapi_v2.Document)
_, err = document.ResolveReferences(g.sourceName)
} else if g.sourceFormat == SourceFormatOpenAPI3 {
document := message.(*openapi_v3.Document)
_, err = document.ResolveReferences(g.sourceName)
}
if err != nil {
return err
}
}
// Optionally write proto in binary format.
if g.binaryOutputPath != "" {
g.writeBinaryOutput(message)
}
// Optionally write proto in text format.
if g.textOutputPath != "" {
g.writeTextOutput(message)
}
// Optionally write document in yaml and/or json formats.
if g.yamlOutputPath != "" || g.jsonOutputPath != "" {
g.writeJSONYAMLOutput(message)
}
// Call all specified plugins.
messages := make([]*plugins.Message, 0)
for _, p := range g.pluginCalls {
pluginMessages, err := p.perform(message, g.sourceFormat, g.sourceName, g.timePlugins)
if err != nil {
writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors")
defer os.Exit(-1) // run all plugins, even when some have errors
}
messages = append(messages, pluginMessages...)
}
if g.messageOutputPath != "" {
g.writeMessagesOutput(&plugins.Messages{Messages: messages})
} else {
// Print any messages from the plugins
if len(messages) > 0 {
for _, message := range messages {
fmt.Printf("%+v\n", message)
}
}
}
return nil
}
func (g *Gnostic) main() {
var err error
g.readOptions()
g.validateOptions()
// Read the OpenAPI source.
bytes, err := compiler.ReadBytesForFile(g.sourceName)
if err != nil {
writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors")
os.Exit(-1)
}
extension := strings.ToLower(filepath.Ext(g.sourceName))
var message proto.Message
if extension == ".json" || extension == ".yaml" {
// Try to read the source as JSON/YAML.
message, err = g.readOpenAPIText(bytes)
if err != nil {
writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors")
os.Exit(-1)
}
} else if extension == ".pb" {
// Try to read the source as a binary protocol buffer.
message, err = g.readOpenAPIBinary(bytes)
if err != nil {
writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors")
os.Exit(-1)
}
} else {
err = errors.New("unknown file extension. 'json', 'yaml', and 'pb' are accepted")
writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors")
os.Exit(-1)
}
// Perform actions specified by command options.
err = g.performActions(message)
if err != nil {
writeFile(g.errorOutputPath, g.errorBytes(err), g.sourceName, "errors")
os.Exit(-1)
}
}
func main() {
g := newGnostic()
g.main()
}

View File

@ -1,453 +0,0 @@
package main
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
func testCompiler(t *testing.T, inputFile string, referenceFile string, expectErrors bool) {
textFile := strings.Replace(filepath.Base(inputFile), filepath.Ext(inputFile), ".text", 1)
errorsFile := strings.Replace(filepath.Base(inputFile), filepath.Ext(inputFile), ".errors", 1)
// remove any preexisting output files
os.Remove(textFile)
os.Remove(errorsFile)
// run the compiler
var err error
var cmd = exec.Command(
"gnostic",
inputFile,
"--text-out=.",
"--errors-out=.",
"--resolve-refs")
//t.Log(cmd.Args)
err = cmd.Run()
if err != nil && !expectErrors {
t.Logf("Compile failed: %+v", err)
t.FailNow()
}
// verify the output against a reference
var outputFile string
if expectErrors {
outputFile = errorsFile
} else {
outputFile = textFile
}
err = exec.Command("diff", outputFile, referenceFile).Run()
if err != nil {
t.Logf("Diff failed: %+v", err)
t.FailNow()
} else {
// if the test succeeded, clean up
os.Remove(textFile)
os.Remove(errorsFile)
}
}
func testNormal(t *testing.T, inputFile string, referenceFile string) {
testCompiler(t, inputFile, referenceFile, false)
}
func testErrors(t *testing.T, inputFile string, referenceFile string) {
testCompiler(t, inputFile, referenceFile, true)
}
func TestPetstoreJSON(t *testing.T) {
testNormal(t,
"examples/v2.0/json/petstore.json",
"test/v2.0/petstore.text")
}
func TestPetstoreYAML(t *testing.T) {
testNormal(t,
"examples/v2.0/yaml/petstore.yaml",
"test/v2.0/petstore.text")
}
func TestSeparateYAML(t *testing.T) {
testNormal(t,
"examples/v2.0/yaml/petstore-separate/spec/swagger.yaml",
"test/v2.0/yaml/petstore-separate/spec/swagger.text")
}
func TestSeparateJSON(t *testing.T) {
testNormal(t,
"examples/v2.0/json/petstore-separate/spec/swagger.json",
"test/v2.0/yaml/petstore-separate/spec/swagger.text") // yaml and json results should be identical
}
func TestRemotePetstoreJSON(t *testing.T) {
testNormal(t,
"https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/json/petstore.json",
"test/v2.0/petstore.text")
}
func TestRemotePetstoreYAML(t *testing.T) {
testNormal(t,
"https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/yaml/petstore.yaml",
"test/v2.0/petstore.text")
}
func TestRemoteSeparateYAML(t *testing.T) {
testNormal(t,
"https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/yaml/petstore-separate/spec/swagger.yaml",
"test/v2.0/yaml/petstore-separate/spec/swagger.text")
}
func TestRemoteSeparateJSON(t *testing.T) {
testNormal(t,
"https://raw.githubusercontent.com/googleapis/openapi-compiler/master/examples/v2.0/json/petstore-separate/spec/swagger.json",
"test/v2.0/yaml/petstore-separate/spec/swagger.text")
}
func TestErrorBadProperties(t *testing.T) {
testErrors(t,
"examples/errors/petstore-badproperties.yaml",
"test/errors/petstore-badproperties.errors")
}
func TestErrorUnresolvedRefs(t *testing.T) {
testErrors(t,
"examples/errors/petstore-unresolvedrefs.yaml",
"test/errors/petstore-unresolvedrefs.errors")
}
func TestErrorMissingVersion(t *testing.T) {
testErrors(t,
"examples/errors/petstore-missingversion.yaml",
"test/errors/petstore-missingversion.errors")
}
func testPlugin(t *testing.T, plugin string, inputFile string, outputFile string, referenceFile string) {
// remove any preexisting output files
os.Remove(outputFile)
// run the compiler
var err error
output, err := exec.Command(
"gnostic",
"--"+plugin+"-out=-",
inputFile).Output()
if err != nil {
t.Logf("Compile failed: %+v", err)
t.FailNow()
}
_ = ioutil.WriteFile(outputFile, output, 0644)
err = exec.Command("diff", outputFile, referenceFile).Run()
if err != nil {
t.Logf("Diff failed: %+v", err)
t.FailNow()
} else {
// if the test succeeded, clean up
os.Remove(outputFile)
}
}
func TestSamplePluginWithPetstore(t *testing.T) {
testPlugin(t,
"summary",
"examples/v2.0/yaml/petstore.yaml",
"sample-petstore.out",
"test/v2.0/yaml/sample-petstore.out")
}
func TestErrorInvalidPluginInvocations(t *testing.T) {
var err error
output, err := exec.Command(
"gnostic",
"examples/v2.0/yaml/petstore.yaml",
"--errors-out=-",
"--plugin-out=foo=bar,:abc",
"--plugin-out=,foo=bar:abc",
"--plugin-out=foo=:abc",
"--plugin-out==bar:abc",
"--plugin-out=,,:abc",
"--plugin-out=foo=bar=baz:abc",
).Output()
if err == nil {
t.Logf("Invalid invocations were accepted")
t.FailNow()
}
outputFile := "invalid-plugin-invocation.errors"
_ = ioutil.WriteFile(outputFile, output, 0644)
err = exec.Command("diff", outputFile, "test/errors/invalid-plugin-invocation.errors").Run()
if err != nil {
t.Logf("Diff failed: %+v", err)
t.FailNow()
} else {
// if the test succeeded, clean up
os.Remove(outputFile)
}
}
func TestValidPluginInvocations(t *testing.T) {
var err error
output, err := exec.Command(
"gnostic",
"examples/v2.0/yaml/petstore.yaml",
"--errors-out=-",
// verify an invocation with no parameters
"--summary-out=!", // "!" indicates that no output should be generated
// verify single pair of parameters
"--summary-out=a=b:!",
// verify multiple parameters
"--summary-out=a=b,c=123,xyz=alphabetagammadelta:!",
// verify that special characters / . - _ can be included in parameter keys and values
"--summary-out=a/b/c=x/y/z:!",
"--summary-out=a.b.c=x.y.z:!",
"--summary-out=a-b-c=x-y-z:!",
"--summary-out=a_b_c=x_y_z:!",
).Output()
if len(output) != 0 {
t.Logf("Valid invocations generated invalid errors\n%s", string(output))
t.FailNow()
}
if err != nil {
t.Logf("Valid invocations were not accepted")
t.FailNow()
}
}
func TestExtensionHandlerWithLibraryExample(t *testing.T) {
outputFile := "library-example-with-ext.text.out"
inputFile := "test/library-example-with-ext.json"
referenceFile := "test/library-example-with-ext.text.out"
os.Remove(outputFile)
// run the compiler
var err error
command := exec.Command(
"gnostic",
"--x-sampleone",
"--x-sampletwo",
"--text-out="+outputFile,
"--resolve-refs",
inputFile)
_, err = command.Output()
if err != nil {
t.Logf("Compile failed for command %v: %+v", command, err)
t.FailNow()
}
//_ = ioutil.WriteFile(outputFile, output, 0644)
err = exec.Command("diff", outputFile, referenceFile).Run()
if err != nil {
t.Logf("Diff failed: %+v", err)
t.FailNow()
} else {
// if the test succeeded, clean up
os.Remove(outputFile)
}
}
func TestJSONOutput(t *testing.T) {
inputFile := "test/library-example-with-ext.json"
textFile := "sample.text"
jsonFile := "sample.json"
textFile2 := "sample2.text"
jsonFile2 := "sample2.json"
os.Remove(textFile)
os.Remove(jsonFile)
os.Remove(textFile2)
os.Remove(jsonFile2)
var err error
// Run the compiler once.
command := exec.Command(
"gnostic",
"--text-out="+textFile,
"--json-out="+jsonFile,
inputFile)
_, err = command.Output()
if err != nil {
t.Logf("Compile failed for command %v: %+v", command, err)
t.FailNow()
}
// Run the compiler again, this time on the generated output.
command = exec.Command(
"gnostic",
"--text-out="+textFile2,
"--json-out="+jsonFile2,
jsonFile)
_, err = command.Output()
if err != nil {
t.Logf("Compile failed for command %v: %+v", command, err)
t.FailNow()
}
// Verify that both models have the same internal representation.
err = exec.Command("diff", textFile, textFile2).Run()
if err != nil {
t.Logf("Diff failed: %+v", err)
t.FailNow()
} else {
// if the test succeeded, clean up
os.Remove(textFile)
os.Remove(jsonFile)
os.Remove(textFile2)
os.Remove(jsonFile2)
}
}
func TestYAMLOutput(t *testing.T) {
inputFile := "test/library-example-with-ext.json"
textFile := "sample.text"
yamlFile := "sample.yaml"
textFile2 := "sample2.text"
yamlFile2 := "sample2.yaml"
os.Remove(textFile)
os.Remove(yamlFile)
os.Remove(textFile2)
os.Remove(yamlFile2)
var err error
// Run the compiler once.
command := exec.Command(
"gnostic",
"--text-out="+textFile,
"--yaml-out="+yamlFile,
inputFile)
_, err = command.Output()
if err != nil {
t.Logf("Compile failed for command %v: %+v", command, err)
t.FailNow()
}
// Run the compiler again, this time on the generated output.
command = exec.Command(
"gnostic",
"--text-out="+textFile2,
"--yaml-out="+yamlFile2,
yamlFile)
_, err = command.Output()
if err != nil {
t.Logf("Compile failed for command %v: %+v", command, err)
t.FailNow()
}
// Verify that both models have the same internal representation.
err = exec.Command("diff", textFile, textFile2).Run()
if err != nil {
t.Logf("Diff failed: %+v", err)
t.FailNow()
} else {
// if the test succeeded, clean up
os.Remove(textFile)
os.Remove(yamlFile)
os.Remove(textFile2)
os.Remove(yamlFile2)
}
}
func testBuilder(version string, t *testing.T) {
var err error
pbFile := "petstore-" + version + ".pb"
yamlFile := "petstore.yaml"
jsonFile := "petstore.json"
textFile := "petstore.text"
textReference := "test/" + version + ".0/petstore.text"
os.Remove(pbFile)
os.Remove(textFile)
os.Remove(yamlFile)
os.Remove(jsonFile)
// Generate petstore.pb.
command := exec.Command(
"petstore-builder",
"--"+version)
_, err = command.Output()
if err != nil {
t.Logf("Command %v failed: %+v", command, err)
t.FailNow()
}
// Convert petstore.pb to yaml and json.
command = exec.Command(
"gnostic",
pbFile,
"--json-out="+jsonFile,
"--yaml-out="+yamlFile)
_, err = command.Output()
if err != nil {
t.Logf("Command %v failed: %+v", command, err)
t.FailNow()
}
// Read petstore.yaml, resolve references, and export text.
command = exec.Command(
"gnostic",
yamlFile,
"--resolve-refs",
"--text-out="+textFile)
_, err = command.Output()
if err != nil {
t.Logf("Command %v failed: %+v", command, err)
t.FailNow()
}
// Verify that the generated text matches our reference.
err = exec.Command("diff", textFile, textReference).Run()
if err != nil {
t.Logf("Diff failed: %+v", err)
t.FailNow()
}
// Read petstore.json, resolve references, and export text.
command = exec.Command(
"gnostic",
jsonFile,
"--resolve-refs",
"--text-out="+textFile)
_, err = command.Output()
if err != nil {
t.Logf("Command %v failed: %+v", command, err)
t.FailNow()
}
// Verify that the generated text matches our reference.
err = exec.Command("diff", textFile, textReference).Run()
if err != nil {
t.Logf("Diff failed: %+v", err)
t.FailNow()
}
// if the test succeeded, clean up
os.Remove(pbFile)
os.Remove(textFile)
os.Remove(yamlFile)
os.Remove(jsonFile)
}
func TestBuilderV2(t *testing.T) {
testBuilder("v2", t)
}
func TestBuilderV3(t *testing.T) {
testBuilder("v3", t)
}
// OpenAPI 3.0 tests
func TestPetstoreYAML_30(t *testing.T) {
testNormal(t,
"examples/v3.0/yaml/petstore.yaml",
"test/v3.0/petstore.text")
}
func TestPetstoreJSON_30(t *testing.T) {
testNormal(t,
"examples/v3.0/json/petstore.json",
"test/v3.0/petstore.text")
}

View File

@ -1,3 +0,0 @@
# jsonschema
This directory contains code for reading, writing, and manipulating JSON schemas.

View File

@ -1,229 +0,0 @@
// 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 jsonschema
import (
"fmt"
"strings"
)
//
// DISPLAY
// The following methods display Schemas.
//
// Description returns a string representation of a string or string array.
func (s *StringOrStringArray) Description() string {
if s.String != nil {
return *s.String
}
if s.StringArray != nil {
return strings.Join(*s.StringArray, ", ")
}
return ""
}
// Returns a string representation of a Schema.
func (schema *Schema) String() string {
return schema.describeSchema("")
}
// Helper: Returns a string representation of a Schema indented by a specified string.
func (schema *Schema) describeSchema(indent string) string {
result := ""
if schema.Schema != nil {
result += indent + "$schema: " + *(schema.Schema) + "\n"
}
if schema.ID != nil {
result += indent + "id: " + *(schema.ID) + "\n"
}
if schema.MultipleOf != nil {
result += indent + fmt.Sprintf("multipleOf: %+v\n", *(schema.MultipleOf))
}
if schema.Maximum != nil {
result += indent + fmt.Sprintf("maximum: %+v\n", *(schema.Maximum))
}
if schema.ExclusiveMaximum != nil {
result += indent + fmt.Sprintf("exclusiveMaximum: %+v\n", *(schema.ExclusiveMaximum))
}
if schema.Minimum != nil {
result += indent + fmt.Sprintf("minimum: %+v\n", *(schema.Minimum))
}
if schema.ExclusiveMinimum != nil {
result += indent + fmt.Sprintf("exclusiveMinimum: %+v\n", *(schema.ExclusiveMinimum))
}
if schema.MaxLength != nil {
result += indent + fmt.Sprintf("maxLength: %+v\n", *(schema.MaxLength))
}
if schema.MinLength != nil {
result += indent + fmt.Sprintf("minLength: %+v\n", *(schema.MinLength))
}
if schema.Pattern != nil {
result += indent + fmt.Sprintf("pattern: %+v\n", *(schema.Pattern))
}
if schema.AdditionalItems != nil {
s := schema.AdditionalItems.Schema
if s != nil {
result += indent + "additionalItems:\n"
result += s.describeSchema(indent + " ")
} else {
b := *(schema.AdditionalItems.Boolean)
result += indent + fmt.Sprintf("additionalItems: %+v\n", b)
}
}
if schema.Items != nil {
result += indent + "items:\n"
items := schema.Items
if items.SchemaArray != nil {
for i, s := range *(items.SchemaArray) {
result += indent + " " + fmt.Sprintf("%d", i) + ":\n"
result += s.describeSchema(indent + " " + " ")
}
} else if items.Schema != nil {
result += items.Schema.describeSchema(indent + " " + " ")
}
}
if schema.MaxItems != nil {
result += indent + fmt.Sprintf("maxItems: %+v\n", *(schema.MaxItems))
}
if schema.MinItems != nil {
result += indent + fmt.Sprintf("minItems: %+v\n", *(schema.MinItems))
}
if schema.UniqueItems != nil {
result += indent + fmt.Sprintf("uniqueItems: %+v\n", *(schema.UniqueItems))
}
if schema.MaxProperties != nil {
result += indent + fmt.Sprintf("maxProperties: %+v\n", *(schema.MaxProperties))
}
if schema.MinProperties != nil {
result += indent + fmt.Sprintf("minProperties: %+v\n", *(schema.MinProperties))
}
if schema.Required != nil {
result += indent + fmt.Sprintf("required: %+v\n", *(schema.Required))
}
if schema.AdditionalProperties != nil {
s := schema.AdditionalProperties.Schema
if s != nil {
result += indent + "additionalProperties:\n"
result += s.describeSchema(indent + " ")
} else {
b := *(schema.AdditionalProperties.Boolean)
result += indent + fmt.Sprintf("additionalProperties: %+v\n", b)
}
}
if schema.Properties != nil {
result += indent + "properties:\n"
for _, pair := range *(schema.Properties) {
name := pair.Name
s := pair.Value
result += indent + " " + name + ":\n"
result += s.describeSchema(indent + " " + " ")
}
}
if schema.PatternProperties != nil {
result += indent + "patternProperties:\n"
for _, pair := range *(schema.PatternProperties) {
name := pair.Name
s := pair.Value
result += indent + " " + name + ":\n"
result += s.describeSchema(indent + " " + " ")
}
}
if schema.Dependencies != nil {
result += indent + "dependencies:\n"
for _, pair := range *(schema.Dependencies) {
name := pair.Name
schemaOrStringArray := pair.Value
s := schemaOrStringArray.Schema
if s != nil {
result += indent + " " + name + ":\n"
result += s.describeSchema(indent + " " + " ")
} else {
a := schemaOrStringArray.StringArray
if a != nil {
result += indent + " " + name + ":\n"
for _, s2 := range *a {
result += indent + " " + " " + s2 + "\n"
}
}
}
}
}
if schema.Enumeration != nil {
result += indent + "enumeration:\n"
for _, value := range *(schema.Enumeration) {
if value.String != nil {
result += indent + " " + fmt.Sprintf("%+v\n", *value.String)
} else {
result += indent + " " + fmt.Sprintf("%+v\n", *value.Bool)
}
}
}
if schema.Type != nil {
result += indent + fmt.Sprintf("type: %+v\n", schema.Type.Description())
}
if schema.AllOf != nil {
result += indent + "allOf:\n"
for _, s := range *(schema.AllOf) {
result += s.describeSchema(indent + " ")
result += indent + "-\n"
}
}
if schema.AnyOf != nil {
result += indent + "anyOf:\n"
for _, s := range *(schema.AnyOf) {
result += s.describeSchema(indent + " ")
result += indent + "-\n"
}
}
if schema.OneOf != nil {
result += indent + "oneOf:\n"
for _, s := range *(schema.OneOf) {
result += s.describeSchema(indent + " ")
result += indent + "-\n"
}
}
if schema.Not != nil {
result += indent + "not:\n"
result += schema.Not.describeSchema(indent + " ")
}
if schema.Definitions != nil {
result += indent + "definitions:\n"
for _, pair := range *(schema.Definitions) {
name := pair.Name
s := pair.Value
result += indent + " " + name + ":\n"
result += s.describeSchema(indent + " " + " ")
}
}
if schema.Title != nil {
result += indent + "title: " + *(schema.Title) + "\n"
}
if schema.Description != nil {
result += indent + "description: " + *(schema.Description) + "\n"
}
if schema.Default != nil {
result += indent + "default:\n"
result += indent + fmt.Sprintf(" %+v\n", *(schema.Default))
}
if schema.Format != nil {
result += indent + "format: " + *(schema.Format) + "\n"
}
if schema.Ref != nil {
result += indent + "$ref: " + *(schema.Ref) + "\n"
}
return result
}

View File

@ -1,226 +0,0 @@
// 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 jsonschema supports the reading, writing, and manipulation
// of JSON Schemas.
package jsonschema
// The Schema struct models a JSON Schema and, because schemas are
// defined hierarchically, contains many references to itself.
// All fields are pointers and are nil if the associated values
// are not specified.
type Schema struct {
Schema *string // $schema
ID *string // id keyword used for $ref resolution scope
Ref *string // $ref, i.e. JSON Pointers
// http://json-schema.org/latest/json-schema-validation.html
// 5.1. Validation keywords for numeric instances (number and integer)
MultipleOf *SchemaNumber
Maximum *SchemaNumber
ExclusiveMaximum *bool
Minimum *SchemaNumber
ExclusiveMinimum *bool
// 5.2. Validation keywords for strings
MaxLength *int64
MinLength *int64
Pattern *string
// 5.3. Validation keywords for arrays
AdditionalItems *SchemaOrBoolean
Items *SchemaOrSchemaArray
MaxItems *int64
MinItems *int64
UniqueItems *bool
// 5.4. Validation keywords for objects
MaxProperties *int64
MinProperties *int64
Required *[]string
AdditionalProperties *SchemaOrBoolean
Properties *[]*NamedSchema
PatternProperties *[]*NamedSchema
Dependencies *[]*NamedSchemaOrStringArray
// 5.5. Validation keywords for any instance type
Enumeration *[]SchemaEnumValue
Type *StringOrStringArray
AllOf *[]*Schema
AnyOf *[]*Schema
OneOf *[]*Schema
Not *Schema
Definitions *[]*NamedSchema
// 6. Metadata keywords
Title *string
Description *string
Default *interface{}
// 7. Semantic validation with "format"
Format *string
}
// These helper structs represent "combination" types that generally can
// have values of one type or another. All are used to represent parts
// of Schemas.
// SchemaNumber represents a value that can be either an Integer or a Float.
type SchemaNumber struct {
Integer *int64
Float *float64
}
// NewSchemaNumberWithInteger creates and returns a new object
func NewSchemaNumberWithInteger(i int64) *SchemaNumber {
result := &SchemaNumber{}
result.Integer = &i
return result
}
// NewSchemaNumberWithFloat creates and returns a new object
func NewSchemaNumberWithFloat(f float64) *SchemaNumber {
result := &SchemaNumber{}
result.Float = &f
return result
}
// SchemaOrBoolean represents a value that can be either a Schema or a Boolean.
type SchemaOrBoolean struct {
Schema *Schema
Boolean *bool
}
// NewSchemaOrBooleanWithSchema creates and returns a new object
func NewSchemaOrBooleanWithSchema(s *Schema) *SchemaOrBoolean {
result := &SchemaOrBoolean{}
result.Schema = s
return result
}
// NewSchemaOrBooleanWithBoolean creates and returns a new object
func NewSchemaOrBooleanWithBoolean(b bool) *SchemaOrBoolean {
result := &SchemaOrBoolean{}
result.Boolean = &b
return result
}
// StringOrStringArray represents a value that can be either
// a String or an Array of Strings.
type StringOrStringArray struct {
String *string
StringArray *[]string
}
// NewStringOrStringArrayWithString creates and returns a new object
func NewStringOrStringArrayWithString(s string) *StringOrStringArray {
result := &StringOrStringArray{}
result.String = &s
return result
}
// NewStringOrStringArrayWithStringArray creates and returns a new object
func NewStringOrStringArrayWithStringArray(a []string) *StringOrStringArray {
result := &StringOrStringArray{}
result.StringArray = &a
return result
}
// SchemaOrStringArray represents a value that can be either
// a Schema or an Array of Strings.
type SchemaOrStringArray struct {
Schema *Schema
StringArray *[]string
}
// SchemaOrSchemaArray represents a value that can be either
// a Schema or an Array of Schemas.
type SchemaOrSchemaArray struct {
Schema *Schema
SchemaArray *[]*Schema
}
// NewSchemaOrSchemaArrayWithSchema creates and returns a new object
func NewSchemaOrSchemaArrayWithSchema(s *Schema) *SchemaOrSchemaArray {
result := &SchemaOrSchemaArray{}
result.Schema = s
return result
}
// NewSchemaOrSchemaArrayWithSchemaArray creates and returns a new object
func NewSchemaOrSchemaArrayWithSchemaArray(a []*Schema) *SchemaOrSchemaArray {
result := &SchemaOrSchemaArray{}
result.SchemaArray = &a
return result
}
// SchemaEnumValue represents a value that can be part of an
// enumeration in a Schema.
type SchemaEnumValue struct {
String *string
Bool *bool
}
// NamedSchema is a name-value pair that is used to emulate maps
// with ordered keys.
type NamedSchema struct {
Name string
Value *Schema
}
// NewNamedSchema creates and returns a new object
func NewNamedSchema(name string, value *Schema) *NamedSchema {
return &NamedSchema{Name: name, Value: value}
}
// NamedSchemaOrStringArray is a name-value pair that is used
// to emulate maps with ordered keys.
type NamedSchemaOrStringArray struct {
Name string
Value *SchemaOrStringArray
}
// Access named subschemas by name
func namedSchemaArrayElementWithName(array *[]*NamedSchema, name string) *Schema {
if array == nil {
return nil
}
for _, pair := range *array {
if pair.Name == name {
return pair.Value
}
}
return nil
}
// PropertyWithName returns the selected element.
func (s *Schema) PropertyWithName(name string) *Schema {
return namedSchemaArrayElementWithName(s.Properties, name)
}
// PatternPropertyWithName returns the selected element.
func (s *Schema) PatternPropertyWithName(name string) *Schema {
return namedSchemaArrayElementWithName(s.PatternProperties, name)
}
// DefinitionWithName returns the selected element.
func (s *Schema) DefinitionWithName(name string) *Schema {
return namedSchemaArrayElementWithName(s.Definitions, name)
}
// AddProperty adds a named property.
func (s *Schema) AddProperty(name string, property *Schema) {
*s.Properties = append(*s.Properties, NewNamedSchema(name, property))
}

View File

@ -1,394 +0,0 @@
// 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 jsonschema
import (
"fmt"
"log"
"strings"
)
//
// OPERATIONS
// The following methods perform operations on Schemas.
//
// IsEmpty returns true if no members of the Schema are specified.
func (schema *Schema) IsEmpty() bool {
return (schema.Schema == nil) &&
(schema.ID == nil) &&
(schema.MultipleOf == nil) &&
(schema.Maximum == nil) &&
(schema.ExclusiveMaximum == nil) &&
(schema.Minimum == nil) &&
(schema.ExclusiveMinimum == nil) &&
(schema.MaxLength == nil) &&
(schema.MinLength == nil) &&
(schema.Pattern == nil) &&
(schema.AdditionalItems == nil) &&
(schema.Items == nil) &&
(schema.MaxItems == nil) &&
(schema.MinItems == nil) &&
(schema.UniqueItems == nil) &&
(schema.MaxProperties == nil) &&
(schema.MinProperties == nil) &&
(schema.Required == nil) &&
(schema.AdditionalProperties == nil) &&
(schema.Properties == nil) &&
(schema.PatternProperties == nil) &&
(schema.Dependencies == nil) &&
(schema.Enumeration == nil) &&
(schema.Type == nil) &&
(schema.AllOf == nil) &&
(schema.AnyOf == nil) &&
(schema.OneOf == nil) &&
(schema.Not == nil) &&
(schema.Definitions == nil) &&
(schema.Title == nil) &&
(schema.Description == nil) &&
(schema.Default == nil) &&
(schema.Format == nil) &&
(schema.Ref == nil)
}
// IsEqual returns true if two schemas are equal.
func (schema *Schema) IsEqual(schema2 *Schema) bool {
return schema.String() == schema2.String()
}
// SchemaOperation represents a function that can be applied to a Schema.
type SchemaOperation func(schema *Schema, context string)
// Applies a specified function to a Schema and all of the Schemas that it contains.
func (schema *Schema) applyToSchemas(operation SchemaOperation, context string) {
if schema.AdditionalItems != nil {
s := schema.AdditionalItems.Schema
if s != nil {
s.applyToSchemas(operation, "AdditionalItems")
}
}
if schema.Items != nil {
if schema.Items.SchemaArray != nil {
for _, s := range *(schema.Items.SchemaArray) {
s.applyToSchemas(operation, "Items.SchemaArray")
}
} else if schema.Items.Schema != nil {
schema.Items.Schema.applyToSchemas(operation, "Items.Schema")
}
}
if schema.AdditionalProperties != nil {
s := schema.AdditionalProperties.Schema
if s != nil {
s.applyToSchemas(operation, "AdditionalProperties")
}
}
if schema.Properties != nil {
for _, pair := range *(schema.Properties) {
s := pair.Value
s.applyToSchemas(operation, "Properties")
}
}
if schema.PatternProperties != nil {
for _, pair := range *(schema.PatternProperties) {
s := pair.Value
s.applyToSchemas(operation, "PatternProperties")
}
}
if schema.Dependencies != nil {
for _, pair := range *(schema.Dependencies) {
schemaOrStringArray := pair.Value
s := schemaOrStringArray.Schema
if s != nil {
s.applyToSchemas(operation, "Dependencies")
}
}
}
if schema.AllOf != nil {
for _, s := range *(schema.AllOf) {
s.applyToSchemas(operation, "AllOf")
}
}
if schema.AnyOf != nil {
for _, s := range *(schema.AnyOf) {
s.applyToSchemas(operation, "AnyOf")
}
}
if schema.OneOf != nil {
for _, s := range *(schema.OneOf) {
s.applyToSchemas(operation, "OneOf")
}
}
if schema.Not != nil {
schema.Not.applyToSchemas(operation, "Not")
}
if schema.Definitions != nil {
for _, pair := range *(schema.Definitions) {
s := pair.Value
s.applyToSchemas(operation, "Definitions")
}
}
operation(schema, context)
}
// CopyProperties copies all non-nil properties from the source Schema to the schema Schema.
func (schema *Schema) CopyProperties(source *Schema) {
if source.Schema != nil {
schema.Schema = source.Schema
}
if source.ID != nil {
schema.ID = source.ID
}
if source.MultipleOf != nil {
schema.MultipleOf = source.MultipleOf
}
if source.Maximum != nil {
schema.Maximum = source.Maximum
}
if source.ExclusiveMaximum != nil {
schema.ExclusiveMaximum = source.ExclusiveMaximum
}
if source.Minimum != nil {
schema.Minimum = source.Minimum
}
if source.ExclusiveMinimum != nil {
schema.ExclusiveMinimum = source.ExclusiveMinimum
}
if source.MaxLength != nil {
schema.MaxLength = source.MaxLength
}
if source.MinLength != nil {
schema.MinLength = source.MinLength
}
if source.Pattern != nil {
schema.Pattern = source.Pattern
}
if source.AdditionalItems != nil {
schema.AdditionalItems = source.AdditionalItems
}
if source.Items != nil {
schema.Items = source.Items
}
if source.MaxItems != nil {
schema.MaxItems = source.MaxItems
}
if source.MinItems != nil {
schema.MinItems = source.MinItems
}
if source.UniqueItems != nil {
schema.UniqueItems = source.UniqueItems
}
if source.MaxProperties != nil {
schema.MaxProperties = source.MaxProperties
}
if source.MinProperties != nil {
schema.MinProperties = source.MinProperties
}
if source.Required != nil {
schema.Required = source.Required
}
if source.AdditionalProperties != nil {
schema.AdditionalProperties = source.AdditionalProperties
}
if source.Properties != nil {
schema.Properties = source.Properties
}
if source.PatternProperties != nil {
schema.PatternProperties = source.PatternProperties
}
if source.Dependencies != nil {
schema.Dependencies = source.Dependencies
}
if source.Enumeration != nil {
schema.Enumeration = source.Enumeration
}
if source.Type != nil {
schema.Type = source.Type
}
if source.AllOf != nil {
schema.AllOf = source.AllOf
}
if source.AnyOf != nil {
schema.AnyOf = source.AnyOf
}
if source.OneOf != nil {
schema.OneOf = source.OneOf
}
if source.Not != nil {
schema.Not = source.Not
}
if source.Definitions != nil {
schema.Definitions = source.Definitions
}
if source.Title != nil {
schema.Title = source.Title
}
if source.Description != nil {
schema.Description = source.Description
}
if source.Default != nil {
schema.Default = source.Default
}
if source.Format != nil {
schema.Format = source.Format
}
if source.Ref != nil {
schema.Ref = source.Ref
}
}
// TypeIs returns true if the Type of a Schema includes the specified type
func (schema *Schema) TypeIs(typeName string) bool {
if schema.Type != nil {
// the schema Type is either a string or an array of strings
if schema.Type.String != nil {
return (*(schema.Type.String) == typeName)
} else if schema.Type.StringArray != nil {
for _, n := range *(schema.Type.StringArray) {
if n == typeName {
return true
}
}
}
}
return false
}
// ResolveRefs resolves "$ref" elements in a Schema and its children.
// But if a reference refers to an object type, is inside a oneOf, or contains a oneOf,
// the reference is kept and we expect downstream tools to separately model these
// referenced schemas.
func (schema *Schema) ResolveRefs() {
rootSchema := schema
count := 1
for count > 0 {
count = 0
schema.applyToSchemas(
func(schema *Schema, context string) {
if schema.Ref != nil {
resolvedRef, err := rootSchema.resolveJSONPointer(*(schema.Ref))
if err != nil {
log.Printf("%+v", err)
} else if resolvedRef.TypeIs("object") {
// don't substitute for objects, we'll model the referenced schema with a class
} else if context == "OneOf" {
// don't substitute for references inside oneOf declarations
} else if resolvedRef.OneOf != nil {
// don't substitute for references that contain oneOf declarations
} else if resolvedRef.AdditionalProperties != nil {
// don't substitute for references that look like objects
} else {
schema.Ref = nil
schema.CopyProperties(resolvedRef)
count++
}
}
}, "")
}
}
// resolveJSONPointer resolves JSON pointers.
// This current implementation is very crude and custom for OpenAPI 2.0 schemas.
// It panics for any pointer that it is unable to resolve.
func (schema *Schema) resolveJSONPointer(ref string) (result *Schema, err error) {
parts := strings.Split(ref, "#")
if len(parts) == 2 {
documentName := parts[0] + "#"
if documentName == "#" && schema.ID != nil {
documentName = *(schema.ID)
}
path := parts[1]
document := schemas[documentName]
pathParts := strings.Split(path, "/")
// we currently do a very limited (hard-coded) resolution of certain paths and log errors for missed cases
if len(pathParts) == 1 {
return document, nil
} else if len(pathParts) == 3 {
switch pathParts[1] {
case "definitions":
dictionary := document.Definitions
for _, pair := range *dictionary {
if pair.Name == pathParts[2] {
result = pair.Value
}
}
case "properties":
dictionary := document.Properties
for _, pair := range *dictionary {
if pair.Name == pathParts[2] {
result = pair.Value
}
}
default:
break
}
}
}
if result == nil {
return nil, fmt.Errorf("unresolved pointer: %+v", ref)
}
return result, nil
}
// ResolveAllOfs replaces "allOf" elements by merging their properties into the parent Schema.
func (schema *Schema) ResolveAllOfs() {
schema.applyToSchemas(
func(schema *Schema, context string) {
if schema.AllOf != nil {
for _, allOf := range *(schema.AllOf) {
schema.CopyProperties(allOf)
}
schema.AllOf = nil
}
}, "resolveAllOfs")
}
// ResolveAnyOfs replaces all "anyOf" elements with "oneOf".
func (schema *Schema) ResolveAnyOfs() {
schema.applyToSchemas(
func(schema *Schema, context string) {
if schema.AnyOf != nil {
schema.OneOf = schema.AnyOf
schema.AnyOf = nil
}
}, "resolveAnyOfs")
}
// return a pointer to a copy of a passed-in string
func stringptr(input string) (output *string) {
return &input
}
// CopyOfficialSchemaProperty copies a named property from the official JSON Schema definition
func (schema *Schema) CopyOfficialSchemaProperty(name string) {
*schema.Properties = append(*schema.Properties,
NewNamedSchema(name,
&Schema{Ref: stringptr("http://json-schema.org/draft-04/schema#/properties/" + name)}))
}
// CopyOfficialSchemaProperties copies named properties from the official JSON Schema definition
func (schema *Schema) CopyOfficialSchemaProperties(names []string) {
for _, name := range names {
schema.CopyOfficialSchemaProperty(name)
}
}

View File

@ -1,409 +0,0 @@
// 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 jsonschema
import (
"fmt"
"io/ioutil"
"gopkg.in/yaml.v2"
)
// This is a global map of all known Schemas.
// It is initialized when the first Schema is created and inserted.
var schemas map[string]*Schema
// NewSchemaFromFile reads a schema from a file.
// Currently this assumes that schemas are stored in the source distribution of this project.
func NewSchemaFromFile(filename string) (schema *Schema, err error) {
file, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
var info yaml.MapSlice
err = yaml.Unmarshal(file, &info)
if err != nil {
return nil, err
}
return NewSchemaFromObject(info), nil
}
// NewSchemaFromObject constructs a schema from a parsed JSON object.
// Due to the complexity of the schema representation, this is a
// custom reader and not the standard Go JSON reader (encoding/json).
func NewSchemaFromObject(jsonData interface{}) *Schema {
switch t := jsonData.(type) {
default:
fmt.Printf("schemaValue: unexpected type %T\n", t)
return nil
case yaml.MapSlice:
schema := &Schema{}
for _, mapItem := range t {
k := mapItem.Key.(string)
v := mapItem.Value
switch k {
case "$schema":
schema.Schema = schema.stringValue(v)
case "id":
schema.ID = schema.stringValue(v)
case "multipleOf":
schema.MultipleOf = schema.numberValue(v)
case "maximum":
schema.Maximum = schema.numberValue(v)
case "exclusiveMaximum":
schema.ExclusiveMaximum = schema.boolValue(v)
case "minimum":
schema.Minimum = schema.numberValue(v)
case "exclusiveMinimum":
schema.ExclusiveMinimum = schema.boolValue(v)
case "maxLength":
schema.MaxLength = schema.intValue(v)
case "minLength":
schema.MinLength = schema.intValue(v)
case "pattern":
schema.Pattern = schema.stringValue(v)
case "additionalItems":
schema.AdditionalItems = schema.schemaOrBooleanValue(v)
case "items":
schema.Items = schema.schemaOrSchemaArrayValue(v)
case "maxItems":
schema.MaxItems = schema.intValue(v)
case "minItems":
schema.MinItems = schema.intValue(v)
case "uniqueItems":
schema.UniqueItems = schema.boolValue(v)
case "maxProperties":
schema.MaxProperties = schema.intValue(v)
case "minProperties":
schema.MinProperties = schema.intValue(v)
case "required":
schema.Required = schema.arrayOfStringsValue(v)
case "additionalProperties":
schema.AdditionalProperties = schema.schemaOrBooleanValue(v)
case "properties":
schema.Properties = schema.mapOfSchemasValue(v)
case "patternProperties":
schema.PatternProperties = schema.mapOfSchemasValue(v)
case "dependencies":
schema.Dependencies = schema.mapOfSchemasOrStringArraysValue(v)
case "enum":
schema.Enumeration = schema.arrayOfEnumValuesValue(v)
case "type":
schema.Type = schema.stringOrStringArrayValue(v)
case "allOf":
schema.AllOf = schema.arrayOfSchemasValue(v)
case "anyOf":
schema.AnyOf = schema.arrayOfSchemasValue(v)
case "oneOf":
schema.OneOf = schema.arrayOfSchemasValue(v)
case "not":
schema.Not = NewSchemaFromObject(v)
case "definitions":
schema.Definitions = schema.mapOfSchemasValue(v)
case "title":
schema.Title = schema.stringValue(v)
case "description":
schema.Description = schema.stringValue(v)
case "default":
schema.Default = &v
case "format":
schema.Format = schema.stringValue(v)
case "$ref":
schema.Ref = schema.stringValue(v)
default:
fmt.Printf("UNSUPPORTED (%s)\n", k)
}
}
// insert schema in global map
if schema.ID != nil {
if schemas == nil {
schemas = make(map[string]*Schema, 0)
}
schemas[*(schema.ID)] = schema
}
return schema
}
return nil
}
//
// BUILDERS
// The following methods build elements of Schemas from interface{} values.
// Each returns nil if it is unable to build the desired element.
//
// Gets the string value of an interface{} value if possible.
func (schema *Schema) stringValue(v interface{}) *string {
switch v := v.(type) {
default:
fmt.Printf("stringValue: unexpected type %T\n", v)
case string:
return &v
}
return nil
}
// Gets the numeric value of an interface{} value if possible.
func (schema *Schema) numberValue(v interface{}) *SchemaNumber {
number := &SchemaNumber{}
switch v := v.(type) {
default:
fmt.Printf("numberValue: unexpected type %T\n", v)
case float64:
v2 := float64(v)
number.Float = &v2
return number
case float32:
v2 := float64(v)
number.Float = &v2
return number
case int:
v2 := int64(v)
number.Integer = &v2
}
return nil
}
// Gets the integer value of an interface{} value if possible.
func (schema *Schema) intValue(v interface{}) *int64 {
switch v := v.(type) {
default:
fmt.Printf("intValue: unexpected type %T\n", v)
case float64:
v2 := int64(v)
return &v2
case int64:
return &v
case int:
v2 := int64(v)
return &v2
}
return nil
}
// Gets the bool value of an interface{} value if possible.
func (schema *Schema) boolValue(v interface{}) *bool {
switch v := v.(type) {
default:
fmt.Printf("boolValue: unexpected type %T\n", v)
case bool:
return &v
}
return nil
}
// Gets a map of Schemas from an interface{} value if possible.
func (schema *Schema) mapOfSchemasValue(v interface{}) *[]*NamedSchema {
switch v := v.(type) {
default:
fmt.Printf("mapOfSchemasValue: unexpected type %T\n", v)
case yaml.MapSlice:
m := make([]*NamedSchema, 0)
for _, mapItem := range v {
k2 := mapItem.Key.(string)
v2 := mapItem.Value
pair := &NamedSchema{Name: k2, Value: NewSchemaFromObject(v2)}
m = append(m, pair)
}
return &m
}
return nil
}
// Gets an array of Schemas from an interface{} value if possible.
func (schema *Schema) arrayOfSchemasValue(v interface{}) *[]*Schema {
switch v := v.(type) {
default:
fmt.Printf("arrayOfSchemasValue: unexpected type %T\n", v)
case []interface{}:
m := make([]*Schema, 0)
for _, v2 := range v {
switch v2 := v2.(type) {
default:
fmt.Printf("arrayOfSchemasValue: unexpected type %T\n", v2)
case yaml.MapSlice:
s := NewSchemaFromObject(v2)
m = append(m, s)
}
}
return &m
case yaml.MapSlice:
m := make([]*Schema, 0)
s := NewSchemaFromObject(v)
m = append(m, s)
return &m
}
return nil
}
// Gets a Schema or an array of Schemas from an interface{} value if possible.
func (schema *Schema) schemaOrSchemaArrayValue(v interface{}) *SchemaOrSchemaArray {
switch v := v.(type) {
default:
fmt.Printf("schemaOrSchemaArrayValue: unexpected type %T\n", v)
case []interface{}:
m := make([]*Schema, 0)
for _, v2 := range v {
switch v2 := v2.(type) {
default:
fmt.Printf("schemaOrSchemaArrayValue: unexpected type %T\n", v2)
case map[string]interface{}:
s := NewSchemaFromObject(v2)
m = append(m, s)
}
}
return &SchemaOrSchemaArray{SchemaArray: &m}
case yaml.MapSlice:
s := NewSchemaFromObject(v)
return &SchemaOrSchemaArray{Schema: s}
}
return nil
}
// Gets an array of strings from an interface{} value if possible.
func (schema *Schema) arrayOfStringsValue(v interface{}) *[]string {
switch v := v.(type) {
default:
fmt.Printf("arrayOfStringsValue: unexpected type %T\n", v)
case []string:
return &v
case string:
a := []string{v}
return &a
case []interface{}:
a := make([]string, 0)
for _, v2 := range v {
switch v2 := v2.(type) {
default:
fmt.Printf("arrayOfStringsValue: unexpected type %T\n", v2)
case string:
a = append(a, v2)
}
}
return &a
}
return nil
}
// Gets a string or an array of strings from an interface{} value if possible.
func (schema *Schema) stringOrStringArrayValue(v interface{}) *StringOrStringArray {
switch v := v.(type) {
default:
fmt.Printf("arrayOfStringsValue: unexpected type %T\n", v)
case []string:
s := &StringOrStringArray{}
s.StringArray = &v
return s
case string:
s := &StringOrStringArray{}
s.String = &v
return s
case []interface{}:
a := make([]string, 0)
for _, v2 := range v {
switch v2 := v2.(type) {
default:
fmt.Printf("arrayOfStringsValue: unexpected type %T\n", v2)
case string:
a = append(a, v2)
}
}
s := &StringOrStringArray{}
s.StringArray = &a
return s
}
return nil
}
// Gets an array of enum values from an interface{} value if possible.
func (schema *Schema) arrayOfEnumValuesValue(v interface{}) *[]SchemaEnumValue {
a := make([]SchemaEnumValue, 0)
switch v := v.(type) {
default:
fmt.Printf("arrayOfEnumValuesValue: unexpected type %T\n", v)
case []interface{}:
for _, v2 := range v {
switch v2 := v2.(type) {
default:
fmt.Printf("arrayOfEnumValuesValue: unexpected type %T\n", v2)
case string:
a = append(a, SchemaEnumValue{String: &v2})
case bool:
a = append(a, SchemaEnumValue{Bool: &v2})
}
}
}
return &a
}
// Gets a map of schemas or string arrays from an interface{} value if possible.
func (schema *Schema) mapOfSchemasOrStringArraysValue(v interface{}) *[]*NamedSchemaOrStringArray {
m := make([]*NamedSchemaOrStringArray, 0)
switch v := v.(type) {
default:
fmt.Printf("mapOfSchemasOrStringArraysValue: unexpected type %T %+v\n", v, v)
case yaml.MapSlice:
for _, mapItem := range v {
k2 := mapItem.Key.(string)
v2 := mapItem.Value
switch v2 := v2.(type) {
default:
fmt.Printf("mapOfSchemasOrStringArraysValue: unexpected type %T %+v\n", v2, v2)
case []interface{}:
a := make([]string, 0)
for _, v3 := range v2 {
switch v3 := v3.(type) {
default:
fmt.Printf("mapOfSchemasOrStringArraysValue: unexpected type %T %+v\n", v3, v3)
case string:
a = append(a, v3)
}
}
s := &SchemaOrStringArray{}
s.StringArray = &a
pair := &NamedSchemaOrStringArray{Name: k2, Value: s}
m = append(m, pair)
}
}
}
return &m
}
// Gets a schema or a boolean value from an interface{} value if possible.
func (schema *Schema) schemaOrBooleanValue(v interface{}) *SchemaOrBoolean {
schemaOrBoolean := &SchemaOrBoolean{}
switch v := v.(type) {
case bool:
schemaOrBoolean.Boolean = &v
case yaml.MapSlice:
schemaOrBoolean.Schema = NewSchemaFromObject(v)
default:
fmt.Printf("schemaOrBooleanValue: unexpected type %T\n", v)
case []map[string]interface{}:
}
return schemaOrBoolean
}

View File

@ -1,150 +0,0 @@
{
"id": "http://json-schema.org/draft-04/schema#",
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Core schema meta-schema",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#" }
},
"positiveInteger": {
"type": "integer",
"minimum": 0
},
"positiveIntegerDefault0": {
"allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
},
"simpleTypes": {
"enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
},
"stringArray": {
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"uniqueItems": true
}
},
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uri"
},
"$schema": {
"type": "string",
"format": "uri"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"default": {},
"multipleOf": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
},
"maximum": {
"type": "number"
},
"exclusiveMaximum": {
"type": "boolean",
"default": false
},
"minimum": {
"type": "number"
},
"exclusiveMinimum": {
"type": "boolean",
"default": false
},
"maxLength": { "$ref": "#/definitions/positiveInteger" },
"minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
"pattern": {
"type": "string",
"format": "regex"
},
"additionalItems": {
"anyOf": [
{ "type": "boolean" },
{ "$ref": "#" }
],
"default": {}
},
"items": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
],
"default": {}
},
"maxItems": { "$ref": "#/definitions/positiveInteger" },
"minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
"uniqueItems": {
"type": "boolean",
"default": false
},
"maxProperties": { "$ref": "#/definitions/positiveInteger" },
"minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
"required": { "$ref": "#/definitions/stringArray" },
"additionalProperties": {
"anyOf": [
{ "type": "boolean" },
{ "$ref": "#" }
],
"default": {}
},
"definitions": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"properties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"patternProperties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"dependencies": {
"type": "object",
"additionalProperties": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/stringArray" }
]
}
},
"enum": {
"type": "array",
"minItems": 1,
"uniqueItems": true
},
"type": {
"anyOf": [
{ "$ref": "#/definitions/simpleTypes" },
{
"type": "array",
"items": { "$ref": "#/definitions/simpleTypes" },
"minItems": 1,
"uniqueItems": true
}
]
},
"allOf": { "$ref": "#/definitions/schemaArray" },
"anyOf": { "$ref": "#/definitions/schemaArray" },
"oneOf": { "$ref": "#/definitions/schemaArray" },
"not": { "$ref": "#" }
},
"dependencies": {
"exclusiveMaximum": [ "maximum" ],
"exclusiveMinimum": [ "minimum" ]
},
"default": {}
}

View File

@ -1,334 +0,0 @@
// 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 jsonschema
import (
"fmt"
"gopkg.in/yaml.v2"
)
const indentation = " "
func renderMap(info interface{}, indent string) (result string) {
result = "{\n"
innerIndent := indent + indentation
switch pairs := info.(type) {
case yaml.MapSlice:
for i, pair := range pairs {
// first print the key
result += fmt.Sprintf("%s\"%+v\": ", innerIndent, pair.Key)
// then the value
switch value := pair.Value.(type) {
case string:
result += "\"" + value + "\""
case bool:
if value {
result += "true"
} else {
result += "false"
}
case []interface{}:
result += renderArray(value, innerIndent)
case yaml.MapSlice:
result += renderMap(value, innerIndent)
case int:
result += fmt.Sprintf("%d", value)
case int64:
result += fmt.Sprintf("%d", value)
case []string:
result += renderStringArray(value, innerIndent)
default:
result += fmt.Sprintf("???MapItem(Key:%+v, Value:%T)", value, value)
}
if i < len(pairs)-1 {
result += ","
}
result += "\n"
}
default:
// t is some other type that we didn't name.
}
result += indent + "}"
return result
}
func renderArray(array []interface{}, indent string) (result string) {
result = "[\n"
innerIndent := indent + indentation
for i, item := range array {
switch item := item.(type) {
case string:
result += innerIndent + "\"" + item + "\""
case bool:
if item {
result += innerIndent + "true"
} else {
result += innerIndent + "false"
}
case yaml.MapSlice:
result += innerIndent + renderMap(item, innerIndent) + ""
default:
result += innerIndent + fmt.Sprintf("???ArrayItem(%+v)", item)
}
if i < len(array)-1 {
result += ","
}
result += "\n"
}
result += indent + "]"
return result
}
func renderStringArray(array []string, indent string) (result string) {
result = "[\n"
innerIndent := indent + indentation
for i, item := range array {
result += innerIndent + "\"" + item + "\""
if i < len(array)-1 {
result += ","
}
result += "\n"
}
result += indent + "]"
return result
}
func Render(info yaml.MapSlice) string {
return renderMap(info, "") + "\n"
}
func (object *SchemaNumber) jsonValue() interface{} {
if object.Integer != nil {
return object.Integer
} else if object.Float != nil {
return object.Float
} else {
return nil
}
}
func (object *SchemaOrBoolean) jsonValue() interface{} {
if object.Schema != nil {
return object.Schema.jsonValue()
} else if object.Boolean != nil {
return *object.Boolean
} else {
return nil
}
}
func (object *StringOrStringArray) jsonValue() interface{} {
if object.String != nil {
return *object.String
} else if object.StringArray != nil {
array := make([]interface{}, 0)
for _, item := range *(object.StringArray) {
array = append(array, item)
}
return array
} else {
return nil
}
}
func (object *SchemaOrStringArray) jsonValue() interface{} {
if object.Schema != nil {
return object.Schema.jsonValue()
} else if object.StringArray != nil {
array := make([]interface{}, 0)
for _, item := range *(object.StringArray) {
array = append(array, item)
}
return array
} else {
return nil
}
}
func (object *SchemaOrSchemaArray) jsonValue() interface{} {
if object.Schema != nil {
return object.Schema.jsonValue()
} else if object.SchemaArray != nil {
array := make([]interface{}, 0)
for _, item := range *(object.SchemaArray) {
array = append(array, item.jsonValue())
}
return array
} else {
return nil
}
}
func (object *SchemaEnumValue) jsonValue() interface{} {
if object.String != nil {
return *object.String
} else if object.Bool != nil {
return *object.Bool
} else {
return nil
}
}
func namedSchemaArrayValue(array *[]*NamedSchema) interface{} {
m2 := yaml.MapSlice{}
for _, pair := range *(array) {
var item2 yaml.MapItem
item2.Key = pair.Name
item2.Value = pair.Value.jsonValue()
m2 = append(m2, item2)
}
return m2
}
func namedSchemaOrStringArrayValue(array *[]*NamedSchemaOrStringArray) interface{} {
m2 := yaml.MapSlice{}
for _, pair := range *(array) {
var item2 yaml.MapItem
item2.Key = pair.Name
item2.Value = pair.Value.jsonValue()
m2 = append(m2, item2)
}
return m2
}
func schemaEnumArrayValue(array *[]SchemaEnumValue) []interface{} {
a := make([]interface{}, 0)
for _, item := range *array {
a = append(a, item.jsonValue())
}
return a
}
func schemaArrayValue(array *[]*Schema) []interface{} {
a := make([]interface{}, 0)
for _, item := range *array {
a = append(a, item.jsonValue())
}
return a
}
func (schema *Schema) jsonValue() yaml.MapSlice {
m := yaml.MapSlice{}
if schema.Title != nil {
m = append(m, yaml.MapItem{Key: "title", Value: *schema.Title})
}
if schema.ID != nil {
m = append(m, yaml.MapItem{Key: "id", Value: *schema.ID})
}
if schema.Schema != nil {
m = append(m, yaml.MapItem{Key: "$schema", Value: *schema.Schema})
}
if schema.Type != nil {
m = append(m, yaml.MapItem{Key: "type", Value: schema.Type.jsonValue()})
}
if schema.Items != nil {
m = append(m, yaml.MapItem{Key: "items", Value: schema.Items.jsonValue()})
}
if schema.Description != nil {
m = append(m, yaml.MapItem{Key: "description", Value: *schema.Description})
}
if schema.Required != nil {
m = append(m, yaml.MapItem{Key: "required", Value: *schema.Required})
}
if schema.AdditionalProperties != nil {
m = append(m, yaml.MapItem{Key: "additionalProperties", Value: schema.AdditionalProperties.jsonValue()})
}
if schema.PatternProperties != nil {
m = append(m, yaml.MapItem{Key: "patternProperties", Value: namedSchemaArrayValue(schema.PatternProperties)})
}
if schema.Properties != nil {
m = append(m, yaml.MapItem{Key: "properties", Value: namedSchemaArrayValue(schema.Properties)})
}
if schema.Dependencies != nil {
m = append(m, yaml.MapItem{Key: "dependencies", Value: namedSchemaOrStringArrayValue(schema.Dependencies)})
}
if schema.Ref != nil {
m = append(m, yaml.MapItem{Key: "$ref", Value: *schema.Ref})
}
if schema.MultipleOf != nil {
m = append(m, yaml.MapItem{Key: "multipleOf", Value: schema.MultipleOf.jsonValue()})
}
if schema.Maximum != nil {
m = append(m, yaml.MapItem{Key: "maximum", Value: schema.Maximum.jsonValue()})
}
if schema.ExclusiveMaximum != nil {
m = append(m, yaml.MapItem{Key: "exclusiveMaximum", Value: schema.ExclusiveMaximum})
}
if schema.Minimum != nil {
m = append(m, yaml.MapItem{Key: "minimum", Value: schema.Minimum.jsonValue()})
}
if schema.ExclusiveMinimum != nil {
m = append(m, yaml.MapItem{Key: "exclusiveMinimum", Value: schema.ExclusiveMinimum})
}
if schema.MaxLength != nil {
m = append(m, yaml.MapItem{Key: "maxLength", Value: *schema.MaxLength})
}
if schema.MinLength != nil {
m = append(m, yaml.MapItem{Key: "minLength", Value: *schema.MinLength})
}
if schema.Pattern != nil {
m = append(m, yaml.MapItem{Key: "pattern", Value: *schema.Pattern})
}
if schema.AdditionalItems != nil {
m = append(m, yaml.MapItem{Key: "additionalItems", Value: schema.AdditionalItems.jsonValue()})
}
if schema.MaxItems != nil {
m = append(m, yaml.MapItem{Key: "maxItems", Value: *schema.MaxItems})
}
if schema.MinItems != nil {
m = append(m, yaml.MapItem{Key: "minItems", Value: *schema.MinItems})
}
if schema.UniqueItems != nil {
m = append(m, yaml.MapItem{Key: "uniqueItems", Value: *schema.UniqueItems})
}
if schema.MaxProperties != nil {
m = append(m, yaml.MapItem{Key: "maxProperties", Value: *schema.MaxProperties})
}
if schema.MinProperties != nil {
m = append(m, yaml.MapItem{Key: "minProperties", Value: *schema.MinProperties})
}
if schema.Enumeration != nil {
m = append(m, yaml.MapItem{Key: "enum", Value: schemaEnumArrayValue(schema.Enumeration)})
}
if schema.AllOf != nil {
m = append(m, yaml.MapItem{Key: "allOf", Value: schemaArrayValue(schema.AllOf)})
}
if schema.AnyOf != nil {
m = append(m, yaml.MapItem{Key: "anyOf", Value: schemaArrayValue(schema.AnyOf)})
}
if schema.OneOf != nil {
m = append(m, yaml.MapItem{Key: "oneOf", Value: schemaArrayValue(schema.OneOf)})
}
if schema.Not != nil {
m = append(m, yaml.MapItem{Key: "not", Value: schema.Not.jsonValue()})
}
if schema.Definitions != nil {
m = append(m, yaml.MapItem{Key: "definitions", Value: namedSchemaArrayValue(schema.Definitions)})
}
if schema.Default != nil {
m = append(m, yaml.MapItem{Key: "default", Value: *schema.Default})
}
if schema.Format != nil {
m = append(m, yaml.MapItem{Key: "format", Value: *schema.Format})
}
return m
}
// JSONString returns a json representation of a schema.
func (schema *Schema) JSONString() string {
info := schema.jsonValue()
return Render(info)
}

View File

@ -1,3 +0,0 @@
# jsonwriter
This directory contains code for writing yaml.MapSlice structures as JSON files.

View File

@ -1,168 +0,0 @@
// 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 jsonwriter
import (
"bytes"
"errors"
"fmt"
"strings"
"gopkg.in/yaml.v2"
)
const indentation = " "
// basic escaping, will need to be improved or replaced
func escape(s string) string {
s = strings.Replace(s, "\n", "\\n", -1)
s = strings.Replace(s, "\"", "\\\"", -1)
return s
}
type writer struct {
b bytes.Buffer
}
func (w *writer) bytes() []byte {
return w.b.Bytes()
}
func (w *writer) writeString(s string) {
w.b.Write([]byte(s))
}
func (w *writer) writeMap(info interface{}, indent string) {
w.writeString("{\n")
innerIndent := indent + indentation
switch pairs := info.(type) {
case yaml.MapSlice:
for i, pair := range pairs {
// first print the key
w.writeString(fmt.Sprintf("%s\"%+v\": ", innerIndent, pair.Key))
// then the value
switch value := pair.Value.(type) {
case string:
w.writeString("\"")
w.writeString(escape(value))
w.writeString("\"")
case bool:
if value {
w.writeString("true")
} else {
w.writeString("false")
}
case []interface{}:
w.writeArray(value, innerIndent)
case yaml.MapSlice:
w.writeMap(value, innerIndent)
case int:
w.writeString(fmt.Sprintf("%d", value))
case int64:
w.writeString(fmt.Sprintf("%d", value))
case []string:
w.writeStringArray(value, innerIndent)
case float64:
w.writeString(fmt.Sprintf("%f", value))
case []yaml.MapSlice:
w.writeMapSliceArray(value, innerIndent)
default:
w.writeString(fmt.Sprintf("???MapItem(%+v, %T)", value, value))
}
if i < len(pairs)-1 {
w.writeString(",")
}
w.writeString("\n")
}
default:
// t is some other type that we didn't name.
}
w.writeString(indent)
w.writeString("}")
}
func (w *writer) writeArray(array []interface{}, indent string) {
w.writeString("[\n")
innerIndent := indent + indentation
for i, item := range array {
w.writeString(innerIndent)
switch item := item.(type) {
case string:
w.writeString("\"")
w.writeString(item)
w.writeString("\"")
case bool:
if item {
w.writeString("true")
} else {
w.writeString("false")
}
case yaml.MapSlice:
w.writeMap(item, innerIndent)
default:
w.writeString(fmt.Sprintf("???ArrayItem(%+v)", item))
}
if i < len(array)-1 {
w.writeString(",")
}
w.writeString("\n")
}
w.writeString(indent)
w.writeString("]")
}
func (w *writer) writeStringArray(array []string, indent string) {
w.writeString("[\n")
innerIndent := indent + indentation
for i, item := range array {
w.writeString(innerIndent)
w.writeString("\"")
w.writeString(escape(item))
w.writeString("\"")
if i < len(array)-1 {
w.writeString(",")
}
w.writeString("\n")
}
w.writeString(indent)
w.writeString("]")
}
func (w *writer) writeMapSliceArray(array []yaml.MapSlice, indent string) {
w.writeString("[\n")
innerIndent := indent + indentation
for i, item := range array {
w.writeString(innerIndent)
w.writeMap(item, innerIndent)
if i < len(array)-1 {
w.writeString(",")
}
w.writeString("\n")
}
w.writeString(indent)
w.writeString("]")
}
// Marshal writes a yaml.MapSlice as JSON
func Marshal(in interface{}) (out []byte, err error) {
var w writer
m, ok := in.(yaml.MapSlice)
if !ok {
return nil, errors.New("invalid type passed to Marshal")
}
w.writeMap(m, "")
w.writeString("\n")
return w.bytes(), err
}

Some files were not shown because too many files have changed in this diff Show More