├── .gitignore
├── .travis.yml
├── Dockerfile
├── LICENSE
├── NOTICE.txt
├── README.md
├── aws-api-import.cmd
├── aws-api-import.sh
├── docker-entrypoint.sh
├── pom.xml
├── src
└── com
│ └── amazonaws
│ └── service
│ └── apigateway
│ └── importer
│ ├── ApiImporterMain.java
│ ├── RamlApiFileImporter.java
│ ├── RamlApiImporter.java
│ ├── SwaggerApiFileImporter.java
│ ├── SwaggerApiImporter.java
│ ├── config
│ ├── ApiImporterDefaultModule.java
│ └── AwsConfig.java
│ ├── impl
│ ├── ApiGatewayRamlFileImporter.java
│ ├── ApiGatewaySwaggerFileImporter.java
│ ├── SchemaTransformer.java
│ └── sdk
│ │ ├── ApiGatewaySdkApiImporter.java
│ │ ├── ApiGatewaySdkRamlApiImporter.java
│ │ └── ApiGatewaySdkSwaggerApiImporter.java
│ └── util
│ └── PatchUtils.java
└── tst
├── com
└── amazonaws
│ └── service
│ └── apigateway
│ └── importer
│ ├── ApiImporterMainTest.java
│ ├── config
│ ├── RamlApiImporterTestModule.java
│ └── SwaggerApiImporterTestModule.java
│ ├── impl
│ ├── ApiGatewayRamlFileImporterTest.java
│ ├── ApiGatewaySwaggerFileImporterTest.java
│ ├── LambdaMatcher.java
│ └── sdk
│ │ ├── ApiGatewaySdkApiImporterTest.java
│ │ └── ApiGatewaySdkSwaggerApiImporterTest.java
│ └── integration
│ └── LargeApiIntegrationTest.java
└── resources
├── raml
├── apigateway.json
├── apigateway.raml
├── example.json
└── example.raml
└── swagger
├── apigateway.json
├── basic.json
├── large.json
├── petstore-expanded.json
├── petstore-minimal.json
├── petstore-simple.json
├── petstore-with-external-docs.json
├── petstore.json
├── test.json
├── uber.json
└── uber.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea/
3 | aws-apigateway-swagger-importer.iml
4 | build/
5 | target/
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk8
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM maven:3-jdk-8
2 |
3 | LABEL Description="Tools to work with Amazon API Gateway, Swagger, and RAML"
4 |
5 | COPY docker-entrypoint.sh /
6 | COPY pom.xml /app/
7 | COPY src /app/src/
8 | COPY tst /app/tst/
9 |
10 | WORKDIR /app
11 |
12 | RUN mvn assembly:assembly \
13 | && mv target/aws-apigateway-*-jar-with-dependencies.jar /aws-apigateway-importer.jar \
14 | && mvn clean
15 |
16 | VOLUME ["/root/.aws"]
17 | VOLUME ["/data"]
18 |
19 | WORKDIR /data
20 |
21 | ENTRYPOINT ["/docker-entrypoint.sh"]
22 | CMD ["--help"]
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/NOTICE.txt:
--------------------------------------------------------------------------------
1 | Amazon API Gateway Swagger Importer
2 | Copyright 2013-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Amazon API Gateway Importer
2 |
3 | The **Amazon API Gateway Importer** lets you create or update [Amazon API Gateway][service-page] APIs from a Swagger or RAML API representation.
4 |
5 | To learn more about API Gateway, please see the [service documentation][service-docs] or the [API documentation][api-docs].
6 |
7 | [service-page]: http://aws.amazon.com/api-gateway/
8 | [service-docs]: http://docs.aws.amazon.com/apigateway/latest/developerguide/
9 | [api-docs]: http://docs.aws.amazon.com/apigateway/api-reference
10 |
11 | [](https://travis-ci.org/awslabs/aws-apigateway-importer)
12 |
13 | #### Updates
14 |
15 | April 5, 2016: Swagger/OpenAPI import is now generally available in the API Gateway [REST API][api], the AWS [CLI][cli] and all AWS [SDKs][sdks]. You can also import and export Swagger definitions using the API Gateway [console][console]. This release addresses many of the open issues and feedback in this repository.
16 |
17 | Customers are encouraged to migrate their workflow to the standard AWS tools. aws-apigateway-importer will receive minimal support from the API Gateway team going forward. Pull requests will be periodically reviewed. Customers using RAML definitions should continue to use aws-apigateway-importer for the time being.
18 |
19 | Thanks for all of your feedback and contributions to this tool. Any feedback or issues going forward should be directed to the official API Gateway [forums][forums]. - @rpgreen
20 |
21 | [sdks]: https://aws.amazon.com/tools
22 | [cli]: http://docs.aws.amazon.com/cli/latest/reference/apigateway/put-rest-api.html
23 | [forums]: https://forums.aws.amazon.com/forum.jspa?forumID=199
24 | [api]: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-import-api.html
25 | [console]: https://console.aws.amazon.com/apigateway/home
26 |
27 | ## Usage
28 |
29 | ### Prerequisites
30 |
31 | #### Credentials
32 | This tool requires AWS credentials to be configured in at least one of the locations specified by the [default credential provider chain](http://docs.aws.amazon.com/AWSSdkDocsJava/latest/DeveloperGuide/credentials.html).
33 |
34 | It will look for configured credentials in environment variables, Java system properties, [AWS SDK/CLI](http://aws.amazon.com/cli) profile credentials, and EC2 instance profile credentials.
35 |
36 | #### Build
37 |
38 | Build with `mvn assembly:assembly`
39 |
40 | ### Import a new API
41 |
42 | ```sh
43 | ./aws-api-import.sh --create path/to/swagger.json
44 |
45 | ./aws-api-import.sh -c path/to/api.raml
46 | ```
47 |
48 | ### Update an existing API and deploy it to a stage
49 |
50 | ```sh
51 | ./aws-api-import.sh --update API_ID --deploy STAGE_NAME path/to/swagger.yaml
52 |
53 | ./aws-api-import.sh --update API_ID --deploy STAGE_NAME --raml-config path/to/config.json path/to/api.raml
54 | ```
55 |
56 | For Windows environments replace `./aws-api-import.sh` with `./aws-api-import.cmd` in the examples.
57 |
58 | ### API Gateway Extension Example
59 |
60 | You can fully define an API Gateway API in Swagger using the `x-amazon-apigateway-auth` and `x-amazon-apigateway-integration` extensions,
61 | or in RAML using an external configuration file.
62 |
63 | Defined on an Operation:
64 |
65 | ```json
66 |
67 | "x-amazon-apigateway-auth" : {
68 | "type" : "aws_iam"
69 | },
70 | "x-amazon-apigateway-integration" : {
71 | "type" : "aws",
72 | "uri" : "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:MY_ACCT_ID:function:helloWorld/invocations",
73 | "httpMethod" : "POST",
74 | "credentials" : "arn:aws:iam::MY_ACCT_ID:role/lambda_exec_role",
75 | "requestTemplates" : {
76 | "application/json" : "json request template 2",
77 | "application/xml" : "xml request template 2"
78 | },
79 | "requestParameters" : {
80 | "integration.request.path.integrationPathParam" : "method.request.querystring.latitude",
81 | "integration.request.querystring.integrationQueryParam" : "method.request.querystring.longitude"
82 | },
83 | "cacheNamespace" : "cache-namespace",
84 | "cacheKeyParameters" : [],
85 | "responses" : {
86 | "2\\d{2}" : {
87 | "statusCode" : "200",
88 | "responseParameters" : {
89 | "method.response.header.test-method-response-header" : "integration.response.header.integrationResponseHeaderParam1"
90 | },
91 | "responseTemplates" : {
92 | "application/json" : "json 200 response template",
93 | "application/xml" : "xml 200 response template"
94 | }
95 | },
96 | "default" : {
97 | "statusCode" : "400",
98 | "responseParameters" : {
99 | "method.response.header.test-method-response-header" : "'static value'"
100 | },
101 | "responseTemplates" : {
102 | "application/json" : "json 400 response template",
103 | "application/xml" : "xml 400 response template"
104 | }
105 | }
106 | }
107 | }
108 | ```
109 |
110 | ## Testing
111 |
112 | ```sh
113 | mvn test
114 | ```
115 |
--------------------------------------------------------------------------------
/aws-api-import.cmd:
--------------------------------------------------------------------------------
1 | java -jar %~dp0target/aws-apigateway-importer-1.0.3-SNAPSHOT-jar-with-dependencies.jar %*
2 |
--------------------------------------------------------------------------------
/aws-api-import.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | root=$(dirname $(perl -MCwd=abs_path -e 'print abs_path(shift)' $0))
3 |
4 | java -jar $root/target/aws-apigateway-importer-1.0.3-SNAPSHOT-jar-with-dependencies.jar "$@"
--------------------------------------------------------------------------------
/docker-entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | java -jar /aws-apigateway-importer.jar "$@"
4 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | com.amazonaws
6 | aws-apigateway-importer
7 | 1.0.3-SNAPSHOT
8 |
9 |
10 | org.sonatype.oss
11 | oss-parent
12 | 7
13 |
14 |
15 |
16 |
17 |
18 | com.amazonaws
19 | aws-apigateway-sdk-java
20 | 1.1.1
21 |
22 |
23 |
24 | com.amazonaws
25 | aws-hal-client-java
26 | 1.3.0
27 |
28 |
29 |
30 | com.amazonaws
31 | aws-java-sdk-core
32 | [1.8.6,1.10.77)
33 |
34 |
35 |
36 | org.glassfish
37 | javax.json
38 | 1.0-b06
39 |
40 |
41 |
42 | de.weltraumschaf.commons
43 | jcommander
44 | 2.0.0
45 |
46 |
47 |
48 | com.google.inject
49 | guice
50 | 4.0
51 |
52 |
53 |
54 | log4j
55 | log4j
56 | 1.2.14
57 |
58 |
59 |
60 | io.swagger
61 | swagger-parser
62 | 1.0.17
63 |
64 |
65 |
66 | io.swagger
67 | swagger-compat-spec-parser
68 | 1.0.17
69 |
70 |
71 |
72 | io.swagger
73 | swagger-core
74 | 1.5.8
75 |
76 |
77 |
78 | org.raml
79 | raml-parser
80 | 0.8.11
81 |
82 |
83 |
84 | org.apache.commons
85 | commons-io
86 | 1.3.2
87 |
88 |
89 |
90 | org.apache.commons
91 | commons-lang3
92 | 3.4
93 |
94 |
95 |
96 | com.google.guava
97 | guava
98 | 18.0
99 |
100 |
101 |
102 | com.amazonaws
103 | aws-java-sdk
104 | 1.9.6
105 |
106 |
107 |
108 | org.apache.httpcomponents
109 | httpclient
110 | 4.3.3
111 |
112 |
113 |
114 |
115 | junit
116 | junit
117 | 4.10
118 | test
119 |
120 |
121 |
122 | org.mockito
123 | mockito-all
124 | 2.0.2-beta
125 | test
126 |
127 |
128 |
129 | com.fasterxml.jackson.core
130 | jackson-annotations
131 | 2.5.0
132 |
133 |
134 |
135 | com.fasterxml.jackson.core
136 | jackson-core
137 | 2.5.0
138 |
139 |
140 |
141 |
142 |
143 |
147 |
148 | release-sign-artifacts
149 |
150 |
151 | performRelease
152 | true
153 |
154 |
155 |
156 |
157 |
158 | org.apache.maven.plugins
159 | maven-gpg-plugin
160 |
161 |
162 | sign-artifacts
163 | verify
164 |
165 | sign
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 | package
177 |
178 | ${basedir}/src
179 | ${basedir}/tst
180 |
181 |
182 |
183 | ${project.basedir}
184 |
185 | LICENSE
186 | NOTICE.txt
187 | README.md
188 |
189 |
190 |
191 |
192 |
193 |
194 | ${basedir}/tst/resources
195 |
196 |
197 |
198 |
199 |
200 | org.apache.maven.plugins
201 | maven-compiler-plugin
202 | 2.5.1
203 |
204 | 1.8
205 | 1.8
206 |
207 |
208 |
209 |
210 | org.apache.maven.plugins
211 | maven-source-plugin
212 | 2.2.1
213 |
214 |
215 | attach-sources
216 |
217 | jar
218 |
219 |
220 | true
221 |
222 |
223 |
224 |
225 |
226 |
227 | org.apache.maven.plugins
228 | maven-javadoc-plugin
229 | 2.9.1
230 |
231 |
232 | attach-javadocs
233 |
234 | jar
235 |
236 |
237 |
238 |
239 |
240 |
241 | org.apache.maven.plugins
242 | maven-release-plugin
243 | 2.4.2
244 |
245 | clean verify install
246 | false
247 | true
248 |
249 |
250 |
251 |
252 | maven-assembly-plugin
253 |
254 |
255 | jar-with-dependencies
256 |
257 |
258 |
259 | com.amazonaws.service.apigateway.importer.ApiImporterMain
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 | Apache License, Version 2.0
270 | https://aws.amazon.com/apache2.0
271 | repo
272 |
273 |
274 |
275 |
276 | scm:git:git@github.com:awslabs/aws-apigateway-importer.git
277 | scm:git:git@github.com:awslabs/aws-apigateway-importer.git
278 | scm:git:git@github.com:awslabs/aws-apigateway-importer.git
279 | HEAD
280 |
281 |
282 |
283 |
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/ApiImporterMain.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer;
16 |
17 | import com.amazonaws.auth.AWSCredentialsProvider;
18 | import com.amazonaws.auth.AWSCredentialsProviderChain;
19 | import com.amazonaws.auth.EnvironmentVariableCredentialsProvider;
20 | import com.amazonaws.auth.InstanceProfileCredentialsProvider;
21 | import com.amazonaws.auth.SystemPropertiesCredentialsProvider;
22 | import com.amazonaws.auth.profile.ProfileCredentialsProvider;
23 | import com.amazonaws.service.apigateway.importer.config.ApiImporterDefaultModule;
24 | import com.amazonaws.service.apigateway.importer.config.AwsConfig;
25 | import com.amazonaws.service.apigateway.importer.impl.ApiGatewayRamlFileImporter;
26 | import com.amazonaws.service.apigateway.importer.impl.ApiGatewaySwaggerFileImporter;
27 | import com.amazonaws.util.json.JSONException;
28 | import com.amazonaws.util.json.JSONObject;
29 | import com.amazonaws.util.json.JSONTokener;
30 | import com.beust.jcommander.JCommander;
31 | import com.beust.jcommander.Parameter;
32 | import com.google.inject.Guice;
33 | import com.google.inject.Injector;
34 | import org.apache.commons.io.FilenameUtils;
35 | import org.apache.commons.lang3.StringUtils;
36 | import org.apache.commons.logging.Log;
37 | import org.apache.commons.logging.LogFactory;
38 | import org.apache.log4j.ConsoleAppender;
39 | import org.apache.log4j.Level;
40 | import org.apache.log4j.Logger;
41 | import org.apache.log4j.PatternLayout;
42 |
43 | import java.io.File;
44 | import java.io.FileReader;
45 | import java.util.List;
46 |
47 | public class ApiImporterMain {
48 | private static final Log LOG = LogFactory.getLog(ApiImporterMain.class);
49 | private static final String CMD_NAME = "aws-api-import";
50 |
51 | @Parameter(names = {"--update", "-u"}, description = "API ID to import swagger into an existing API")
52 | private String apiId;
53 |
54 | @Parameter(names = {"--create", "-c"}, description = "Create a new API")
55 | private boolean createNew;
56 |
57 | @Parameter(description = "Path to API definition file to import")
58 | private List files;
59 |
60 | @Parameter(names = {"--deploy", "-d"}, description = "Stage used to deploy the API (optional)")
61 | private String deploymentLabel;
62 |
63 | @Parameter(names = {"--test", "-t"}, description = "Delete the API after import (create only)")
64 | private boolean cleanup = false;
65 |
66 | @Parameter(names = {"--region", "-r"}, description = "AWS region to use (optional)")
67 | private String region;
68 |
69 | @Parameter(names = {"--profile", "-p"}, description = "AWS CLI profile to use (optional)")
70 | private String profile = "default";
71 |
72 | @Parameter(names = {"--raml-config"}, description = "RAML file for API Gateway metadata (optional)")
73 | private String configFile;
74 |
75 | @Parameter(names = "--help", help = true)
76 | private boolean help;
77 |
78 | public static void main(String[] args) {
79 | bootstrap();
80 | ApiImporterMain main = new ApiImporterMain();
81 | JCommander jCommander = new JCommander(main, args);
82 | jCommander.setProgramName(CMD_NAME);
83 | main.execute(jCommander);
84 | }
85 |
86 | static void bootstrap() {
87 | Logger root = Logger.getRootLogger();
88 | root.setLevel(Level.INFO);
89 | root.addAppender(new ConsoleAppender(new PatternLayout("%d %p - %m%n")));
90 | }
91 |
92 | public void execute(JCommander jCommander) {
93 | if (help) {
94 | jCommander.usage();
95 | return;
96 | }
97 |
98 | if (!validateArgs()) {
99 | jCommander.usage();
100 | System.exit(1);
101 | }
102 |
103 | // use default AWS credentials provider chain
104 | AWSCredentialsProvider credentialsProvider = new AWSCredentialsProviderChain(
105 | new EnvironmentVariableCredentialsProvider(),
106 | new SystemPropertiesCredentialsProvider(),
107 | new ProfileCredentialsProvider(profile),
108 | new InstanceProfileCredentialsProvider());
109 |
110 | // if region parameter is not specified, attempt to load configured region from profile
111 | if (StringUtils.isBlank(region)) {
112 | AwsConfig config = new AwsConfig(profile);
113 | try {
114 | config.load();
115 | } catch (Throwable t) {
116 | LOG.error("Could not load region from profile and no region parameter specified. " +
117 | "Please run 'aws configure' or specify region with '--region' parameter.");
118 | System.exit(1);
119 | }
120 | region = config.getRegion();
121 | }
122 |
123 | try {
124 | Injector injector = Guice.createInjector(new ApiImporterDefaultModule(credentialsProvider, region));
125 |
126 | String fileName = files.get(0);
127 |
128 | if (FilenameUtils.getExtension(fileName).equals("raml")) {
129 | final JSONObject configData;
130 |
131 | RamlApiFileImporter importer = injector.getInstance(ApiGatewayRamlFileImporter.class);
132 |
133 | try {
134 | configData = configFile == null ? null : new JSONObject(new JSONTokener(new FileReader(configFile)));
135 | } catch (JSONException e) {
136 | LOG.info("Unable to parse configuration file: " + e);
137 | System.exit(1);
138 | return;
139 | }
140 |
141 | importRaml(fileName, configData, importer);
142 | } else {
143 | SwaggerApiFileImporter importer = injector.getInstance(ApiGatewaySwaggerFileImporter.class);
144 |
145 | importSwagger(fileName, importer);
146 | }
147 | } catch (Throwable t) {
148 | LOG.error("Error importing API definition", t);
149 | System.exit(1);
150 | }
151 | }
152 |
153 | private void importSwagger(String fileName, SwaggerApiFileImporter importer) {
154 | if (createNew) {
155 | apiId = importer.importApi(fileName);
156 |
157 | if (cleanup) {
158 | importer.deleteApi(apiId);
159 | }
160 | } else {
161 | importer.updateApi(apiId, fileName);
162 | }
163 |
164 | if (!StringUtils.isBlank(deploymentLabel)) {
165 | importer.deploy(apiId, deploymentLabel);
166 | }
167 | }
168 |
169 | private void importRaml(String fileName, JSONObject configData, RamlApiFileImporter importer) {
170 | if (createNew) {
171 | apiId = importer.importApi(fileName, configData);
172 |
173 | if (cleanup) {
174 | importer.deleteApi(apiId);
175 | }
176 | } else {
177 | importer.updateApi(apiId, fileName, configData);
178 | }
179 |
180 | if (!StringUtils.isBlank(deploymentLabel)) {
181 | importer.deploy(apiId, deploymentLabel);
182 | }
183 | }
184 |
185 | private boolean validateArgs() {
186 | if ((apiId == null && !createNew) || files == null || files.isEmpty()) {
187 | return false;
188 | }
189 |
190 | if (cleanup && apiId != null) {
191 | LOG.error("Test mode is not supported when updating an API");
192 | return false;
193 | }
194 |
195 | final String fileName = files.get(0);
196 |
197 | if (!new File(fileName).exists()) {
198 | LOG.error(String.format("Could not load file '%s'", fileName));
199 | return false;
200 | }
201 |
202 | return true;
203 | }
204 |
205 | }
206 |
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/RamlApiFileImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer;
16 |
17 | import com.amazonaws.util.json.JSONObject;
18 |
19 | public interface RamlApiFileImporter {
20 | String importApi(String filePath, JSONObject config);
21 | void updateApi(String apiId, String filePath, JSONObject config);
22 | void deploy(String apiId, String deploymentStage);
23 | void deleteApi(String apiId);
24 | }
25 |
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/RamlApiImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer;
16 |
17 | import com.amazonaws.util.json.JSONObject;
18 | import org.raml.model.Raml;
19 |
20 | public interface RamlApiImporter {
21 | String createApi(Raml raml, String name, JSONObject config);
22 | void updateApi(String apiId, Raml raml, JSONObject config);
23 | void deploy(String apiId, String deploymentStage);
24 | void deleteApi(String apiId);
25 | }
26 |
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/SwaggerApiFileImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer;
16 |
17 | public interface SwaggerApiFileImporter {
18 | String importApi(String filePath);
19 | void updateApi(String apiId, String filePath);
20 | void deploy(String apiId, String deploymentStage);
21 | void deleteApi(String apiId);
22 | }
23 |
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/SwaggerApiImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer;
16 |
17 | import io.swagger.models.Swagger;
18 |
19 | public interface SwaggerApiImporter {
20 | String createApi(Swagger swagger, String name);
21 | void updateApi(String apiId, Swagger swagger);
22 | void deploy(String apiId, String deploymentStage);
23 | void deleteApi(String apiId);
24 | }
25 |
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/config/ApiImporterDefaultModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.config;
16 |
17 | import com.amazonaws.AmazonServiceException;
18 | import com.amazonaws.ClientConfiguration;
19 | import com.amazonaws.auth.AWSCredentialsProvider;
20 | import com.amazonaws.retry.PredefinedRetryPolicies;
21 | import com.amazonaws.retry.RetryPolicy;
22 | import com.amazonaws.retry.RetryUtils;
23 | import com.amazonaws.service.apigateway.importer.ApiImporterMain;
24 | import com.amazonaws.service.apigateway.importer.RamlApiImporter;
25 | import com.amazonaws.service.apigateway.importer.SwaggerApiImporter;
26 | import com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkRamlApiImporter;
27 | import com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkSwaggerApiImporter;
28 | import com.amazonaws.services.apigateway.AmazonApiGateway;
29 | import com.amazonaws.services.apigateway.model.ApiGateway;
30 | import com.google.inject.AbstractModule;
31 | import com.google.inject.Provides;
32 | import com.google.inject.name.Named;
33 | import com.google.inject.name.Names;
34 | import org.apache.commons.logging.Log;
35 | import org.apache.commons.logging.LogFactory;
36 |
37 | import java.util.Random;
38 |
39 | public class ApiImporterDefaultModule extends AbstractModule {
40 | private static final Log LOG = LogFactory.getLog(ApiImporterMain.class);
41 | private static final String USER_AGENT = "AmazonApiGatewaySwaggerImporter/1.0";
42 |
43 | private final AWSCredentialsProvider awsCredentialsProvider;
44 |
45 | private String region;
46 |
47 | public ApiImporterDefaultModule(AWSCredentialsProvider awsCredentialsProvider, String region) {
48 | this.awsCredentialsProvider = awsCredentialsProvider;
49 | this.region = region;
50 |
51 | LOG.info("Using API Gateway endpoint " + getEndpoint(region));
52 | }
53 |
54 | @Override
55 | protected void configure() {
56 | bind(SwaggerApiImporter.class).to(ApiGatewaySdkSwaggerApiImporter.class);
57 | bind(RamlApiImporter.class).to(ApiGatewaySdkRamlApiImporter.class);
58 | bind(String.class).annotatedWith(Names.named("region")).toInstance(region);
59 | }
60 |
61 | @Provides
62 | protected AWSCredentialsProvider provideCredentialsProvider() {
63 | return awsCredentialsProvider;
64 | }
65 |
66 | @Provides
67 | protected ApiGateway provideAmazonApiGateway(AWSCredentialsProvider credsProvider,
68 | RetryPolicy.BackoffStrategy backoffStrategy,
69 | @Named("region") String region) {
70 |
71 | final RetryPolicy retrypolicy = new RetryPolicy(PredefinedRetryPolicies.DEFAULT_RETRY_CONDITION, backoffStrategy, 5, true);
72 |
73 | final ClientConfiguration clientConfig = new ClientConfiguration().withUserAgent(USER_AGENT).withRetryPolicy(retrypolicy);
74 |
75 | return new AmazonApiGateway(getEndpoint(region)).with(credsProvider).with(clientConfig).getApiGateway();
76 | }
77 |
78 | protected String getEndpoint(String region) {
79 | return String.format("https://apigateway.%s.amazonaws.com", region);
80 | }
81 |
82 | /*
83 | * Override the default SDK exponential backoff implementation
84 | * See {@link PredefinedRetryPolicies#DEFAULT_BACKOFF_STRATEGY
85 | */
86 | @Provides
87 | protected RetryPolicy.BackoffStrategy provideBackoffStrategy() {
88 |
89 | // tune these parameters to handle throttling errors
90 | final int maxBackoffInMilliseconds = 50 * 1000; // maximum exponential back-off time before retrying a request
91 | final int throttlingScaleFactor = 800; // base sleep time for throttling exceptions
92 | final int maxRetriesBeforeBackoff = 10; // log2(maxBackoffInMilliseconds/throttlingScaleFactor)
93 |
94 | final int baseScaleFactor = 600; // base sleep time for general exceptions
95 | final int throttlingScaleFactorRandomRange = throttlingScaleFactor / 4;
96 |
97 | final Random random = new Random();
98 |
99 | return (originalRequest, exception, retriesAttempted) -> {
100 |
101 | LOG.debug("Caught error from service. Retry attempt: " + retriesAttempted, exception);
102 |
103 | if (retriesAttempted < 0) return 0;
104 | if (retriesAttempted > maxRetriesBeforeBackoff) return maxBackoffInMilliseconds;
105 |
106 | int scaleFactor;
107 | if (exception instanceof AmazonServiceException
108 | && RetryUtils.isThrottlingException((AmazonServiceException) exception)) {
109 | scaleFactor = throttlingScaleFactor + random.nextInt(throttlingScaleFactorRandomRange);
110 | } else {
111 | scaleFactor = baseScaleFactor;
112 | }
113 |
114 | long delay = (1L << retriesAttempted) * scaleFactor;
115 | delay = Math.min(delay, maxBackoffInMilliseconds);
116 |
117 | LOG.info("Client backing off for " + delay + "ms");
118 |
119 | return delay;
120 | };
121 | }
122 | }
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/config/AwsConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.config;
16 |
17 | import org.apache.commons.logging.Log;
18 | import org.apache.commons.logging.LogFactory;
19 |
20 | import java.io.BufferedReader;
21 | import java.io.File;
22 | import java.io.FileReader;
23 | import java.util.Optional;
24 | import java.util.regex.*;
25 |
26 | public class AwsConfig {
27 | private static final Log LOG = LogFactory.getLog(AwsConfig.class);
28 | public static final String DEFAULT_REGION = "us-east-1";
29 |
30 | private String region;
31 | private String profile;
32 |
33 | public AwsConfig(String profile) {
34 | this.profile = profile;
35 | }
36 |
37 | public String getRegion() {
38 | return region;
39 | }
40 |
41 | public String getProfile() {
42 | return profile;
43 | }
44 |
45 | public void load() {
46 | Optional region = loadRegion();
47 |
48 | if (region.isPresent()) {
49 | this.region = region.get();
50 | } else {
51 | this.region = DEFAULT_REGION;
52 | LOG.warn("Could not load region configuration. Please ensure AWS CLI is " +
53 | "configured via 'aws configure'. Will use default region of " + this.region);
54 | }
55 | }
56 |
57 | private Optional loadRegion() {
58 | String file = System.getProperty("user.home") + "/.aws/config";
59 |
60 | boolean foundProfile = false;
61 | try (BufferedReader br = new BufferedReader(new FileReader(new File(file)))) {
62 | String line;
63 | String region;
64 | Pattern regionPat = Pattern.compile("[a-z]{2}+-[a-z]{2,}+-[0-9]");
65 | Matcher regionMat;
66 | Integer eqPos;
67 |
68 | while ((line = br.readLine()) != null) {
69 |
70 | if (line.startsWith("[") && line.contains(this.profile)) {
71 | foundProfile = true;
72 | }
73 |
74 | if (foundProfile && line.startsWith("region")) {
75 | eqPos = line.indexOf("=");
76 | region = line.substring(eqPos + 1, line.length()).trim();
77 | regionMat = regionPat.matcher(region);
78 | if (! regionMat.matches()) {
79 | LOG.error("Region does not match '[a-z]{2}+-[a-z]{2,}+-[0-9]': " + region);
80 | throw new RuntimeException("Region does not match '[a-z]{2}+-[a-z]{2,}+-[0-9]'" + region);
81 | }
82 | return Optional.of(region);
83 | }
84 | }
85 | } catch (Throwable t) {
86 | throw new RuntimeException("Could not load configuration. Please run 'aws configure'");
87 | }
88 |
89 | return Optional.empty();
90 | }
91 |
92 | }
93 |
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/impl/ApiGatewayRamlFileImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.impl;
16 |
17 | import com.amazonaws.service.apigateway.importer.RamlApiFileImporter;
18 | import com.amazonaws.service.apigateway.importer.RamlApiImporter;
19 | import com.amazonaws.util.json.JSONObject;
20 | import com.google.inject.Inject;
21 | import org.apache.commons.logging.Log;
22 | import org.apache.commons.logging.LogFactory;
23 | import org.raml.model.Raml;
24 | import org.raml.parser.visitor.RamlDocumentBuilder;
25 |
26 | import java.io.File;
27 |
28 | import static java.lang.String.format;
29 |
30 | public class ApiGatewayRamlFileImporter implements RamlApiFileImporter {
31 | private static final Log LOG = LogFactory.getLog(ApiGatewayRamlFileImporter.class);
32 |
33 | private final RamlDocumentBuilder builder;
34 | private final RamlApiImporter client;
35 |
36 | @Inject
37 | public ApiGatewayRamlFileImporter(RamlDocumentBuilder builder, RamlApiImporter client) {
38 | this.builder = builder;
39 | this.client = client;
40 | }
41 |
42 | @Override
43 | public String importApi(String filePath, JSONObject config) {
44 | LOG.info(format("Attempting to create API from RAML definition. " +
45 | "RAML file: %s", filePath));
46 |
47 | final Raml raml = parse(filePath);
48 |
49 | return client.createApi(raml, new File(filePath).getName(), config);
50 | }
51 |
52 | @Override
53 | public void updateApi(String apiId, String filePath, JSONObject config) {
54 | LOG.info(format("Attempting to update API from RAML definition. " +
55 | "API identifier: %s RAML file: %s", apiId, filePath));
56 |
57 | final Raml raml = parse(filePath);
58 |
59 | client.updateApi(apiId, raml, config);
60 | }
61 |
62 | @Override
63 | public void deploy(String apiId, String deploymentStage) {
64 | client.deploy(apiId, deploymentStage);
65 | }
66 |
67 | @Override
68 | public void deleteApi(String apiId) {
69 | client.deleteApi(apiId);
70 | }
71 |
72 | private Raml parse(String filePath) {
73 | final Raml raml = builder.build(filePath);
74 |
75 | // TODO: Error handling.
76 |
77 | return raml;
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/impl/ApiGatewaySwaggerFileImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.impl;
16 |
17 | import com.amazonaws.service.apigateway.importer.SwaggerApiFileImporter;
18 | import com.amazonaws.service.apigateway.importer.SwaggerApiImporter;
19 | import com.google.inject.Inject;
20 | import io.swagger.models.Swagger;
21 | import io.swagger.parser.SwaggerParser;
22 | import org.apache.commons.logging.Log;
23 | import org.apache.commons.logging.LogFactory;
24 |
25 | import java.io.File;
26 |
27 | import static java.lang.String.format;
28 |
29 | public class ApiGatewaySwaggerFileImporter implements SwaggerApiFileImporter {
30 | private static final Log LOG = LogFactory.getLog(ApiGatewaySwaggerFileImporter.class);
31 |
32 | private final SwaggerParser parser;
33 | private final SwaggerApiImporter client;
34 |
35 | @Inject
36 | public ApiGatewaySwaggerFileImporter(SwaggerParser parser, SwaggerApiImporter client) {
37 | this.parser = parser;
38 | this.client = client;
39 | }
40 |
41 | @Override
42 | public String importApi(String filePath) {
43 | LOG.info(format("Attempting to create API from Swagger definition. " +
44 | "Swagger file: %s", filePath));
45 |
46 | final Swagger swagger = parse(filePath);
47 |
48 | return client.createApi(swagger, new File(filePath).getName());
49 | }
50 |
51 | @Override
52 | public void updateApi(String apiId, String filePath) {
53 | LOG.info(format("Attempting to update API from Swagger definition. " +
54 | "API identifier: %s Swagger file: %s", apiId, filePath));
55 |
56 | final Swagger swagger = parse(filePath);
57 |
58 | client.updateApi(apiId, swagger);
59 | }
60 |
61 | @Override
62 | public void deploy(String apiId, String deploymentStage) {
63 | client.deploy(apiId, deploymentStage);
64 | }
65 |
66 | @Override
67 | public void deleteApi(String apiId) {
68 | client.deleteApi(apiId);
69 | }
70 |
71 | private Swagger parse(String filePath) {
72 | final Swagger swagger = parser.read(filePath);
73 |
74 | if (swagger != null && swagger.getPaths() != null) {
75 | LOG.info("Parsed Swagger with " + swagger.getPaths().size() + " paths");
76 | }
77 |
78 | return swagger;
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/impl/SchemaTransformer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.impl;
16 |
17 | import com.fasterxml.jackson.core.JsonProcessingException;
18 | import com.fasterxml.jackson.databind.JsonNode;
19 | import com.fasterxml.jackson.databind.ObjectMapper;
20 | import com.fasterxml.jackson.databind.node.JsonNodeFactory;
21 | import com.fasterxml.jackson.databind.node.ObjectNode;
22 | import com.fasterxml.jackson.databind.node.TextNode;
23 | import com.github.fge.jsonschema.core.exceptions.ProcessingException;
24 | import com.github.fge.jsonschema.core.report.ProcessingReport;
25 | import com.github.fge.jsonschema.main.JsonSchemaFactory;
26 | import org.apache.log4j.Logger;
27 |
28 | import java.io.IOException;
29 | import java.util.HashMap;
30 | import java.util.Map;
31 |
32 | /**
33 | * Deserializes and transforms schema schemas into normalized form
34 | *
35 | * @author rpgreen
36 | */
37 | public class SchemaTransformer {
38 | protected final static Logger LOG = Logger.getLogger(SchemaTransformer.class);
39 |
40 | /**
41 | * Get a schema schema in "flattened" form whereby all dependent references are resolved
42 | * and included as inline schema definitions
43 | *
44 | * @return the json-schema string in flattened form
45 | */
46 | public String flatten(String model, String models) {
47 | return getFlattened(deserialize(model), deserialize(models));
48 | }
49 |
50 | private void buildSchemaReferenceMap(JsonNode model, JsonNode models, Map modelMap) {
51 | Map refs = new HashMap<>();
52 | findReferences(model, refs);
53 |
54 | for (JsonNode ref : refs.keySet()) {
55 | String canonicalRef = ref.textValue();
56 |
57 | String schemaName = getSchemaName(canonicalRef);
58 |
59 | JsonNode subSchema = getSchema(schemaName, models);
60 |
61 | // replace reference values with inline definitions
62 | replaceRef((ObjectNode) refs.get(ref), schemaName);
63 |
64 | buildSchemaReferenceMap(subSchema, models, modelMap);
65 |
66 | modelMap.put(schemaName, serializeExisting(subSchema));
67 | }
68 | }
69 |
70 | private JsonNode getSchema(String schemaName, JsonNode models) {
71 | return models.findPath(schemaName);
72 | }
73 |
74 | private String getFlattened(JsonNode model, JsonNode models) {
75 | HashMap schemaMap = new HashMap<>();
76 |
77 | buildSchemaReferenceMap(model, models, schemaMap);
78 |
79 | replaceRefs(model, schemaMap);
80 |
81 | if (LOG.isTraceEnabled()) {
82 | try {
83 | LOG.trace("Flattened schema to: " + new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(model));
84 | } catch (JsonProcessingException ignored){}
85 | }
86 |
87 | String flattened = serializeExisting(model);
88 |
89 | validate(model);
90 |
91 | return flattened;
92 | }
93 |
94 | private void validate(JsonNode rootNode) {
95 | final JsonSchemaFactory factory;
96 | try {
97 | factory = JsonSchemaFactory.byDefault();
98 | factory.getJsonSchema(rootNode);
99 | } catch (ProcessingException e) {
100 | throw new IllegalStateException("Invalid schema json was generated", e);
101 | } catch (ExceptionInInitializerError | NoClassDefFoundError e) {
102 | return; // this should only happen from test code. JsonSchemaFactory not easily mocked
103 | }
104 |
105 | ProcessingReport report = factory.getSyntaxValidator().validateSchema(rootNode);
106 | if (!report.isSuccess()) {
107 | throw new IllegalStateException("Invalid schema json was generated" + report.iterator().next().getMessage());
108 | }
109 | }
110 |
111 | /*
112 | * Add schema references as inline definitions to the root schema
113 | */
114 | private void replaceRefs(JsonNode root, HashMap schemaMap) {
115 |
116 | ObjectNode definitionsNode = new ObjectNode(JsonNodeFactory.instance);
117 |
118 | for (Map.Entry entry : schemaMap.entrySet()) {
119 | JsonNode schemaNode = deserialize(entry.getValue());
120 | definitionsNode.set(entry.getKey(), schemaNode);
121 | }
122 |
123 | ((ObjectNode)root).set("definitions", definitionsNode);
124 | }
125 |
126 | /*
127 | * Replace a reference node with an inline reference
128 | */
129 | private void replaceRef(ObjectNode parent, String schemaName) {
130 | parent.set("$ref", new TextNode("#/definitions/" + schemaName));
131 | }
132 |
133 | /*
134 | * Find all reference node in the schema tree. Build a map of the reference node to its parent
135 | */
136 | private void findReferences(JsonNode node, Map refNodes) {
137 | JsonNode refNode = node.path("$ref");
138 | if (!refNode.isMissingNode()) {
139 | refNodes.put(refNode, node);
140 | }
141 |
142 | for (JsonNode child : node) {
143 | findReferences(child, refNodes);
144 | }
145 | }
146 |
147 | /*
148 | * Attempt to serialize an existing schema
149 | * If this fails something is seriously wrong, because this schema has already been saved by the control plane
150 | */
151 | JsonNode deserialize(String schemaText) {
152 | try {
153 | ObjectMapper mapper = new ObjectMapper();
154 | return mapper.readTree(schemaText);
155 | } catch (IOException e) {
156 | throw new IllegalStateException("Invalid schema found. Could not deserialize schema: " + schemaText, e);
157 | }
158 | }
159 |
160 | /*
161 | * Attempt to serialize an existing schema
162 | * If this fails something is seriously wrong, because this schema has already been saved by the control plane
163 | */
164 | private String serializeExisting(JsonNode root) {
165 | try {
166 | return new ObjectMapper().writeValueAsString(root);
167 | } catch (JsonProcessingException e) {
168 | throw new IllegalStateException("Could not serialize generated schema json", e);
169 | }
170 | }
171 |
172 | public static String getSchemaName(String refVal) {
173 | String schemaName;
174 | try {
175 | schemaName = refVal.substring(refVal.lastIndexOf("/") + 1,
176 | refVal.length());
177 | } catch (Throwable t) {
178 | throw new IllegalStateException("Invalid reference found: " + refVal, t);
179 | }
180 |
181 | return schemaName;
182 | }
183 |
184 | public static String getRestApiId(String refVal) {
185 | String apiId;
186 | try {
187 | apiId = refVal.substring(refVal.indexOf("restapis/"),
188 | refVal.length()).split("/")[1];
189 | } catch (Throwable t) {
190 | throw new IllegalStateException("Invalid reference found: " + refVal, t);
191 | }
192 |
193 | return apiId;
194 | }
195 |
196 | }
197 |
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/impl/sdk/ApiGatewaySdkApiImporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.impl.sdk;
16 |
17 | import com.amazonaws.services.apigateway.model.ApiGateway;
18 | import com.amazonaws.services.apigateway.model.CreateDeploymentInput;
19 | import com.amazonaws.services.apigateway.model.CreateModelInput;
20 | import com.amazonaws.services.apigateway.model.CreateResourceInput;
21 | import com.amazonaws.services.apigateway.model.CreateRestApiInput;
22 | import com.amazonaws.services.apigateway.model.Model;
23 | import com.amazonaws.services.apigateway.model.Models;
24 | import com.amazonaws.services.apigateway.model.NotFoundException;
25 | import com.amazonaws.services.apigateway.model.Resource;
26 | import com.amazonaws.services.apigateway.model.Resources;
27 | import com.amazonaws.services.apigateway.model.RestApi;
28 | import com.google.common.util.concurrent.RateLimiter;
29 | import com.google.inject.Inject;
30 | import org.apache.commons.lang3.StringUtils;
31 | import org.apache.commons.logging.Log;
32 | import org.apache.commons.logging.LogFactory;
33 |
34 | import java.util.ArrayList;
35 | import java.util.HashSet;
36 | import java.util.List;
37 | import java.util.Optional;
38 | import java.util.Set;
39 | import java.util.stream.Stream;
40 |
41 | import static com.amazonaws.service.apigateway.importer.util.PatchUtils.createPatchDocument;
42 | import static com.amazonaws.service.apigateway.importer.util.PatchUtils.createReplaceOperation;
43 |
44 | public class ApiGatewaySdkApiImporter {
45 |
46 | private static final Log LOG = LogFactory.getLog(ApiGatewaySdkApiImporter.class);
47 |
48 | @Inject
49 | protected ApiGateway apiGateway;
50 |
51 | // keep track of the models created/updated from the definition file. Any orphaned models left in the API will be deleted
52 | protected HashSet processedModels = new HashSet<>();
53 |
54 | public void deleteApi(String apiId) {
55 | deleteApi(apiGateway.getRestApiById(apiId));
56 | }
57 |
58 | public void deploy(String apiId, String deploymentStage) {
59 | LOG.info(String.format("Creating deployment for API %s and stage %s", apiId, deploymentStage));
60 |
61 | CreateDeploymentInput input = new CreateDeploymentInput();
62 | input.setStageName(deploymentStage);
63 |
64 | apiGateway.getRestApiById(apiId).createDeployment(input);
65 | }
66 |
67 | protected RestApi createApi(String name, String description) {
68 | LOG.info("Creating API with name " + name);
69 |
70 | CreateRestApiInput input = new CreateRestApiInput();
71 | input.setName(name);
72 | input.setDescription(description);
73 |
74 | return apiGateway.createRestApi(input);
75 | }
76 |
77 | protected void rollback(RestApi api) {
78 | deleteApi(api);
79 | }
80 |
81 | protected void deleteApi(RestApi api) {
82 | LOG.info("Deleting API " + api.getId());
83 | api.deleteRestApi();
84 | }
85 |
86 | protected Optional getRootResource(RestApi api) {
87 | for (Resource r : buildResourceList(api)) {
88 | if ("/".equals(r.getPath())) {
89 | return Optional.of(r);
90 | }
91 | }
92 | return Optional.empty();
93 | }
94 |
95 | // todo: optimize number of calls to this as it is an expensive operation
96 | protected List buildResourceList(RestApi api) {
97 | List resourceList = new ArrayList<>();
98 |
99 | Resources resources = api.getResources();
100 | resourceList.addAll(resources.getItem());
101 |
102 | LOG.debug("Building list of resources. Stack trace: ", new Throwable());
103 |
104 | final RateLimiter rl = RateLimiter.create(2);
105 | while (resources._isLinkAvailable("next")) {
106 | rl.acquire();
107 | resources = resources.getNext();
108 | resourceList.addAll(resources.getItem());
109 | }
110 |
111 | return resourceList;
112 | }
113 |
114 | protected void deleteDefaultModels(RestApi api) {
115 | buildModelList(api).stream().forEach(model -> {
116 | LOG.info("Removing default model " + model.getName());
117 | try {
118 | model.deleteModel();
119 | } catch (Throwable ignored) {
120 | } // todo: temporary catch until API fix
121 | });
122 | }
123 |
124 | protected List buildModelList(RestApi api) {
125 | List modelList = new ArrayList<>();
126 |
127 | Models models = api.getModels();
128 | modelList.addAll(models.getItem());
129 |
130 | while (models._isLinkAvailable("next")) {
131 | models = models.getNext();
132 | modelList.addAll(models.getItem());
133 | }
134 |
135 | return modelList;
136 | }
137 |
138 | protected RestApi getApi(String id) {
139 | return apiGateway.getRestApiById(id);
140 | }
141 |
142 | protected void createModel(RestApi api, String modelName, String description, String schema, String modelContentType) {
143 | this.processedModels.add(modelName);
144 |
145 | CreateModelInput input = new CreateModelInput();
146 |
147 | input.setName(modelName);
148 | input.setDescription(description);
149 | input.setContentType(modelContentType);
150 | input.setSchema(schema);
151 |
152 | api.createModel(input);
153 | }
154 |
155 | protected void updateModel(RestApi api, String modelName, String schema) {
156 | this.processedModels.add(modelName);
157 |
158 | api.getModelByName(modelName).updateModel(createPatchDocument(createReplaceOperation("/schema", schema)));
159 | }
160 |
161 | protected void cleanupModels(RestApi api, Set models) {
162 | List existingModels = buildModelList(api);
163 | Stream modelsToDelete = existingModels.stream().filter(model -> !models.contains(model.getName()));
164 |
165 | modelsToDelete.forEach(model -> {
166 | LOG.info("Removing deleted model " + model.getName());
167 | model.deleteModel();
168 | });
169 | }
170 |
171 | protected Optional getResource(String parentResourceId, String pathPart, List resources) {
172 | for (Resource r : resources) {
173 | if (pathEquals(pathPart, r.getPathPart()) && r.getParentId().equals(parentResourceId)) {
174 | return Optional.of(r);
175 | }
176 | }
177 | return Optional.empty();
178 | }
179 |
180 | protected boolean pathEquals(String p1, String p2) {
181 | return (StringUtils.isBlank(p1) && StringUtils.isBlank(p2)) || p1.equals(p2);
182 | }
183 |
184 | protected Optional getResource(RestApi api, String fullPath) {
185 | for (Resource r : buildResourceList(api)) {
186 | if (r.getPath().equals(fullPath)) {
187 | return Optional.of(r);
188 | }
189 | }
190 |
191 | return Optional.empty();
192 | }
193 |
194 | protected Optional getModel(RestApi api, String modelName) {
195 | try {
196 | return Optional.of(api.getModelByName(modelName));
197 | } catch (Exception ignored) {
198 | return Optional.empty();
199 | }
200 | }
201 |
202 | protected boolean methodExists(Resource resource, String httpMethod) {
203 | return resource.getResourceMethods().get(httpMethod.toUpperCase()) != null;
204 | }
205 |
206 | protected void deleteResource(Resource resource) {
207 | if (resource._isLinkAvailable("resource:delete")) {
208 | try {
209 | resource.deleteResource();
210 | } catch (NotFoundException error) {}
211 | }
212 | // can't delete root resource
213 | }
214 |
215 | /**
216 | * Build the full resource path, including base path, add any missing leading '/', remove any trailing '/',
217 | * and remove any double '/'
218 | * @param basePath the base path
219 | * @param resourcePath the resource path
220 | * @return the full path
221 | */
222 | protected String buildResourcePath(String basePath, String resourcePath) {
223 | if (basePath == null) {
224 | basePath = "";
225 | }
226 | String base = trimSlashes(basePath);
227 | if (!base.equals("")) {
228 | base = "/" + base;
229 | }
230 | String result = StringUtils.removeEnd(base + "/" + trimSlashes(resourcePath), "/");
231 | if (result.equals("")) {
232 | result = "/";
233 | }
234 | return result;
235 | }
236 |
237 | private String trimSlashes(String path) {
238 | return StringUtils.removeEnd(StringUtils.removeStart(path, "/"), "/");
239 | }
240 |
241 | protected Resource createResource(RestApi api, String parentResourceId, String part, List resources) {
242 | final Optional existingResource = getResource(parentResourceId, part, resources);
243 |
244 | // create resource if doesn't exist
245 | if (!existingResource.isPresent()) {
246 |
247 | LOG.info("Creating resource '" + part + "' on " + parentResourceId);
248 |
249 | CreateResourceInput input = new CreateResourceInput();
250 | input.setPathPart(part);
251 | Resource resource = api.getResourceById(parentResourceId);
252 |
253 | Resource created = resource.createResource(input);
254 |
255 | resources.add(created);
256 |
257 | return created;
258 | } else {
259 | return existingResource.get();
260 | }
261 | }
262 |
263 | protected String getStringValue(Object in) {
264 | return in == null ? null : String.valueOf(in); // use null value instead of "null"
265 | }
266 |
267 | }
268 |
--------------------------------------------------------------------------------
/src/com/amazonaws/service/apigateway/importer/util/PatchUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.util;
16 |
17 | import com.amazonaws.services.apigateway.model.PatchDocument;
18 | import com.amazonaws.services.apigateway.model.PatchOperation;
19 |
20 | import java.util.ArrayList;
21 |
22 | public class PatchUtils {
23 |
24 | public static PatchOperation createReplaceOperation(String path, String value) {
25 | PatchOperation op = new PatchOperation();
26 | op.setOp("replace");
27 | op.setPath(path);
28 | op.setValue(value);
29 | return op;
30 | }
31 |
32 | public static PatchOperation createRemoveOperation(String path) {
33 | PatchOperation op = new PatchOperation();
34 | op.setOp("remove");
35 | op.setPath(path);
36 | return op;
37 | }
38 |
39 | public static PatchOperation createAddOperation(String path, String value) {
40 | PatchOperation op = new PatchOperation();
41 | op.setOp("add");
42 | op.setPath(path);
43 | op.setValue(value);
44 | return op;
45 | }
46 |
47 | public static PatchDocument createPatchDocument(PatchOperation... ops) {
48 | PatchDocument pd = new PatchDocument();
49 | pd.setPatchOperations(new ArrayList<>());
50 | for (PatchOperation op : ops) {
51 | pd.getPatchOperations().add(op);
52 | }
53 | return pd;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tst/com/amazonaws/service/apigateway/importer/ApiImporterMainTest.java:
--------------------------------------------------------------------------------
1 | package com.amazonaws.service.apigateway.importer;
2 |
3 | import org.junit.Ignore;
4 | import org.junit.Test;
5 |
6 | import java.net.URISyntaxException;
7 | import java.nio.file.Paths;
8 |
9 | public class ApiImporterMainTest {
10 |
11 | @Test
12 | @Ignore
13 | public void test() throws URISyntaxException {
14 | ApiImporterMain main = new ApiImporterMain();
15 |
16 | String[] args = {"--create", Paths.get(getClass().getResource("/swagger/apigateway.json").toURI()).toString()};
17 | main.main(args);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/tst/com/amazonaws/service/apigateway/importer/config/RamlApiImporterTestModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.config;
16 |
17 | import com.amazonaws.service.apigateway.importer.RamlApiFileImporter;
18 | import com.amazonaws.service.apigateway.importer.RamlApiImporter;
19 | import com.amazonaws.service.apigateway.importer.impl.ApiGatewayRamlFileImporter;
20 | import com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkRamlApiImporter;
21 | import com.amazonaws.services.apigateway.model.ApiGateway;
22 | import com.google.inject.AbstractModule;
23 | import org.mockito.Mockito;
24 |
25 | public class RamlApiImporterTestModule extends AbstractModule {
26 |
27 | @Override
28 | protected void configure() {
29 | bind(RamlApiFileImporter.class).to(ApiGatewayRamlFileImporter.class);
30 | bind(RamlApiImporter.class).to(ApiGatewaySdkRamlApiImporter.class);
31 | bind(ApiGateway.class).toInstance(Mockito.mock(ApiGateway.class));
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/tst/com/amazonaws/service/apigateway/importer/config/SwaggerApiImporterTestModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.config;
16 |
17 | import com.amazonaws.service.apigateway.importer.SwaggerApiFileImporter;
18 | import com.amazonaws.service.apigateway.importer.SwaggerApiImporter;
19 | import com.amazonaws.service.apigateway.importer.impl.ApiGatewaySwaggerFileImporter;
20 | import com.amazonaws.service.apigateway.importer.impl.sdk.ApiGatewaySdkSwaggerApiImporter;
21 | import com.amazonaws.services.apigateway.model.ApiGateway;
22 | import com.google.inject.AbstractModule;
23 | import org.mockito.Mockito;
24 |
25 | public class SwaggerApiImporterTestModule extends AbstractModule {
26 |
27 | @Override
28 | protected void configure() {
29 | bind(SwaggerApiFileImporter.class).to(ApiGatewaySwaggerFileImporter.class);
30 | bind(SwaggerApiImporter.class).to(ApiGatewaySdkSwaggerApiImporter.class);
31 | bind(ApiGateway.class).toInstance(Mockito.mock(ApiGateway.class));
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/tst/com/amazonaws/service/apigateway/importer/impl/ApiGatewayRamlFileImporterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.impl;
16 |
17 | import com.amazonaws.service.apigateway.importer.RamlApiFileImporter;
18 | import com.amazonaws.service.apigateway.importer.config.RamlApiImporterTestModule;
19 | import com.amazonaws.services.apigateway.model.*;
20 | import com.amazonaws.util.json.JSONException;
21 | import com.amazonaws.util.json.JSONObject;
22 | import com.amazonaws.util.json.JSONTokener;
23 | import com.google.inject.Guice;
24 | import com.google.inject.Injector;
25 | import org.apache.log4j.BasicConfigurator;
26 | import org.junit.Before;
27 | import org.junit.Test;
28 | import org.mockito.Mock;
29 | import org.mockito.Mockito;
30 |
31 | import java.io.FileNotFoundException;
32 | import java.io.FileReader;
33 | import java.net.URISyntaxException;
34 | import java.util.Arrays;
35 |
36 | import static org.mockito.Matchers.any;
37 | import static org.mockito.Matchers.argThat;
38 | import static org.mockito.Mockito.atLeastOnce;
39 | import static org.mockito.Mockito.mock;
40 | import static org.mockito.Mockito.times;
41 | import static org.mockito.Mockito.verify;
42 | import static org.mockito.Mockito.when;
43 |
44 | public class ApiGatewayRamlFileImporterTest {
45 | private RamlApiFileImporter importer;
46 |
47 | private final String API_GATEWAY = "/raml/apigateway.raml";
48 | private final String API_GATEWAY_CONFIG = "/raml/apigateway.json";
49 |
50 | @Mock
51 | private ApiGateway client;
52 |
53 | @Mock
54 | private Resource mockResource;
55 |
56 | @Mock
57 | private Resource mockChildResource;
58 |
59 | @Mock
60 | private RestApi mockRestApi;
61 |
62 | @Before
63 | public void setUp() throws Exception {
64 | BasicConfigurator.configure();
65 |
66 | Injector injector = Guice.createInjector(new RamlApiImporterTestModule());
67 |
68 | client = injector.getInstance(ApiGateway.class);
69 | importer = injector.getInstance(RamlApiFileImporter.class);
70 |
71 | RestApis mockRestApis = mock(RestApis.class);
72 | Integration mockIntegration = Mockito.mock(Integration.class);
73 |
74 | Method mockMethod = Mockito.mock(Method.class);
75 | when(mockMethod.getHttpMethod()).thenReturn("GET");
76 | when(mockMethod.putIntegration(any())).thenReturn(mockIntegration);
77 |
78 | mockChildResource = Mockito.mock(Resource.class);
79 | when(mockChildResource.getPath()).thenReturn("/child");
80 | when(mockChildResource.putMethod(any(), any())).thenReturn(mockMethod);
81 |
82 | mockResource = Mockito.mock(Resource.class);
83 | when(mockResource.getPath()).thenReturn("/");
84 | when(mockResource.createResource(any())).thenReturn(mockChildResource);
85 | when(mockResource.putMethod(any(), any())).thenReturn(mockMethod);
86 |
87 | Resources mockResources = mock(Resources.class);
88 | when(mockResources.getItem()).thenReturn(Arrays.asList(mockResource));
89 |
90 | Model mockModel = Mockito.mock(Model.class);
91 | when(mockModel.getName()).thenReturn("test model");
92 |
93 | Models mockModels = mock(Models.class);
94 | when(mockModels.getItem()).thenReturn(Arrays.asList(mockModel));
95 |
96 | mockRestApi = mock(RestApi.class);
97 | when(mockRestApi.getResources()).thenReturn(mockResources);
98 | when(mockRestApi.getModels()).thenReturn(mockModels);
99 | when(mockRestApi.getResourceById(any())).thenReturn(mockResource);
100 |
101 | when(client.getRestApis()).thenReturn(mockRestApis);
102 | when(client.createRestApi(any())).thenReturn(mockRestApi);
103 |
104 | importer.importApi(getResourcePath(API_GATEWAY), getJsonObject(API_GATEWAY_CONFIG));
105 | }
106 |
107 | @Test
108 | public void testImport_create_api() throws Exception {
109 | verify(client, times(1)).createRestApi(any());
110 | }
111 |
112 | @Test
113 | public void testImport_create_resources() throws Exception {
114 | // to simplify mocking, all child resources are added to the root resource, and parent resources will be added multiple times
115 | // /v1, /v1/products, /v1, /v1/products, /v1/products/child
116 | verify(mockResource, atLeastOnce()).createResource(argThat(new LambdaMatcher<>(i -> i.getPathPart().equals("v1"))));
117 | verify(mockResource, atLeastOnce()).createResource(argThat(new LambdaMatcher<>(i -> i.getPathPart().equals("products"))));
118 | verify(mockResource, atLeastOnce()).createResource(argThat(new LambdaMatcher<>(i -> i.getPathPart().equals("child"))));
119 | }
120 |
121 | @Test
122 | public void testImport_create_methods() throws Exception {
123 | verify(mockChildResource, times(1)).putMethod(
124 | argThat(new LambdaMatcher<>(i -> i.getAuthorizationType().equals("AWS_IAM"))),
125 | argThat(new LambdaMatcher<>(i -> i.equals("GET"))));
126 | verify(mockChildResource, times(1)).putMethod(
127 | argThat(new LambdaMatcher<>(i -> i.getAuthorizationType().equals("NONE"))),
128 | argThat(new LambdaMatcher<>(i -> i.equals("POST"))));
129 | }
130 |
131 | @Test
132 | public void testImport_create_models() throws Exception {
133 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("Product"))));
134 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("PriceEstimate"))));
135 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("Profile"))));
136 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("Activity"))));
137 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("Activities"))));
138 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("Error"))));
139 | verify(mockRestApi, atLeastOnce()).createModel(argThat(new LambdaMatcher<>(i -> i.getName().matches("model\\w+"))));
140 | }
141 |
142 | // todo: add more tests
143 | private String getResourcePath(String path) throws URISyntaxException {
144 | return getClass().getResource(path).toURI().toString();
145 | }
146 |
147 | private JSONObject getJsonObject(String path) throws FileNotFoundException, JSONException {
148 | return new JSONObject(new JSONTokener(new FileReader(getClass().getResource(path).getFile())));
149 | }
150 |
151 | }
152 |
--------------------------------------------------------------------------------
/tst/com/amazonaws/service/apigateway/importer/impl/ApiGatewaySwaggerFileImporterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.impl;
16 |
17 | import com.amazonaws.service.apigateway.importer.SwaggerApiFileImporter;
18 | import com.amazonaws.service.apigateway.importer.config.SwaggerApiImporterTestModule;
19 | import com.amazonaws.services.apigateway.model.ApiGateway;
20 | import com.amazonaws.services.apigateway.model.Integration;
21 | import com.amazonaws.services.apigateway.model.Method;
22 | import com.amazonaws.services.apigateway.model.Model;
23 | import com.amazonaws.services.apigateway.model.Models;
24 | import com.amazonaws.services.apigateway.model.Resource;
25 | import com.amazonaws.services.apigateway.model.Resources;
26 | import com.amazonaws.services.apigateway.model.RestApi;
27 | import com.amazonaws.services.apigateway.model.RestApis;
28 | import com.google.inject.Guice;
29 | import com.google.inject.Injector;
30 | import org.apache.log4j.BasicConfigurator;
31 | import org.junit.Before;
32 | import org.junit.Test;
33 | import org.mockito.Mock;
34 | import org.mockito.Mockito;
35 |
36 | import java.net.URISyntaxException;
37 | import java.nio.file.Paths;
38 | import java.util.Arrays;
39 |
40 | import static org.mockito.Matchers.any;
41 | import static org.mockito.Matchers.argThat;
42 | import static org.mockito.Mockito.atLeastOnce;
43 | import static org.mockito.Mockito.mock;
44 | import static org.mockito.Mockito.times;
45 | import static org.mockito.Mockito.verify;
46 | import static org.mockito.Mockito.when;
47 |
48 | public class ApiGatewaySwaggerFileImporterTest {
49 | private SwaggerApiFileImporter importer;
50 |
51 | private final String API_GATEWAY = "/swagger/apigateway.json";
52 |
53 | @Mock
54 | private ApiGateway client;
55 |
56 | @Mock
57 | private Resource mockResource;
58 |
59 | @Mock
60 | private Resource mockChildResource;
61 |
62 | @Mock
63 | private RestApi mockRestApi;
64 |
65 | @Before
66 | public void setUp() throws Exception {
67 | BasicConfigurator.configure();
68 |
69 | Injector injector = Guice.createInjector(new SwaggerApiImporterTestModule());
70 |
71 | client = injector.getInstance(ApiGateway.class);
72 | importer = injector.getInstance(SwaggerApiFileImporter.class);
73 |
74 | RestApis mockRestApis = mock(RestApis.class);
75 | Integration mockIntegration = Mockito.mock(Integration.class);
76 |
77 | Method mockMethod = Mockito.mock(Method.class);
78 | when(mockMethod.getHttpMethod()).thenReturn("GET");
79 | when(mockMethod.putIntegration(any())).thenReturn(mockIntegration);
80 |
81 | mockChildResource = Mockito.mock(Resource.class);
82 | when(mockChildResource.getPath()).thenReturn("/child");
83 | when(mockChildResource.putMethod(any(), any())).thenReturn(mockMethod);
84 |
85 | mockResource = Mockito.mock(Resource.class);
86 | when(mockResource.getPath()).thenReturn("/");
87 | when(mockResource.createResource(any())).thenReturn(mockChildResource);
88 | when(mockResource.putMethod(any(), any())).thenReturn(mockMethod);
89 |
90 | Resources mockResources = mock(Resources.class);
91 | when(mockResources.getItem()).thenReturn(Arrays.asList(mockResource));
92 |
93 | Model mockModel = Mockito.mock(Model.class);
94 | when(mockModel.getName()).thenReturn("test model");
95 |
96 | Models mockModels = mock(Models.class);
97 | when(mockModels.getItem()).thenReturn(Arrays.asList(mockModel));
98 |
99 | mockRestApi = mock(RestApi.class);
100 | when(mockRestApi.getResources()).thenReturn(mockResources);
101 | when(mockRestApi.getModels()).thenReturn(mockModels);
102 | when(mockRestApi.getResourceById(any())).thenReturn(mockResource);
103 |
104 | when(client.getRestApis()).thenReturn(mockRestApis);
105 | when(client.createRestApi(any())).thenReturn(mockRestApi);
106 |
107 | importer.importApi(getResourcePath(API_GATEWAY));
108 | }
109 |
110 | @Test
111 | public void testImport_create_api() throws Exception {
112 | verify(client, times(1)).createRestApi(any());
113 | }
114 |
115 | @Test
116 | public void testImport_create_resources() throws Exception {
117 | // to simplify mocking, all child resources are added to the root resource, and parent resources will be added multiple times
118 | // /v1, /v1/products, /v1, /v1/products, /v1/products/child
119 | verify(mockResource, atLeastOnce()).createResource(argThat(new LambdaMatcher<>(i -> i.getPathPart().equals("v1"))));
120 | verify(mockResource, atLeastOnce()).createResource(argThat(new LambdaMatcher<>(i -> i.getPathPart().equals("products"))));
121 | verify(mockResource, atLeastOnce()).createResource(argThat(new LambdaMatcher<>(i -> i.getPathPart().equals("child"))));
122 | }
123 |
124 | @Test
125 | public void testImport_create_methods() throws Exception {
126 | verify(mockChildResource, times(1)).putMethod(
127 | argThat(new LambdaMatcher<>(i -> i.getAuthorizationType().equals("AWS_IAM"))),
128 | argThat(new LambdaMatcher<>(i -> i.equals("GET"))));
129 | verify(mockChildResource, times(1)).putMethod(
130 | argThat(new LambdaMatcher<>(i -> i.getAuthorizationType().equals("NONE"))),
131 | argThat(new LambdaMatcher<>(i -> i.equals("POST"))));
132 | }
133 |
134 | @Test
135 | public void testImport_create_models() throws Exception {
136 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("Product"))));
137 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("PriceEstimate"))));
138 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("Profile"))));
139 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("Activity"))));
140 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("Activities"))));
141 | verify(mockRestApi, times(1)).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("Error"))));
142 | verify(mockRestApi, atLeastOnce()).createModel(argThat(new LambdaMatcher<>(i -> i.getName().equals("Anarrayofproducts"))));
143 | }
144 |
145 | // todo: add more tests
146 | private String getResourcePath(String path) throws URISyntaxException {
147 | return Paths.get(getClass().getResource(path).toURI()).toString();
148 | }
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/tst/com/amazonaws/service/apigateway/importer/impl/LambdaMatcher.java:
--------------------------------------------------------------------------------
1 | package com.amazonaws.service.apigateway.importer.impl;
2 |
3 | import org.hamcrest.BaseMatcher;
4 | import org.hamcrest.Description;
5 |
6 | import java.util.Optional;
7 | import java.util.function.Predicate;
8 |
9 | public class LambdaMatcher extends BaseMatcher {
10 | private final Predicate matcher;
11 | private final Optional description;
12 |
13 | public LambdaMatcher(Predicate matcher) {
14 | this(matcher, null);
15 | }
16 |
17 | public LambdaMatcher(Predicate matcher, String description) {
18 | this.matcher = matcher;
19 | this.description = Optional.ofNullable(description);
20 | }
21 |
22 | @SuppressWarnings("unchecked")
23 | @Override
24 | public boolean matches(Object argument) {
25 | return matcher.test((T) argument);
26 | }
27 |
28 | @Override
29 | public void describeTo(Description description) {
30 | this.description.ifPresent(description::appendText);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/tst/com/amazonaws/service/apigateway/importer/impl/sdk/ApiGatewaySdkApiImporterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.impl.sdk;
16 |
17 | import com.amazonaws.service.apigateway.importer.config.SwaggerApiImporterTestModule;
18 | import com.google.inject.Guice;
19 | import com.google.inject.Injector;
20 | import org.apache.log4j.BasicConfigurator;
21 | import org.junit.Before;
22 | import org.junit.Test;
23 |
24 | import static org.junit.Assert.assertEquals;
25 |
26 | public class ApiGatewaySdkApiImporterTest {
27 |
28 | private ApiGatewaySdkApiImporter client;
29 |
30 | @Before
31 | public void setUp() throws Exception {
32 | BasicConfigurator.configure();
33 |
34 | Injector injector = Guice.createInjector(new SwaggerApiImporterTestModule());
35 | client = injector.getInstance(ApiGatewaySdkApiImporter.class);
36 | }
37 |
38 | @Test
39 | public void testBuildResourcePath_happy() {
40 | String basePath = "/v1";
41 | String path = "/1/2/3";
42 | assertEquals("/v1/1/2/3", client.buildResourcePath(basePath, path));
43 | }
44 |
45 | @Test
46 | public void testBuildResourcePath_baseBlank() {
47 | String basePath = "";
48 | String path = "/1/2/3";
49 | assertEquals("/1/2/3", client.buildResourcePath(basePath, path));
50 | }
51 |
52 | @Test
53 | public void testBuildResourcePath_baseSlash() {
54 | String basePath = "/";
55 | String path = "/1/2/3";
56 | assertEquals("/1/2/3", client.buildResourcePath(basePath, path));
57 | }
58 |
59 | @Test
60 | public void testBuildResourcePath_bothBlank() {
61 | String basePath = "";
62 | String path = "";
63 | assertEquals("/", client.buildResourcePath(basePath, path));
64 | }
65 |
66 | @Test
67 | public void testBuildResourcePath_baseTrailingSlash() {
68 | String basePath = "/v1/";
69 | String path = "/1/2";
70 | assertEquals("/v1/1/2", client.buildResourcePath(basePath, path));
71 | }
72 |
73 | @Test
74 | public void testBuildResourcePath_bothTrailingSlash() {
75 | String basePath = "/v1/";
76 | String path = "/1/2/";
77 | assertEquals("/v1/1/2", client.buildResourcePath(basePath, path));
78 | }
79 |
80 | @Test
81 | public void testBuildResourcePath_bothMissingSlash() {
82 | String basePath = "v1";
83 | String path = "1/2";
84 | assertEquals("/v1/1/2", client.buildResourcePath(basePath, path));
85 | }
86 |
87 | @Test
88 | public void testBuildResourcePath_pathTrailingSlash() {
89 | String basePath = "";
90 | String path = "/1/2/";
91 | assertEquals("/1/2", client.buildResourcePath(basePath, path));
92 | }
93 |
94 | @Test
95 | public void testBuildResourcePath_pathRoot() {
96 | String basePath = "/v1";
97 | String path = "/";
98 | assertEquals("/v1", client.buildResourcePath(basePath, path));
99 | }
100 |
101 | @Test
102 | public void testBuildResourcePath_nested() {
103 | String basePath = "/v1/2/3";
104 | String path = "/4/5/6";
105 | assertEquals("/v1/2/3/4/5/6", client.buildResourcePath(basePath, path));
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/tst/com/amazonaws/service/apigateway/importer/impl/sdk/ApiGatewaySdkSwaggerApiImporterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located at
7 | *
8 | * http://aws.amazon.com/apache2.0
9 | *
10 | * or in the "license" file accompanying this file. This file is distributed
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 | * express or implied. See the License for the specific language governing
13 | * permissions and limitations under the License.
14 | */
15 | package com.amazonaws.service.apigateway.importer.impl.sdk;
16 |
17 | import com.amazonaws.service.apigateway.importer.config.SwaggerApiImporterTestModule;
18 | import com.google.inject.Guice;
19 | import com.google.inject.Injector;
20 | import io.swagger.models.Response;
21 | import junit.framework.Assert;
22 | import org.apache.log4j.BasicConfigurator;
23 | import org.junit.Before;
24 | import org.junit.Test;
25 |
26 | public class ApiGatewaySdkSwaggerApiImporterTest {
27 |
28 | private ApiGatewaySdkSwaggerApiImporter client;
29 |
30 | @Before
31 | public void setUp() throws Exception {
32 | BasicConfigurator.configure();
33 |
34 | Injector injector = Guice.createInjector(new SwaggerApiImporterTestModule());
35 | client = injector.getInstance(ApiGatewaySdkSwaggerApiImporter.class);
36 | }
37 |
38 | @Test
39 | public void testGenerateModelName_description() {
40 | Response r = new Response();
41 | r.setDescription("Descriptive text will be converted to model name !@$%#^$#%");
42 | Assert.assertEquals("Wrong model name", "Descriptivetextwillbeconvertedtomodelname", client.generateModelName(r));
43 | }
44 |
45 | @Test
46 | public void testGenerateModelName_guid() {
47 | String generated = client.generateModelName(new Response());
48 | Assert.assertTrue("Wrong model name", generated.startsWith("model"));
49 | Assert.assertEquals("Wrong model name", 13, generated.length());
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/tst/com/amazonaws/service/apigateway/importer/integration/LargeApiIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.amazonaws.service.apigateway.importer.integration;
2 |
3 | import com.amazonaws.service.apigateway.importer.ApiImporterMain;
4 | import org.junit.Ignore;
5 | import org.junit.Test;
6 |
7 | import java.net.URISyntaxException;
8 | import java.nio.file.Paths;
9 |
10 | public class LargeApiIntegrationTest {
11 |
12 | @Test
13 | @Ignore // todo: integrate into CI
14 | public void test() throws URISyntaxException {
15 | ApiImporterMain main = new ApiImporterMain();
16 |
17 | String[] args = {"--create", Paths.get(getClass().getResource("/swagger/large.json").toURI()).toString()};
18 | main.main(args);
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/tst/resources/raml/apigateway.json:
--------------------------------------------------------------------------------
1 | {
2 | "/child": {
3 | "get": {
4 | "auth": {
5 | "type": "aws_iam"
6 | },
7 | "integration": {
8 | "type": "aws",
9 | "uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:ACCOUNT_ID:function:myFunction/invocations",
10 | "httpMethod": "POST",
11 | "credentials": "arn:aws:iam::ACCOUNT_ID:role/lambda_exec_role",
12 | "requestTemplates": {
13 | "application/json": "json request template 2",
14 | "application/xml": "xml request template 2"
15 | },
16 | "requestParameters": {
17 | "integration.request.path.integrationPathParam": "method.request.querystring.latitude",
18 | "integration.request.querystring.integrationQueryParam": "method.request.querystring.longitude"
19 | },
20 | "cacheNamespace": "cache namespace",
21 | "cacheKeyParameters": [],
22 | "responses": {
23 | "2\\d{2}": {
24 | "statusCode": "200",
25 | "responseParameters": {
26 | "method.response.header.test-method-response-header": "integration.response.header.integrationResponseHeaderParam1"
27 | },
28 | "responseTemplates": {
29 | "application/json": "json 200 response template",
30 | "application/xml": "xml 200 response template"
31 | }
32 | },
33 | "default": {
34 | "statusCode": "400",
35 | "responseParameters": {
36 | "method.response.header.test-method-response-header": "'static value'"
37 | },
38 | "responseTemplates": {
39 | "application/json": "json 400 response template",
40 | "application/xml": "xml 400 response template"
41 | }
42 | }
43 | }
44 | }
45 | },
46 | "post": {
47 | "auth": {
48 | "type": "none"
49 | },
50 | "integration": {
51 | "type": "http",
52 | "uri": "https://api.github.com",
53 | "httpMethod": "GET",
54 | "responses": {
55 | "2//d{2}": {
56 | "statusCode": "200"
57 | },
58 | "default": {
59 | "statusCode": "400",
60 | "responseParameters": {
61 | "method.response.header.test-method-response-header": "'static value'"
62 | },
63 | "responseTemplates": {
64 | "application/json": "json 400 response template",
65 | "application/xml": "xml 400 response template"
66 | }
67 | }
68 | }
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/tst/resources/raml/apigateway.raml:
--------------------------------------------------------------------------------
1 | #%RAML 0.8
2 |
3 | title: API Gateway Test API
4 | version: 1.0.0
5 |
6 | documentation:
7 | - title: About
8 | content: Move your app forward with the Uber API
9 |
10 | baseUri: https://api.uber.com/v1
11 |
12 | mediaType: application/json
13 |
14 | schemas:
15 | - Product: |
16 | {
17 | "properties": {
18 | "product_id": {
19 | "type": "string",
20 | "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."
21 | },
22 | "description": {
23 | "type": "string",
24 | "description": "Description of product."
25 | },
26 | "display_name": {
27 | "type": "string",
28 | "description": "Display name of product."
29 | },
30 | "capacity": {
31 | "type": "string",
32 | "description": "Capacity of product. For example, 4 people."
33 | },
34 | "image": {
35 | "type": "string",
36 | "description": "Image URL representing the product."
37 | }
38 | }
39 | }
40 | - PriceEstimate: |
41 | {
42 | "properties": {
43 | "product_id": {
44 | "type": "string",
45 | "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"
46 | },
47 | "currency_code": {
48 | "type": "string",
49 | "description": "[ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code."
50 | },
51 | "display_name": {
52 | "type": "string",
53 | "description": "Display name of product."
54 | },
55 | "estimate": {
56 | "type": "string",
57 | "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."
58 | },
59 | "low_estimate": {
60 | "type": "number",
61 | "description": "Lower bound of the estimated price."
62 | },
63 | "high_estimate": {
64 | "type": "number",
65 | "description": "Upper bound of the estimated price."
66 | },
67 | "surge_multiplier": {
68 | "type": "number",
69 | "description": "Expected surge multiplier. Surge is active if surge_multiplier is greater than 1. Price estimate already factors in the surge multiplier."
70 | }
71 | }
72 | }
73 | - Profile: |
74 | {
75 | "properties": {
76 | "first_name": {
77 | "type": "string",
78 | "description": "First name of the Uber user."
79 | },
80 | "last_name": {
81 | "type": "string",
82 | "description": "Last name of the Uber user."
83 | },
84 | "email": {
85 | "type": "string",
86 | "description": "Email address of the Uber user"
87 | },
88 | "picture": {
89 | "type": "string",
90 | "description": "Image URL of the Uber user."
91 | },
92 | "promo_code": {
93 | "type": "string",
94 | "description": "Promo code of the Uber user."
95 | }
96 | }
97 | }
98 | - Activity: |
99 | {
100 | "properties": {
101 | "uuid": {
102 | "type": "string",
103 | "description": "Unique identifier for the activity"
104 | }
105 | }
106 | }
107 | - Activities: |
108 | {
109 | "properties": {
110 | "offset": {
111 | "type": "integer",
112 | "format": "int32",
113 | "description": "Position in pagination."
114 | },
115 | "limit": {
116 | "type": "integer",
117 | "format": "int32",
118 | "description": "Number of items to retrieve (100 max)."
119 | },
120 | "count": {
121 | "type": "integer",
122 | "format": "int32",
123 | "description": "Total number of items available."
124 | },
125 | "history": {
126 | "type": "array",
127 | "items": {
128 | "properties": {
129 | "uuid": {
130 | "type": "string",
131 | "description": "Unique identifier for the activity"
132 | }
133 | }
134 | }
135 | }
136 | }
137 | }
138 | - Error: |
139 | {
140 | "properties": {
141 | "code": {
142 | "type": "integer",
143 | "format": "int32"
144 | },
145 | "message": {
146 | "type": "string"
147 | },
148 | "fields": {
149 | "type": "string"
150 | }
151 | }
152 | }
153 |
154 | /products:
155 | get:
156 | description: |
157 | The Products endpoint returns information about the *Uber* products
158 | offered at a given location. The response includes the display name
159 | and other details about each product, and lists the products in the
160 | proper display order.
161 | queryParameters:
162 | latitude:
163 | description: Latitude component of location.
164 | type: number
165 | required: true
166 | longitude:
167 | description: Longitude component of location.
168 | type: number
169 | required: true
170 | responses:
171 | 200:
172 | description: An array of products
173 | body:
174 | schema: |
175 | {
176 | "type": "array",
177 | "items": {
178 | "properties": {
179 | "product_id": {
180 | "type": "string",
181 | "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."
182 | },
183 | "description": {
184 | "type": "string",
185 | "description": "Description of product."
186 | },
187 | "display_name": {
188 | "type": "string",
189 | "description": "Display name of product."
190 | },
191 | "capacity": {
192 | "type": "string",
193 | "description": "Capacity of product. For example, 4 people."
194 | },
195 | "image": {
196 | "type": "string",
197 | "description": "Image URL representing the product."
198 | }
199 | }
200 | }
201 | }
202 | headers:
203 | test-method-response-header:
204 | type: string
205 | 400:
206 | description: Bad Request
207 | body:
208 | schema: Error
209 | /child:
210 | post:
211 | description: |
212 | The Products endpoint returns information about the *Uber* products
213 | offered at a given location. The response includes the display name
214 | and other details about each product, and lists the products in the
215 | proper display order.
216 | queryParameters:
217 | latitude:
218 | description: Latitude component of location.
219 | type: number
220 | required: true
221 | longitude:
222 | description: Longitude component of location.
223 | type: number
224 | required: true
225 | responses:
226 | 200:
227 | description: An array of products
228 | body:
229 | schema: |
230 | {
231 | "type": "array",
232 | "items": {
233 | "properties": {
234 | "product_id": {
235 | "type": "string",
236 | "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."
237 | },
238 | "description": {
239 | "type": "string",
240 | "description": "Description of product."
241 | },
242 | "display_name": {
243 | "type": "string",
244 | "description": "Display name of product."
245 | },
246 | "capacity": {
247 | "type": "string",
248 | "description": "Capacity of product. For example, 4 people."
249 | },
250 | "image": {
251 | "type": "string",
252 | "description": "Image URL representing the product."
253 | }
254 | }
255 | }
256 | }
257 | headers:
258 | test-method-response-header:
259 | type: string
260 | 400:
261 | description: Bad Request
262 | body:
263 | schema: Error
264 |
--------------------------------------------------------------------------------
/tst/resources/raml/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "/{version}/endpoint": {
3 | "get": {
4 | "auth" : {
5 | "type" : "aws_iam"
6 | },
7 | "integration" : {
8 | "type" : "aws",
9 | "uri" : "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:MY_ACCT_ID:function:helloWorld/invocations",
10 | "httpMethod" : "POST",
11 | "credentials" : "arn:aws:iam::MY_ACCT_ID:role/lambda_exec_role",
12 | "requestTemplates" : {
13 | "application/json" : "json request template 2",
14 | "application/xml" : "xml request template 2"
15 | },
16 | "requestParameters" : {
17 | "integration.request.path.integrationPathParam" : "method.request.querystring.latitude",
18 | "integration.request.querystring.integrationQueryParam" : "method.request.querystring.longitude"
19 | },
20 | "cacheNamespace" : "cache-namespace",
21 | "cacheKeyParameters" : [],
22 | "responses" : {
23 | "2\\d{2}" : {
24 | "statusCode" : "200",
25 | "responseParameters" : {
26 | "method.response.header.test-method-response-header" : "integration.response.header.integrationResponseHeaderParam1"
27 | },
28 | "responseTemplates" : {
29 | "application/json" : "json 200 response template",
30 | "application/xml" : "xml 200 response template"
31 | }
32 | },
33 | "default" : {
34 | "statusCode" : "400",
35 | "responseParameters" : {
36 | "method.response.header.test-method-response-header" : "'static value'"
37 | },
38 | "responseTemplates" : {
39 | "application/json" : "json 400 response template",
40 | "application/xml" : "xml 400 response template"
41 | }
42 | }
43 | }
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tst/resources/raml/example.raml:
--------------------------------------------------------------------------------
1 | #%RAML 0.8
2 |
3 | title: Example API
4 |
5 | baseUri: http://example.com/{version}
6 |
7 | schemas:
8 | - endpointJson: >
9 | {
10 | "type": "string"
11 | }
12 |
13 | mediaType: application/json
14 |
15 | /endpoint:
16 | get:
17 | body:
18 | schema: endpointJson
19 | post:
20 | body:
21 |
--------------------------------------------------------------------------------
/tst/resources/swagger/apigateway.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "title": "API Gateway Test API",
5 | "description": "Move your app forward with the Uber API",
6 | "version": "1.0.0"
7 | },
8 | "host": "api.uber.com",
9 | "schemes": [
10 | "https"
11 | ],
12 | "basePath": "/v1",
13 | "produces": [
14 | "application/json"
15 | ],
16 | "security" : [{
17 | "api_key" : []
18 | }],
19 | "securityDefinitions" : {
20 | "api_key": {
21 | "type": "apiKey",
22 | "name": "x-api-key",
23 | "in": "header"
24 | }
25 | },
26 | "paths": {
27 | "/products": {
28 | "get": {
29 | "summary": "Product Types",
30 | "description": "The Products endpoint returns information about the *Uber* products\noffered at a given location. The response includes the display name\nand other details about each product, and lists the products in the\nproper display order.\n",
31 | "parameters": [
32 | {
33 | "name": "latitude",
34 | "in": "query",
35 | "description": "Latitude component of location.",
36 | "required": true,
37 | "type": "number",
38 | "format": "double"
39 | },
40 | {
41 | "name": "longitude",
42 | "in": "query",
43 | "description": "Longitude component of location.",
44 | "required": true,
45 | "type": "number",
46 | "format": "double"
47 | }
48 | ],
49 | "tags": [
50 | "Products"
51 | ],
52 | "responses": {
53 | "200": {
54 | "description": "An array of products",
55 | "schema": {
56 | "type": "array",
57 | "items": {
58 | "$ref": "#/definitions/Product"
59 | }
60 | },
61 | "headers" : {
62 | "test-method-response-header" : {
63 | "type" : "string"
64 | }
65 | }
66 | },
67 | "400": {
68 | "description": "Bad request",
69 | "schema": {
70 | "$ref": "#/definitions/Error"
71 | }
72 | },
73 | "default": {
74 | "description": "Unexpected error",
75 | "schema": {
76 | "$ref": "#/definitions/Error"
77 | }
78 | }
79 | },
80 | "security" : [{
81 | "api_key" : []
82 | }],
83 | "x-amazon-apigateway-auth" : {
84 | "type" : "aws_iam"
85 | },
86 | "x-amazon-apigateway-integration" : {
87 | "type" : "aws",
88 | "uri" : "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:ACCOUNT_ID:function:myFunction/invocations",
89 | "httpMethod" : "POST",
90 | "credentials" : "arn:aws:iam::ACCOUNT_ID:role/lambda_exec_role",
91 | "requestTemplates" : {
92 | "application/json" : "json request template 2",
93 | "application/xml" : "xml request template 2"
94 | },
95 | "requestParameters" : {
96 | "integration.request.path.integrationPathParam" : "method.request.querystring.latitude",
97 | "integration.request.querystring.integrationQueryParam" : "method.request.querystring.longitude"
98 | },
99 | "cacheNamespace" : "cache namespace",
100 | "cacheKeyParameters" : [],
101 | "responses" : {
102 | "2\\d{2}" : {
103 | "statusCode" : "200",
104 | "responseParameters" : {
105 | "method.response.header.test-method-response-header" : "integration.response.header.integrationResponseHeaderParam1"
106 | },
107 | "responseTemplates" : {
108 | "application/json" : "json 200 response template",
109 | "application/xml" : "xml 200 response template"
110 | }
111 | },
112 | "default" : {
113 | "statusCode" : "400",
114 | "responseParameters" : {
115 | "method.response.header.test-method-response-header" : "'static value'"
116 | },
117 | "responseTemplates" : {
118 | "application/json" : "json 400 response template",
119 | "application/xml" : "xml 400 response template"
120 | }
121 | }
122 | }
123 | }
124 | }
125 | },
126 | "/products/child": {
127 | "post": {
128 | "summary": "Product Types",
129 | "description": "The Products endpoint returns information about the *Uber* products\noffered at a given location. The response includes the display name\nand other details about each product, and lists the products in the\nproper display order.\n",
130 | "parameters": [
131 | {
132 | "name": "latitude",
133 | "in": "query",
134 | "description": "Latitude component of location.",
135 | "required": true,
136 | "type": "number",
137 | "format": "double"
138 | },
139 | {
140 | "name": "longitude",
141 | "in": "query",
142 | "description": "Longitude component of location.",
143 | "required": true,
144 | "type": "number",
145 | "format": "double"
146 | }
147 | ],
148 | "tags": [
149 | "Products"
150 | ],
151 | "responses": {
152 | "200": {
153 | "description": "An array of products",
154 | "schema": {
155 | "type": "array",
156 | "items": {
157 | "$ref": "#/definitions/Product"
158 | }
159 | },
160 | "headers" : {
161 | "test-method-response-header" : {
162 | "type" : "string"
163 | }
164 | }
165 | },
166 | "400": {
167 | "description": "Bad request",
168 | "schema": {
169 | "$ref": "#/definitions/Error"
170 | }
171 | },
172 | "default": {
173 | "description": "Unexpected error",
174 | "schema": {
175 | "$ref": "#/definitions/Error"
176 | }
177 | }
178 | },
179 | "security" : [{
180 | "api_key" : []
181 | }],
182 | "x-amazon-apigateway-auth" : {
183 | "type" : "none"
184 | },
185 | "x-amazon-apigateway-integration" : {
186 | "type" : "http",
187 | "uri" : "https://api.github.com",
188 | "httpMethod" : "GET",
189 | "responses" : {
190 | "2\\d{2}" : {
191 | "statusCode" : "200"
192 | },
193 | "default" : {
194 | "statusCode" : "400",
195 | "responseParameters" : {
196 | "method.response.header.test-method-response-header" : "'static value'"
197 | },
198 | "responseTemplates" : {
199 | "application/json" : "json 400 response template",
200 | "application/xml" : "xml 400 response template"
201 | }
202 | }
203 | }
204 | }
205 | }
206 | }
207 | },
208 | "definitions": {
209 | "Product": {
210 | "properties": {
211 | "product_id": {
212 | "type": "string",
213 | "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."
214 | },
215 | "description": {
216 | "type": "string",
217 | "description": "Description of product."
218 | },
219 | "display_name": {
220 | "type": "string",
221 | "description": "Display name of product."
222 | },
223 | "capacity": {
224 | "type": "string",
225 | "description": "Capacity of product. For example, 4 people."
226 | },
227 | "image": {
228 | "type": "string",
229 | "description": "Image URL representing the product."
230 | }
231 | }
232 | },
233 | "PriceEstimate": {
234 | "properties": {
235 | "product_id": {
236 | "type": "string",
237 | "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"
238 | },
239 | "currency_code": {
240 | "type": "string",
241 | "description": "[ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code."
242 | },
243 | "display_name": {
244 | "type": "string",
245 | "description": "Display name of product."
246 | },
247 | "estimate": {
248 | "type": "string",
249 | "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."
250 | },
251 | "low_estimate": {
252 | "type": "number",
253 | "description": "Lower bound of the estimated price."
254 | },
255 | "high_estimate": {
256 | "type": "number",
257 | "description": "Upper bound of the estimated price."
258 | },
259 | "surge_multiplier": {
260 | "type": "number",
261 | "description": "Expected surge multiplier. Surge is active if surge_multiplier is greater than 1. Price estimate already factors in the surge multiplier."
262 | }
263 | }
264 | },
265 | "Profile": {
266 | "properties": {
267 | "first_name": {
268 | "type": "string",
269 | "description": "First name of the Uber user."
270 | },
271 | "last_name": {
272 | "type": "string",
273 | "description": "Last name of the Uber user."
274 | },
275 | "email": {
276 | "type": "string",
277 | "description": "Email address of the Uber user"
278 | },
279 | "picture": {
280 | "type": "string",
281 | "description": "Image URL of the Uber user."
282 | },
283 | "promo_code": {
284 | "type": "string",
285 | "description": "Promo code of the Uber user."
286 | }
287 | }
288 | },
289 | "Activity": {
290 | "properties": {
291 | "uuid": {
292 | "type": "string",
293 | "description": "Unique identifier for the activity"
294 | }
295 | }
296 | },
297 | "Activities": {
298 | "properties": {
299 | "offset": {
300 | "type": "integer",
301 | "format": "int32",
302 | "description": "Position in pagination."
303 | },
304 | "limit": {
305 | "type": "integer",
306 | "format": "int32",
307 | "description": "Number of items to retrieve (100 max)."
308 | },
309 | "count": {
310 | "type": "integer",
311 | "format": "int32",
312 | "description": "Total number of items available."
313 | },
314 | "history": {
315 | "type": "array",
316 | "items": {
317 | "$ref": "#/definitions/Activity"
318 | }
319 | }
320 | }
321 | },
322 | "Error": {
323 | "properties": {
324 | "code": {
325 | "type": "integer",
326 | "format": "int32"
327 | },
328 | "message": {
329 | "type": "string"
330 | },
331 | "fields": {
332 | "type": "string"
333 | }
334 | }
335 | }
336 | }
337 | }
338 |
--------------------------------------------------------------------------------
/tst/resources/swagger/basic.json:
--------------------------------------------------------------------------------
1 | {
2 | "apiVersion": "",
3 | "apis": [
4 |
5 | ],
6 | "basePath": "http://192.168.1.1:8000",
7 | "models": {
8 |
9 | },
10 | "resourcePath": "/api",
11 | "swaggerVersion": "1.2"
12 | }
--------------------------------------------------------------------------------
/tst/resources/swagger/large.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "title": "Uber API v2",
5 | "description": "Move your app forward with the Uber API",
6 | "version": "1.0.0"
7 | },
8 | "host": "api.uber.com",
9 | "schemes": [
10 | "https"
11 | ],
12 | "basePath": "/v1",
13 | "produces": [
14 | "application/json"
15 | ],
16 | "paths": {
17 | "/" : {
18 | "get": {
19 | }
20 | },
21 | "/level1" : {
22 | "get": {
23 | }
24 | },
25 | "/level1/level2" : {
26 | "get": {
27 | }
28 | },
29 | "/level1/level2/level3" : {
30 | "post": {
31 | }
32 | },
33 | "/1" : {"get": {}},
34 | "/2" : {"get": {}},
35 | "/3" : {"get": {}},
36 | "/4" : {"get": {}},
37 | "/5" : {"get": {}},
38 | "/6" : {"get": {}},
39 | "/7" : {"get": {}},
40 | "/8" : {"get": {}},
41 | "/9" : {"get": {}},
42 | "/10" : {"get": {}},
43 | "/11" : {"get": {}},
44 | "/12" : {"get": {}},
45 | "/13" : {"get": {}},
46 | "/14" : {"get": {}},
47 | "/15" : {"get": {}},
48 | "/16" : {"get": {}},
49 | "/17" : {"get": {}},
50 | "/18" : {"get": {}},
51 | "/19" : {"get": {}},
52 | "/20" : {"get": {}},
53 | "/21" : {"get": {}},
54 | "/22" : {"get": {}},
55 | "/23" : {"get": {}},
56 | "/24" : {"get": {}},
57 | "/25" : {"get": {}},
58 | "/26" : {"get": {}},
59 | "/27" : {"get": {}},
60 | "/28" : {"get": {}},
61 | "/29" : {"get": {}},
62 | "/30" : {"get": {}},
63 | "/31" : {"get": {}},
64 | "/33" : {"get": {}},
65 | "/34" : {"get": {}},
66 | "/35" : {"get": {}},
67 | "/36" : {"get": {}},
68 | "/37" : {"get": {}},
69 | "/38" : {"get": {}},
70 | "/39" : {"get": {}},
71 | "/40" : {"get": {}},
72 | "/41" : {"get": {}},
73 | "/42" : {"get": {}},
74 | "/43" : {"get": {}},
75 | "/44" : {"get": {}},
76 | "/45" : {"get": {}},
77 | "/46" : {"get": {}},
78 | "/47" : {"get": {}},
79 | "/48" : {"get": {}},
80 | "/49" : {"get": {}},
81 | "/50" : {"get": {}},
82 | "/51" : {"get": {}},
83 | "/52" : {"get": {}},
84 | "/53" : {"get": {}},
85 | "/54" : {"get": {}},
86 | "/55" : {"get": {}},
87 | "/56" : {"get": {}},
88 | "/57" : {"get": {}},
89 | "/58" : {"get": {}},
90 | "/59" : {"get": {}}
91 |
92 | },
93 | "definitions": {
94 | "Product": {
95 | "properties": {
96 | "product_id": {
97 | "type": "string",
98 | "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."
99 | },
100 | "description": {
101 | "type": "string",
102 | "description": "Description of product."
103 | },
104 | "display_name": {
105 | "type": "string",
106 | "description": "Display name of product."
107 | },
108 | "capacity": {
109 | "type": "string",
110 | "description": "Capacity of product. For example, 4 people."
111 | },
112 | "image": {
113 | "type": "string",
114 | "description": "Image URL representing the product."
115 | }
116 | }
117 | },
118 | "PriceEstimate": {
119 | "properties": {
120 | "product_id": {
121 | "type": "string",
122 | "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"
123 | },
124 | "currency_code": {
125 | "type": "string",
126 | "description": "[ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code."
127 | },
128 | "display_name": {
129 | "type": "string",
130 | "description": "Display name of product."
131 | },
132 | "estimate": {
133 | "type": "string",
134 | "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."
135 | },
136 | "low_estimate": {
137 | "type": "number",
138 | "description": "Lower bound of the estimated price."
139 | },
140 | "high_estimate": {
141 | "type": "number",
142 | "description": "Upper bound of the estimated price."
143 | },
144 | "surge_multiplier": {
145 | "type": "number",
146 | "description": "Expected surge multiplier. Surge is active if surge_multiplier is greater than 1. Price estimate already factors in the surge multiplier."
147 | }
148 | }
149 | },
150 | "Profile": {
151 | "properties": {
152 | "first_name": {
153 | "type": "string",
154 | "description": "First name of the Uber user."
155 | },
156 | "last_name": {
157 | "type": "string",
158 | "description": "Last name of the Uber user."
159 | },
160 | "email": {
161 | "type": "string",
162 | "description": "Email address of the Uber user"
163 | },
164 | "picture": {
165 | "type": "string",
166 | "description": "Image URL of the Uber user."
167 | },
168 | "promo_code": {
169 | "type": "string",
170 | "description": "Promo code of the Uber user."
171 | }
172 | }
173 | },
174 | "Activity": {"properties": {"uuid": {"type": "string"}}},
175 | "Activity1": {"properties": {"uuid": {"type": "string"}}},
176 | "Activity2": {"properties": {"uuid": {"type": "string"}}},
177 | "Activity3": {"properties": {"uuid": {"type": "string"}}},
178 | "Activity4": {"properties": {"uuid": {"type": "string"}}},
179 | "Activity5": {"properties": {"uuid": {"type": "string"}}},
180 | "Activity6": {"properties": {"uuid": {"type": "string"}}},
181 | "Activity7": {"properties": {"uuid": {"type": "string"}}},
182 | "Activity8": {"properties": {"uuid": {"type": "string"}}},
183 | "Activity9": {"properties": {"uuid": {"type": "string"}}},
184 | "Activity10": {"properties": {"uuid": {"type": "string"}}},
185 | "Activity11": {"properties": {"uuid": {"type": "string"}}},
186 | "Activity12": {"properties": {"uuid": {"type": "string"}}},
187 | "Activity13": {"properties": {"uuid": {"type": "string"}}},
188 | "Activity14": {"properties": {"uuid": {"type": "string"}}},
189 | "Activity15": {"properties": {"uuid": {"type": "string"}}},
190 | "Activity16": {"properties": {"uuid": {"type": "string"}}},
191 | "Activity17": {"properties": {"uuid": {"type": "string"}}},
192 | "Activity18": {"properties": {"uuid": {"type": "string"}}},
193 | "Activity19": {"properties": {"uuid": {"type": "string"}}},
194 | "Activity20": {"properties": {"uuid": {"type": "string"}}},
195 | "Activity21": {"properties": {"uuid": {"type": "string"}}},
196 | "Activity22": {"properties": {"uuid": {"type": "string"}}},
197 | "Activity23": {"properties": {"uuid": {"type": "string"}}},
198 | "Activity24": {"properties": {"uuid": {"type": "string"}}},
199 | "Activity25": {"properties": {"uuid": {"type": "string"}}},
200 | "Activity26": {"properties": {"uuid": {"type": "string"}}},
201 | "Activity27": {"properties": {"uuid": {"type": "string"}}},
202 | "Activity28": {"properties": {"uuid": {"type": "string"}}},
203 | "Activity29": {"properties": {"uuid": {"type": "string"}}},
204 | "Activities": {
205 | "properties": {
206 | "offset": {
207 | "type": "integer",
208 | "format": "int32",
209 | "description": "Position in pagination."
210 | },
211 | "limit": {
212 | "type": "integer",
213 | "format": "int32",
214 | "description": "Number of items to retrieve (100 max)."
215 | },
216 | "count": {
217 | "type": "integer",
218 | "format": "int32",
219 | "description": "Total number of items available."
220 | },
221 | "history": {
222 | "type": "array",
223 | "items": {
224 | "$ref": "#/definitions/Activity"
225 | }
226 | }
227 | }
228 | }
229 | }
230 | }
--------------------------------------------------------------------------------
/tst/resources/swagger/petstore-expanded.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "version": "1.0.0",
5 | "title": "Swagger Petstore",
6 | "description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
7 | "termsOfService": "http://swagger.io/terms/",
8 | "contact": {
9 | "name": "Swagger API Team",
10 | "email": "foo@example.com",
11 | "url": "http://madskristensen.net"
12 | },
13 | "license": {
14 | "name": "MIT",
15 | "url": "http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT"
16 | }
17 | },
18 | "host": "petstore.swagger.io",
19 | "basePath": "/api",
20 | "schemes": [
21 | "http"
22 | ],
23 | "consumes": [
24 | "application/json"
25 | ],
26 | "produces": [
27 | "application/json"
28 | ],
29 | "paths": {
30 | "/pets": {
31 | "get": {
32 | "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",
33 | "operationId": "findPets",
34 | "parameters": [
35 | {
36 | "name": "tags",
37 | "in": "query",
38 | "description": "tags to filter by",
39 | "required": false,
40 | "type": "array",
41 | "collectionFormat": "csv",
42 | "items": {
43 | "type": "string"
44 | }
45 | },
46 | {
47 | "name": "limit",
48 | "in": "query",
49 | "description": "maximum number of results to return",
50 | "required": false,
51 | "type": "integer",
52 | "format": "int32"
53 | }
54 | ],
55 | "responses": {
56 | "200": {
57 | "description": "pet response",
58 | "schema": {
59 | "type": "array",
60 | "items": {
61 | "$ref": "#/definitions/Pet"
62 | }
63 | }
64 | },
65 | "default": {
66 | "description": "unexpected error",
67 | "schema": {
68 | "$ref": "#/definitions/Error"
69 | }
70 | }
71 | }
72 | },
73 | "post": {
74 | "description": "Creates a new pet in the store. Duplicates are allowed",
75 | "operationId": "addPet",
76 | "parameters": [
77 | {
78 | "name": "pet",
79 | "in": "body",
80 | "description": "Pet to add to the store",
81 | "required": true,
82 | "schema": {
83 | "$ref": "#/definitions/NewPet"
84 | }
85 | }
86 | ],
87 | "responses": {
88 | "200": {
89 | "description": "pet response",
90 | "schema": {
91 | "$ref": "#/definitions/Pet"
92 | }
93 | },
94 | "default": {
95 | "description": "unexpected error",
96 | "schema": {
97 | "$ref": "#/definitions/Error"
98 | }
99 | }
100 | }
101 | }
102 | },
103 | "/pets/{id}": {
104 | "get": {
105 | "description": "Returns a user based on a single ID, if the user does not have access to the pet",
106 | "operationId": "find pet by id",
107 | "parameters": [
108 | {
109 | "name": "id",
110 | "in": "path",
111 | "description": "ID of pet to fetch",
112 | "required": true,
113 | "type": "integer",
114 | "format": "int64"
115 | }
116 | ],
117 | "responses": {
118 | "200": {
119 | "description": "pet response",
120 | "schema": {
121 | "$ref": "#/definitions/Pet"
122 | }
123 | },
124 | "default": {
125 | "description": "unexpected error",
126 | "schema": {
127 | "$ref": "#/definitions/Error"
128 | }
129 | }
130 | }
131 | },
132 | "delete": {
133 | "description": "deletes a single pet based on the ID supplied",
134 | "operationId": "deletePet",
135 | "parameters": [
136 | {
137 | "name": "id",
138 | "in": "path",
139 | "description": "ID of pet to delete",
140 | "required": true,
141 | "type": "integer",
142 | "format": "int64"
143 | }
144 | ],
145 | "responses": {
146 | "204": {
147 | "description": "pet deleted"
148 | },
149 | "default": {
150 | "description": "unexpected error",
151 | "schema": {
152 | "$ref": "#/definitions/Error"
153 | }
154 | }
155 | }
156 | }
157 | }
158 | },
159 | "definitions": {
160 | "Pet": {
161 | "type": "object",
162 | "allOf": [
163 | {
164 | "$ref": "#/definitions/NewPet"
165 | },
166 | {
167 | "required": [
168 | "id"
169 | ],
170 | "properties": {
171 | "id": {
172 | "type": "integer",
173 | "format": "int64"
174 | }
175 | }
176 | }
177 | ]
178 | },
179 | "NewPet": {
180 | "type": "object",
181 | "required": [
182 | "name"
183 | ],
184 | "properties": {
185 | "name": {
186 | "type": "string"
187 | },
188 | "tag": {
189 | "type": "string"
190 | }
191 | }
192 | },
193 | "Error": {
194 | "type": "object",
195 | "required": [
196 | "code",
197 | "message"
198 | ],
199 | "properties": {
200 | "code": {
201 | "type": "integer",
202 | "format": "int32"
203 | },
204 | "message": {
205 | "type": "string"
206 | }
207 | }
208 | }
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/tst/resources/swagger/petstore-minimal.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "version": "1.0.0",
5 | "title": "Swagger Petstore",
6 | "description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
7 | "termsOfService": "http://swagger.io/terms/",
8 | "contact": {
9 | "name": "Swagger API Team"
10 | },
11 | "license": {
12 | "name": "MIT"
13 | }
14 | },
15 | "host": "petstore.swagger.io",
16 | "basePath": "/api",
17 | "schemes": [
18 | "http"
19 | ],
20 | "consumes": [
21 | "application/json"
22 | ],
23 | "produces": [
24 | "application/json"
25 | ],
26 | "paths": {
27 | "/pets": {
28 | "get": {
29 | "description": "Returns all pets from the system that the user has access to",
30 | "produces": [
31 | "application/json"
32 | ],
33 | "responses": {
34 | "200": {
35 | "description": "A list of pets.",
36 | "schema": {
37 | "type": "array",
38 | "items": {
39 | "$ref": "#/definitions/Pet"
40 | }
41 | }
42 | }
43 | }
44 | }
45 | }
46 | },
47 | "definitions": {
48 | "Pet": {
49 | "type": "object",
50 | "required": [
51 | "id",
52 | "name"
53 | ],
54 | "properties": {
55 | "id": {
56 | "type": "integer",
57 | "format": "int64"
58 | },
59 | "name": {
60 | "type": "string"
61 | },
62 | "tag": {
63 | "type": "string"
64 | }
65 | }
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/tst/resources/swagger/petstore-simple.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "version": "1.0.0",
5 | "title": "Swagger Petstore",
6 | "description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
7 | "termsOfService": "http://swagger.io/terms/",
8 | "contact": {
9 | "name": "Swagger API Team"
10 | },
11 | "license": {
12 | "name": "MIT"
13 | }
14 | },
15 | "host": "petstore.swagger.io",
16 | "basePath": "/api",
17 | "schemes": [
18 | "http"
19 | ],
20 | "consumes": [
21 | "application/json"
22 | ],
23 | "produces": [
24 | "application/json"
25 | ],
26 | "paths": {
27 | "/pets": {
28 | "get": {
29 | "description": "Returns all pets from the system that the user has access to",
30 | "operationId": "findPets",
31 | "produces": [
32 | "application/json",
33 | "application/xml",
34 | "text/xml",
35 | "text/html"
36 | ],
37 | "parameters": [
38 | {
39 | "name": "tags",
40 | "in": "query",
41 | "description": "tags to filter by",
42 | "required": false,
43 | "type": "array",
44 | "items": {
45 | "type": "string"
46 | },
47 | "collectionFormat": "csv"
48 | },
49 | {
50 | "name": "limit",
51 | "in": "query",
52 | "description": "maximum number of results to return",
53 | "required": false,
54 | "type": "integer",
55 | "format": "int32"
56 | }
57 | ],
58 | "responses": {
59 | "200": {
60 | "description": "pet response",
61 | "schema": {
62 | "type": "array",
63 | "items": {
64 | "$ref": "#/definitions/Pet"
65 | }
66 | }
67 | },
68 | "default": {
69 | "description": "unexpected error",
70 | "schema": {
71 | "$ref": "#/definitions/ErrorModel"
72 | }
73 | }
74 | }
75 | },
76 | "post": {
77 | "description": "Creates a new pet in the store. Duplicates are allowed",
78 | "operationId": "addPet",
79 | "produces": [
80 | "application/json"
81 | ],
82 | "parameters": [
83 | {
84 | "name": "pet",
85 | "in": "body",
86 | "description": "Pet to add to the store",
87 | "required": true,
88 | "schema": {
89 | "$ref": "#/definitions/PetInput"
90 | }
91 | }
92 | ],
93 | "responses": {
94 | "200": {
95 | "description": "pet response",
96 | "schema": {
97 | "$ref": "#/definitions/Pet"
98 | }
99 | },
100 | "default": {
101 | "description": "unexpected error",
102 | "schema": {
103 | "$ref": "#/definitions/ErrorModel"
104 | }
105 | }
106 | }
107 | }
108 | },
109 | "/pets/{id}": {
110 | "get": {
111 | "description": "Returns a user based on a single ID, if the user does not have access to the pet",
112 | "operationId": "findPetById",
113 | "produces": [
114 | "application/json",
115 | "application/xml",
116 | "text/xml",
117 | "text/html"
118 | ],
119 | "parameters": [
120 | {
121 | "name": "id",
122 | "in": "path",
123 | "description": "ID of pet to fetch",
124 | "required": true,
125 | "type": "integer",
126 | "format": "int64"
127 | }
128 | ],
129 | "responses": {
130 | "200": {
131 | "description": "pet response",
132 | "schema": {
133 | "$ref": "#/definitions/Pet"
134 | }
135 | },
136 | "default": {
137 | "description": "unexpected error",
138 | "schema": {
139 | "$ref": "#/definitions/ErrorModel"
140 | }
141 | }
142 | }
143 | },
144 | "delete": {
145 | "description": "deletes a single pet based on the ID supplied",
146 | "operationId": "deletePet",
147 | "parameters": [
148 | {
149 | "name": "id",
150 | "in": "path",
151 | "description": "ID of pet to delete",
152 | "required": true,
153 | "type": "integer",
154 | "format": "int64"
155 | }
156 | ],
157 | "responses": {
158 | "204": {
159 | "description": "pet deleted"
160 | },
161 | "default": {
162 | "description": "unexpected error",
163 | "schema": {
164 | "$ref": "#/definitions/ErrorModel"
165 | }
166 | }
167 | }
168 | }
169 | }
170 | },
171 | "definitions": {
172 | "Pet": {
173 | "type": "object",
174 | "required": [
175 | "id",
176 | "name"
177 | ],
178 | "properties": {
179 | "id": {
180 | "type": "integer",
181 | "format": "int64"
182 | },
183 | "name": {
184 | "type": "string"
185 | },
186 | "tag": {
187 | "type": "string"
188 | }
189 | }
190 | },
191 | "PetInput": {
192 | "type": "object",
193 | "allOf": [
194 | {
195 | "$ref": "#/definitions/Pet"
196 | },
197 | {
198 | "required": [
199 | "name"
200 | ],
201 | "properties": {
202 | "id": {
203 | "type": "integer",
204 | "format": "int64"
205 | }
206 | }
207 | }
208 | ]
209 | },
210 | "ErrorModel": {
211 | "type": "object",
212 | "required": [
213 | "code",
214 | "message"
215 | ],
216 | "properties": {
217 | "code": {
218 | "type": "integer",
219 | "format": "int32"
220 | },
221 | "message": {
222 | "type": "string"
223 | }
224 | }
225 | }
226 | }
227 | }
--------------------------------------------------------------------------------
/tst/resources/swagger/petstore-with-external-docs.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "version": "1.0.0",
5 | "title": "Swagger Petstore",
6 | "description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
7 | "termsOfService": "http://swagger.io/terms/",
8 | "contact": {
9 | "name": "Swagger API Team",
10 | "email": "apiteam@swagger.io",
11 | "url": "http://swagger.io"
12 | },
13 | "license": {
14 | "name": "MIT",
15 | "url": "http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT"
16 | }
17 | },
18 | "externalDocs": {
19 | "description": "find more info here",
20 | "url": "https://swagger.io/about"
21 | },
22 | "host": "petstore.swagger.io",
23 | "basePath": "/api",
24 | "schemes": [
25 | "http"
26 | ],
27 | "consumes": [
28 | "application/json"
29 | ],
30 | "produces": [
31 | "application/json"
32 | ],
33 | "paths": {
34 | "/pets": {
35 | "get": {
36 | "description": "Returns all pets from the system that the user has access to",
37 | "operationId": "findPets",
38 | "externalDocs": {
39 | "description": "find more info here",
40 | "url": "https://swagger.io/about"
41 | },
42 | "produces": [
43 | "application/json",
44 | "application/xml",
45 | "text/xml",
46 | "text/html"
47 | ],
48 | "parameters": [
49 | {
50 | "name": "tags",
51 | "in": "query",
52 | "description": "tags to filter by",
53 | "required": false,
54 | "type": "array",
55 | "items": {
56 | "type": "string"
57 | },
58 | "collectionFormat": "csv"
59 | },
60 | {
61 | "name": "limit",
62 | "in": "query",
63 | "description": "maximum number of results to return",
64 | "required": false,
65 | "type": "integer",
66 | "format": "int32"
67 | }
68 | ],
69 | "responses": {
70 | "200": {
71 | "description": "pet response",
72 | "schema": {
73 | "type": "array",
74 | "items": {
75 | "$ref": "#/definitions/Pet"
76 | }
77 | }
78 | },
79 | "default": {
80 | "description": "unexpected error",
81 | "schema": {
82 | "$ref": "#/definitions/ErrorModel"
83 | }
84 | }
85 | }
86 | },
87 | "post": {
88 | "description": "Creates a new pet in the store. Duplicates are allowed",
89 | "operationId": "addPet",
90 | "produces": [
91 | "application/json"
92 | ],
93 | "parameters": [
94 | {
95 | "name": "pet",
96 | "in": "body",
97 | "description": "Pet to add to the store",
98 | "required": true,
99 | "schema": {
100 | "$ref": "#/definitions/NewPet"
101 | }
102 | }
103 | ],
104 | "responses": {
105 | "200": {
106 | "description": "pet response",
107 | "schema": {
108 | "$ref": "#/definitions/Pet"
109 | }
110 | },
111 | "default": {
112 | "description": "unexpected error",
113 | "schema": {
114 | "$ref": "#/definitions/ErrorModel"
115 | }
116 | }
117 | }
118 | }
119 | },
120 | "/pets/{id}": {
121 | "get": {
122 | "description": "Returns a user based on a single ID, if the user does not have access to the pet",
123 | "operationId": "findPetById",
124 | "produces": [
125 | "application/json",
126 | "application/xml",
127 | "text/xml",
128 | "text/html"
129 | ],
130 | "parameters": [
131 | {
132 | "name": "id",
133 | "in": "path",
134 | "description": "ID of pet to fetch",
135 | "required": true,
136 | "type": "integer",
137 | "format": "int64"
138 | }
139 | ],
140 | "responses": {
141 | "200": {
142 | "description": "pet response",
143 | "schema": {
144 | "$ref": "#/definitions/Pet"
145 | }
146 | },
147 | "default": {
148 | "description": "unexpected error",
149 | "schema": {
150 | "$ref": "#/definitions/ErrorModel"
151 | }
152 | }
153 | }
154 | },
155 | "delete": {
156 | "description": "deletes a single pet based on the ID supplied",
157 | "operationId": "deletePet",
158 | "parameters": [
159 | {
160 | "name": "id",
161 | "in": "path",
162 | "description": "ID of pet to delete",
163 | "required": true,
164 | "type": "integer",
165 | "format": "int64"
166 | }
167 | ],
168 | "responses": {
169 | "204": {
170 | "description": "pet deleted"
171 | },
172 | "default": {
173 | "description": "unexpected error",
174 | "schema": {
175 | "$ref": "#/definitions/ErrorModel"
176 | }
177 | }
178 | }
179 | }
180 | }
181 | },
182 | "definitions": {
183 | "Pet": {
184 | "type": "object",
185 | "required": [
186 | "id",
187 | "name"
188 | ],
189 | "externalDocs": {
190 | "description": "find more info here",
191 | "url": "https://swagger.io/about"
192 | },
193 | "properties": {
194 | "id": {
195 | "type": "integer",
196 | "format": "int64"
197 | },
198 | "name": {
199 | "type": "string"
200 | },
201 | "tag": {
202 | "type": "string"
203 | }
204 | }
205 | },
206 | "NewPet": {
207 | "type": "object",
208 | "allOf": [
209 | {
210 | "$ref": "#/definitions/Pet"
211 | },
212 | {
213 | "required": [
214 | "name"
215 | ],
216 | "properties": {
217 | "id": {
218 | "type": "integer",
219 | "format": "int64"
220 | }
221 | }
222 | }
223 | ]
224 | },
225 | "ErrorModel": {
226 | "type": "object",
227 | "required": [
228 | "code",
229 | "message"
230 | ],
231 | "properties": {
232 | "code": {
233 | "type": "integer",
234 | "format": "int32"
235 | },
236 | "message": {
237 | "type": "string"
238 | }
239 | }
240 | }
241 | }
242 | }
243 |
--------------------------------------------------------------------------------
/tst/resources/swagger/petstore.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "swagger": "2.0",
4 | "info": {
5 | "version": "1.0.0",
6 | "title": "Swagger Petstore",
7 | "description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification",
8 | "termsOfService": "http://swagger.io/terms/",
9 | "contact": {
10 | "name": "Swagger API Team",
11 | "email": "apiteam@swagger.io",
12 | "url": "http://swagger.io"
13 | },
14 | "license": {
15 | "name": "MIT",
16 | "url": "http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT"
17 | }
18 | },
19 | "externalDocs": {
20 | "description": "find more info here",
21 | "url": "https://swagger.io/about"
22 | },
23 | "host": "petstore.swagger.io",
24 | "basePath": "/api",
25 | "schemes": [
26 | "http"
27 | ],
28 | "consumes": [
29 | "application/json"
30 | ],
31 | "produces": [
32 | "application/json"
33 | ],
34 | "paths": {
35 | "/pets2/pets3" : {},
36 | "/pets": {
37 | "get": {
38 | "description": "Returns all pets from the system that the user has access to",
39 | "operationId": "findPets",
40 | "externalDocs": {
41 | "description": "find more info here",
42 | "url": "https://swagger.io/about"
43 | },
44 | "produces": [
45 | "application/json",
46 | "application/xml",
47 | "text/xml",
48 | "text/html"
49 | ],
50 | "parameters": [
51 | {
52 | "name": "tags",
53 | "in": "query",
54 | "description": "tags to filter by",
55 | "required": false,
56 | "type": "array",
57 | "items": {
58 | "type": "string"
59 | },
60 | "collectionFormat": "csv"
61 | },
62 | {
63 | "name": "limit",
64 | "in": "query",
65 | "description": "maximum number of results to return",
66 | "required": false,
67 | "type": "integer",
68 | "format": "int32"
69 | }
70 | ],
71 | "responses": {
72 | "200": {
73 | "description": "pet response",
74 | "schema": {
75 | "type": "array",
76 | "items": {
77 | "$ref": "#/definitions/Pet"
78 | }
79 | }
80 | },
81 | "default": {
82 | "description": "unexpected error",
83 | "schema": {
84 | "$ref": "#/definitions/ErrorModel"
85 | }
86 | }
87 | }
88 | },
89 | "post": {
90 | "description": "Creates a new pet in the store. Duplicates are allowed",
91 | "operationId": "addPet",
92 | "produces": [
93 | "application/json"
94 | ],
95 | "parameters": [
96 | {
97 | "name": "pet",
98 | "in": "body",
99 | "description": "Pet to add to the store",
100 | "required": true,
101 | "schema": {
102 | "$ref": "#/definitions/NewPet"
103 | }
104 | }
105 | ],
106 | "responses": {
107 | "200": {
108 | "description": "pet response",
109 | "schema": {
110 | "$ref": "#/definitions/Pet"
111 | }
112 | },
113 | "default": {
114 | "description": "unexpected error",
115 | "schema": {
116 | "$ref": "#/definitions/ErrorModel"
117 | }
118 | }
119 | }
120 | }
121 | },
122 | "/pets/{id}": {
123 | "get": {
124 | "description": "Returns a user based on a single ID, if the user does not have access to the pet",
125 | "operationId": "findPetById",
126 | "produces": [
127 | "application/json",
128 | "application/xml",
129 | "text/xml",
130 | "text/html"
131 | ],
132 | "parameters": [
133 | {
134 | "name": "id",
135 | "in": "path",
136 | "description": "ID of pet to fetch",
137 | "required": true,
138 | "type": "integer",
139 | "format": "int64"
140 | }
141 | ],
142 | "responses": {
143 | "200": {
144 | "description": "pet response",
145 | "schema": {
146 | "$ref": "#/definitions/Pet"
147 | }
148 | },
149 | "default": {
150 | "description": "unexpected error",
151 | "schema": {
152 | "$ref": "#/definitions/ErrorModel"
153 | }
154 | }
155 | }
156 | },
157 | "delete": {
158 | "description": "deletes a single pet based on the ID supplied",
159 | "operationId": "deletePet",
160 | "parameters": [
161 | {
162 | "name": "id",
163 | "in": "path",
164 | "description": "ID of pet to delete",
165 | "required": true,
166 | "type": "integer",
167 | "format": "int64"
168 | }
169 | ],
170 | "responses": {
171 | "204": {
172 | "description": "pet deleted"
173 | },
174 | "default": {
175 | "description": "unexpected error",
176 | "schema": {
177 | "$ref": "#/definitions/ErrorModel"
178 | }
179 | }
180 | }
181 | }
182 | }
183 | },
184 | "definitions": {
185 | "Pet": {
186 | "required": [
187 | "id",
188 | "name"
189 | ],
190 |
191 | "properties": {
192 | "id": {
193 | "type": "integer",
194 | "format": "int64"
195 | },
196 | "name": {
197 | "type": "string"
198 | },
199 | "tag": {
200 | "type": "string"
201 | }
202 | }
203 | },
204 | "NewPet": {
205 | "allOf": [
206 | {
207 | "$ref": "#/definitions/Pet"
208 | },
209 | {
210 | "required": [
211 | "name"
212 | ],
213 | "properties": {
214 | "id": {
215 | "type": "integer",
216 | "format": "int64"
217 | }
218 | }
219 | }
220 | ]
221 | },
222 | "ErrorModel": {
223 | "required": [
224 | "code",
225 | "message"
226 | ],
227 | "properties": {
228 | "code": {
229 | "type": "integer",
230 | "format": "int32"
231 | },
232 | "message": {
233 | "type": "string"
234 | }
235 | }
236 | }
237 | }
238 | }
--------------------------------------------------------------------------------
/tst/resources/swagger/test.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "title": "Uber API v2",
5 | "description": "Move your app forward with the Uber API",
6 | "version": "1.0.0"
7 | },
8 | "host": "api.uber.com",
9 | "schemes": [
10 | "https"
11 | ],
12 | "basePath": "/api/v1",
13 | "produces": [
14 | "application/json"
15 | ],
16 | "paths": {
17 | "/" : {
18 | "get": {
19 | }
20 | },
21 | "/level1" : {
22 | "get": {
23 | }
24 | },
25 | "/level1/level2" : {
26 | "get": {
27 | }
28 | },
29 | "/level1/level2/level3" : {
30 | "post": {
31 | }
32 | },
33 | "noslash" : {
34 | "get": {
35 | }
36 | },
37 | "postbody" : {
38 | "post": {
39 | "summary": "Product Types",
40 | "description": "The Products endpoint returns information about the *Uber* products\noffered at a given location. The response includes the display name\nand other details about each product, and lists the products in the\nproper display order.\n",
41 | "parameters": [
42 | {
43 | "name": "postbody",
44 | "in": "body",
45 | "description": "Latitude component of location.",
46 | "required": true,
47 | "type": "object",
48 | "schema": {
49 | "properties": {
50 | "prop1": {
51 | "type": "string"
52 | },
53 | "prop2": {
54 | "type": "array",
55 | "items": {
56 | "$ref": "#/definitions/Product"
57 | }
58 |
59 | }
60 | }
61 | }
62 | }
63 | ],
64 | "tags": [
65 | "Products"
66 | ],
67 | "responses": {
68 | "200": {
69 | "description": "An array of products",
70 | "schema": {
71 | "type": "array",
72 | "items": {
73 | "$ref": "#/definitions/Product"
74 | }
75 | }
76 | },
77 | "400": {
78 | "schema": {
79 | "properties": {
80 | "prop1" : { "type" : "string" },
81 | "prop2" : { "type" : "array"}
82 | }
83 | }
84 | },
85 | "default": {
86 | "description": "Unexpected error",
87 | "schema": {
88 | "$ref": "#/definitions/Error"
89 | }
90 | }
91 | }
92 | }
93 | },
94 | "/products": {
95 | "get": {
96 | "summary": "Product Types",
97 | "description": "The Products endpoint returns information about the *Uber* products\noffered at a given location. The response includes the display name\nand other details about each product, and lists the products in the\nproper display order.\n",
98 | "parameters": [
99 | {
100 | "name": "latitude",
101 | "in": "query",
102 | "description": "Latitude component of location.",
103 | "required": true,
104 | "type": "number",
105 | "format": "double"
106 | },
107 | {
108 | "name": "longitude",
109 | "in": "query",
110 | "description": "Longitude component of location.",
111 | "required": true,
112 | "type": "number",
113 | "format": "double"
114 | }
115 | ],
116 | "tags": [
117 | "Products"
118 | ],
119 | "responses": {
120 | "200": {
121 | "description": "An array of products",
122 | "schema": {
123 | "type": "array",
124 | "items": {
125 | "$ref": "#/definitions/Product"
126 | }
127 | }
128 | },
129 | "400": {
130 | "schema": {
131 | "type": "object",
132 | "properties": {
133 | "prop1" : { "type" : "string" },
134 | "prop2" : { "type" : "array"}
135 | }
136 | }
137 | },
138 | "default": {
139 | "description": "Unexpected error",
140 | "schema": {
141 | "$ref": "#/definitions/Error"
142 | }
143 | }
144 | }
145 | }
146 | },
147 | "/estimates/price": {
148 | "get": {
149 | "summary": "Price Estimates",
150 | "description": "The Price Estimates endpoint returns an estimated price range\nfor each product offered at a given location. The price estimate is\nprovided as a formatted string with the full price range and the localized\ncurrency symbol.
The response also includes low and high estimates,\nand the [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code for\nsituations requiring currency conversion. When surge is active for a particular\nproduct, its surge_multiplier will be greater than 1, but the price estimate\nalready factors in this multiplier.\n",
151 | "parameters": [
152 | {
153 | "name": "start_latitude",
154 | "in": "query",
155 | "description": "Latitude component of start location.",
156 | "required": true,
157 | "type": "number",
158 | "format": "double"
159 | },
160 | {
161 | "name": "start_longitude",
162 | "in": "query",
163 | "description": "Longitude component of start location.",
164 | "required": true,
165 | "type": "number",
166 | "format": "double"
167 | },
168 | {
169 | "name": "end_latitude",
170 | "in": "query",
171 | "description": "Latitude component of end location.",
172 | "required": true,
173 | "type": "number",
174 | "format": "double"
175 | },
176 | {
177 | "name": "end_longitude",
178 | "in": "query",
179 | "description": "Longitude component of end location.",
180 | "required": true,
181 | "type": "number",
182 | "format": "double"
183 | }
184 | ],
185 | "tags": [
186 | "Estimates"
187 | ],
188 | "responses": {
189 | "200": {
190 | "description": "An array of price estimates by product",
191 | "schema": {
192 | "type": "array",
193 | "items": {
194 | "$ref": "#/definitions/PriceEstimate"
195 | }
196 | }
197 | },
198 | "default": {
199 | "description": "Unexpected error",
200 | "schema": {
201 | "$ref": "#/definitions/Error"
202 | }
203 | }
204 | }
205 | },
206 |
207 | "put" : {
208 | },
209 | "delete" : {
210 | },
211 | "options" : {
212 | },
213 | "patch" : {
214 | }
215 | },
216 | "/estimates/time": {
217 | "get": {
218 | "summary": "Time Estimates",
219 | "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.",
220 | "parameters": [
221 | {
222 | "name": "start_latitude",
223 | "in": "query",
224 | "description": "Latitude component of start location.",
225 | "required": true,
226 | "type": "number",
227 | "format": "double"
228 | },
229 | {
230 | "name": "start_longitude",
231 | "in": "query",
232 | "description": "Longitude component of start location.",
233 | "required": true,
234 | "type": "number",
235 | "format": "double"
236 | },
237 | {
238 | "name": "customer_uuid",
239 | "in": "query",
240 | "type": "string",
241 | "format": "uuid",
242 | "description": "Unique customer identifier to be used for experience customization."
243 | },
244 | {
245 | "name": "product_id",
246 | "in": "query",
247 | "type": "string",
248 | "description": "Unique identifier representing a specific product for a given latitude & longitude."
249 | }
250 | ],
251 | "tags": [
252 | "Estimates"
253 | ],
254 | "responses": {
255 | "200": {
256 | "description": "An array of products",
257 | "schema": {
258 | "type": "array",
259 | "items": {
260 | "$ref": "#/definitions/Product"
261 | }
262 | }
263 | },
264 | "301": {
265 | "description": "An array of products",
266 | "schema": {
267 | "type": "array",
268 | "items": {
269 | "$ref": "#/definitions/Product"
270 | }
271 | }
272 | },
273 |
274 | "default": {
275 | "description": "Unexpected error",
276 | "schema": {
277 | "$ref": "#/definitions/Error"
278 | }
279 | }
280 | }
281 | }
282 | },
283 | "/me": {
284 | "get": {
285 | "summary": "User Profile",
286 | "description": "The User Profile endpoint returns information about the Uber user that has authorized with the application.",
287 | "tags": [
288 | "User"
289 | ],
290 | "responses": {
291 | "200": {
292 | "description": "Profile information for a user",
293 | "schema": {
294 | "$ref": "#/definitions/Profile"
295 | }
296 | },
297 | "default": {
298 | "description": "Unexpected error",
299 | "schema": {
300 | "$ref": "#/definitions/Error"
301 | }
302 | }
303 | }
304 | }
305 | },
306 | "/history": {
307 | "get": {
308 | "summary": "User Activity",
309 | "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.
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.",
310 | "parameters": [
311 | {
312 | "name": "offset",
313 | "in": "query",
314 | "type": "integer",
315 | "format": "int32",
316 | "description": "Offset the list of returned results by this amount. Default is zero."
317 | },
318 | {
319 | "name": "limit",
320 | "in": "query",
321 | "type": "integer",
322 | "format": "int32",
323 | "description": "Number of items to retrieve. Default is 5, maximum is 100."
324 | }
325 | ],
326 | "tags": [
327 | "User"
328 | ],
329 | "responses": {
330 | "200": {
331 | "description": "History information for the given user",
332 | "schema": {
333 | "$ref": "#/definitions/Activities"
334 | }
335 | },
336 | "default": {
337 | "description": "Unexpected error",
338 | "schema": {
339 | "$ref": "#/definitions/Error"
340 | }
341 | }
342 | }
343 | }
344 | }
345 | },
346 | "definitions": {
347 | "Product": {
348 | "properties": {
349 | "product_id": {
350 | "type": "string",
351 | "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."
352 | },
353 | "description": {
354 | "type": "string",
355 | "description": "Description of product."
356 | },
357 | "display_name": {
358 | "type": "string",
359 | "description": "Display name of product."
360 | },
361 | "capacity": {
362 | "type": "string",
363 | "description": "Capacity of product. For example, 4 people."
364 | },
365 | "image": {
366 | "type": "string",
367 | "description": "Image URL representing the product."
368 | }
369 | }
370 | },
371 | "PriceEstimate": {
372 | "properties": {
373 | "product_id": {
374 | "type": "string",
375 | "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"
376 | },
377 | "currency_code": {
378 | "type": "string",
379 | "description": "[ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code."
380 | },
381 | "display_name": {
382 | "type": "string",
383 | "description": "Display name of product."
384 | },
385 | "estimate": {
386 | "type": "string",
387 | "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."
388 | },
389 | "low_estimate": {
390 | "type": "number",
391 | "description": "Lower bound of the estimated price."
392 | },
393 | "high_estimate": {
394 | "type": "number",
395 | "description": "Upper bound of the estimated price."
396 | },
397 | "surge_multiplier": {
398 | "type": "number",
399 | "description": "Expected surge multiplier. Surge is active if surge_multiplier is greater than 1. Price estimate already factors in the surge multiplier."
400 | }
401 | }
402 | },
403 | "Profile": {
404 | "properties": {
405 | "first_name": {
406 | "type": "string",
407 | "description": "First name of the Uber user."
408 | },
409 | "last_name": {
410 | "type": "string",
411 | "description": "Last name of the Uber user."
412 | },
413 | "email": {
414 | "type": "string",
415 | "description": "Email address of the Uber user"
416 | },
417 | "picture": {
418 | "type": "string",
419 | "description": "Image URL of the Uber user."
420 | },
421 | "promo_code": {
422 | "type": "string",
423 | "description": "Promo code of the Uber user."
424 | }
425 | }
426 | },
427 | "Activity": {
428 | "properties": {
429 | "uuid": {
430 | "type": "string",
431 | "description": "Unique identifier for the activity"
432 | }
433 | }
434 | },
435 | "Activities": {
436 | "properties": {
437 | "offset": {
438 | "type": "integer",
439 | "format": "int32",
440 | "description": "Position in pagination."
441 | },
442 | "limit": {
443 | "type": "integer",
444 | "format": "int32",
445 | "description": "Number of items to retrieve (100 max)."
446 | },
447 | "count": {
448 | "type": "integer",
449 | "format": "int32",
450 | "description": "Total number of items available."
451 | },
452 | "history": {
453 | "type": "array",
454 | "items": {
455 | "$ref": "#/definitions/Activity"
456 | }
457 | }
458 | }
459 | }
460 | }
461 | }
--------------------------------------------------------------------------------
/tst/resources/swagger/uber.json:
--------------------------------------------------------------------------------
1 | {
2 | "swagger": "2.0",
3 | "info": {
4 | "title": "Uber API",
5 | "description": "Move your app forward with the Uber API",
6 | "version": "1.0.0"
7 | },
8 | "host": "api.uber.com",
9 | "schemes": [
10 | "https"
11 | ],
12 | "basePath": "/v1",
13 | "produces": [
14 | "application/json"
15 | ],
16 | "paths": {
17 | "/products": {
18 | "get": {
19 | "summary": "Product Types",
20 | "description": "The Products endpoint returns information about the *Uber* products\noffered at a given location. The response includes the display name\nand other details about each product, and lists the products in the\nproper display order.\n",
21 | "parameters": [
22 | {
23 | "name": "latitude",
24 | "in": "query",
25 | "description": "Latitude component of location.",
26 | "required": true,
27 | "type": "number",
28 | "format": "double"
29 | },
30 | {
31 | "name": "longitude",
32 | "in": "query",
33 | "description": "Longitude component of location.",
34 | "required": true,
35 | "type": "number",
36 | "format": "double"
37 | }
38 | ],
39 | "tags": [
40 | "Products"
41 | ],
42 | "responses": {
43 | "200": {
44 | "description": "An array of products",
45 | "schema": {
46 | "type": "array",
47 | "items": {
48 | "$ref": "#/definitions/Product"
49 | }
50 | }
51 | },
52 | "default": {
53 | "description": "Unexpected error",
54 | "schema": {
55 | "$ref": "#/definitions/Error"
56 | }
57 | }
58 | }
59 | }
60 | },
61 | "/estimates/price": {
62 | "get": {
63 | "summary": "Price Estimates",
64 | "description": "The Price Estimates endpoint returns an estimated price range\nfor each product offered at a given location. The price estimate is\nprovided as a formatted string with the full price range and the localized\ncurrency symbol.
The response also includes low and high estimates,\nand the [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code for\nsituations requiring currency conversion. When surge is active for a particular\nproduct, its surge_multiplier will be greater than 1, but the price estimate\nalready factors in this multiplier.\n",
65 | "parameters": [
66 | {
67 | "name": "start_latitude",
68 | "in": "query",
69 | "description": "Latitude component of start location.",
70 | "required": true,
71 | "type": "number",
72 | "format": "double"
73 | },
74 | {
75 | "name": "start_longitude",
76 | "in": "query",
77 | "description": "Longitude component of start location.",
78 | "required": true,
79 | "type": "number",
80 | "format": "double"
81 | },
82 | {
83 | "name": "end_latitude",
84 | "in": "query",
85 | "description": "Latitude component of end location.",
86 | "required": true,
87 | "type": "number",
88 | "format": "double"
89 | },
90 | {
91 | "name": "end_longitude",
92 | "in": "query",
93 | "description": "Longitude component of end location.",
94 | "required": true,
95 | "type": "number",
96 | "format": "double"
97 | }
98 | ],
99 | "tags": [
100 | "Estimates"
101 | ],
102 | "responses": {
103 | "200": {
104 | "description": "An array of price estimates by product",
105 | "schema": {
106 | "type": "array",
107 | "items": {
108 | "$ref": "#/definitions/PriceEstimate"
109 | }
110 | }
111 | },
112 | "default": {
113 | "description": "Unexpected error",
114 | "schema": {
115 | "$ref": "#/definitions/Error"
116 | }
117 | }
118 | }
119 | }
120 | },
121 | "/estimates/time": {
122 | "get": {
123 | "summary": "Time Estimates",
124 | "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.",
125 | "parameters": [
126 | {
127 | "name": "start_latitude",
128 | "in": "query",
129 | "description": "Latitude component of start location.",
130 | "required": true,
131 | "type": "number",
132 | "format": "double"
133 | },
134 | {
135 | "name": "start_longitude",
136 | "in": "query",
137 | "description": "Longitude component of start location.",
138 | "required": true,
139 | "type": "number",
140 | "format": "double"
141 | },
142 | {
143 | "name": "customer_uuid",
144 | "in": "query",
145 | "type": "string",
146 | "format": "uuid",
147 | "description": "Unique customer identifier to be used for experience customization."
148 | },
149 | {
150 | "name": "product_id",
151 | "in": "query",
152 | "type": "string",
153 | "description": "Unique identifier representing a specific product for a given latitude & longitude."
154 | }
155 | ],
156 | "tags": [
157 | "Estimates"
158 | ],
159 | "responses": {
160 | "200": {
161 | "description": "An array of products",
162 | "schema": {
163 | "type": "array",
164 | "items": {
165 | "$ref": "#/definitions/Product"
166 | }
167 | }
168 | },
169 | "default": {
170 | "description": "Unexpected error",
171 | "schema": {
172 | "$ref": "#/definitions/Error"
173 | }
174 | }
175 | }
176 | }
177 | },
178 | "/me": {
179 | "get": {
180 | "summary": "User Profile",
181 | "description": "The User Profile endpoint returns information about the Uber user that has authorized with the application.",
182 | "tags": [
183 | "User"
184 | ],
185 | "responses": {
186 | "200": {
187 | "description": "Profile information for a user",
188 | "schema": {
189 | "$ref": "#/definitions/Profile"
190 | }
191 | },
192 | "default": {
193 | "description": "Unexpected error",
194 | "schema": {
195 | "$ref": "#/definitions/Error"
196 | }
197 | }
198 | }
199 | }
200 | },
201 | "/history": {
202 | "get": {
203 | "summary": "User Activity",
204 | "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.
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.",
205 | "parameters": [
206 | {
207 | "name": "offset",
208 | "in": "query",
209 | "type": "integer",
210 | "format": "int32",
211 | "description": "Offset the list of returned results by this amount. Default is zero."
212 | },
213 | {
214 | "name": "limit",
215 | "in": "query",
216 | "type": "integer",
217 | "format": "int32",
218 | "description": "Number of items to retrieve. Default is 5, maximum is 100."
219 | }
220 | ],
221 | "tags": [
222 | "User"
223 | ],
224 | "responses": {
225 | "200": {
226 | "description": "History information for the given user",
227 | "schema": {
228 | "$ref": "#/definitions/Activities"
229 | }
230 | },
231 | "default": {
232 | "description": "Unexpected error",
233 | "schema": {
234 | "$ref": "#/definitions/Error"
235 | }
236 | }
237 | }
238 | }
239 | }
240 | },
241 | "definitions": {
242 | "Product": {
243 | "properties": {
244 | "product_id": {
245 | "type": "string",
246 | "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."
247 | },
248 | "description": {
249 | "type": "string",
250 | "description": "Description of product."
251 | },
252 | "display_name": {
253 | "type": "string",
254 | "description": "Display name of product."
255 | },
256 | "capacity": {
257 | "type": "string",
258 | "description": "Capacity of product. For example, 4 people."
259 | },
260 | "image": {
261 | "type": "string",
262 | "description": "Image URL representing the product."
263 | }
264 | }
265 | },
266 | "PriceEstimate": {
267 | "properties": {
268 | "product_id": {
269 | "type": "string",
270 | "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"
271 | },
272 | "currency_code": {
273 | "type": "string",
274 | "description": "[ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code."
275 | },
276 | "display_name": {
277 | "type": "string",
278 | "description": "Display name of product."
279 | },
280 | "estimate": {
281 | "type": "string",
282 | "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."
283 | },
284 | "low_estimate": {
285 | "type": "number",
286 | "description": "Lower bound of the estimated price."
287 | },
288 | "high_estimate": {
289 | "type": "number",
290 | "description": "Upper bound of the estimated price."
291 | },
292 | "surge_multiplier": {
293 | "type": "number",
294 | "description": "Expected surge multiplier. Surge is active if surge_multiplier is greater than 1. Price estimate already factors in the surge multiplier."
295 | }
296 | }
297 | },
298 | "Profile": {
299 | "properties": {
300 | "first_name": {
301 | "type": "string",
302 | "description": "First name of the Uber user."
303 | },
304 | "last_name": {
305 | "type": "string",
306 | "description": "Last name of the Uber user."
307 | },
308 | "email": {
309 | "type": "string",
310 | "description": "Email address of the Uber user"
311 | },
312 | "picture": {
313 | "type": "string",
314 | "description": "Image URL of the Uber user."
315 | },
316 | "promo_code": {
317 | "type": "string",
318 | "description": "Promo code of the Uber user."
319 | }
320 | }
321 | },
322 | "Activity": {
323 | "properties": {
324 | "uuid": {
325 | "type": "string",
326 | "description": "Unique identifier for the activity"
327 | }
328 | }
329 | },
330 | "Activities": {
331 | "properties": {
332 | "offset": {
333 | "type": "integer",
334 | "format": "int32",
335 | "description": "Position in pagination."
336 | },
337 | "limit": {
338 | "type": "integer",
339 | "format": "int32",
340 | "description": "Number of items to retrieve (100 max)."
341 | },
342 | "count": {
343 | "type": "integer",
344 | "format": "int32",
345 | "description": "Total number of items available."
346 | },
347 | "history": {
348 | "type": "array",
349 | "items": {
350 | "$ref": "#/definitions/Activity"
351 | }
352 | }
353 | }
354 | },
355 | "Error": {
356 | "properties": {
357 | "code": {
358 | "type": "integer",
359 | "format": "int32"
360 | },
361 | "message": {
362 | "type": "string"
363 | },
364 | "fields": {
365 | "type": "string"
366 | }
367 | }
368 | }
369 | }
370 | }
--------------------------------------------------------------------------------
/tst/resources/swagger/uber.yaml:
--------------------------------------------------------------------------------
1 | # this is an example of the Uber API
2 | # as a demonstration of an API spec in YAML
3 | swagger: '2.0'
4 | info:
5 | title: Uber API
6 | description: Move your app forward with the Uber API
7 | version: "1.0.0"
8 | # the domain of the service
9 | host: api.uber.com
10 | # array of all schemes that your API supports
11 | schemes:
12 | - https
13 | # will be prefixed to all paths
14 | basePath: /v1
15 | produces:
16 | - application/json
17 | paths:
18 | /products:
19 | get:
20 | summary: Product Types
21 | description: |
22 | The Products endpoint returns information about the *Uber* products
23 | offered at a given location. The response includes the display name
24 | and other details about each product, and lists the products in the
25 | proper display order.
26 | parameters:
27 | - name: latitude
28 | in: query
29 | description: Latitude component of location.
30 | required: true
31 | type: number
32 | format: double
33 | - name: longitude
34 | in: query
35 | description: Longitude component of location.
36 | required: true
37 | type: number
38 | format: double
39 | tags:
40 | - Products
41 | responses:
42 | 200:
43 | description: An array of products
44 | schema:
45 | type: array
46 | items:
47 | $ref: '#/definitions/Product'
48 | default:
49 | description: Unexpected error
50 | schema:
51 | $ref: '#/definitions/Error'
52 | /estimates/price:
53 | get:
54 | summary: Price Estimates
55 | description: |
56 | The Price Estimates endpoint returns an estimated price range
57 | for each product offered at a given location. The price estimate is
58 | provided as a formatted string with the full price range and the localized
59 | currency symbol.
The response also includes low and high estimates,
60 | and the [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code for
61 | situations requiring currency conversion. When surge is active for a particular
62 | product, its surge_multiplier will be greater than 1, but the price estimate
63 | already factors in this multiplier.
64 | parameters:
65 | - name: start_latitude
66 | in: query
67 | description: Latitude component of start location.
68 | required: true
69 | type: number
70 | format: double
71 | - name: start_longitude
72 | in: query
73 | description: Longitude component of start location.
74 | required: true
75 | type: number
76 | format: double
77 | - name: end_latitude
78 | in: query
79 | description: Latitude component of end location.
80 | required: true
81 | type: number
82 | format: double
83 | - name: end_longitude
84 | in: query
85 | description: Longitude component of end location.
86 | required: true
87 | type: number
88 | format: double
89 | tags:
90 | - Estimates
91 | responses:
92 | 200:
93 | description: An array of price estimates by product
94 | schema:
95 | type: array
96 | items:
97 | $ref: '#/definitions/PriceEstimate'
98 | default:
99 | description: Unexpected error
100 | schema:
101 | $ref: '#/definitions/Error'
102 | /estimates/time:
103 | get:
104 | summary: Time Estimates
105 | 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.
106 | parameters:
107 | - name: start_latitude
108 | in: query
109 | description: Latitude component of start location.
110 | required: true
111 | type: number
112 | format: double
113 | - name: start_longitude
114 | in: query
115 | description: Longitude component of start location.
116 | required: true
117 | type: number
118 | format: double
119 | - name: customer_uuid
120 | in: query
121 | type: string
122 | format: uuid
123 | description: Unique customer identifier to be used for experience customization.
124 | - name: product_id
125 | in: query
126 | type: string
127 | description: Unique identifier representing a specific product for a given latitude & longitude.
128 | tags:
129 | - Estimates
130 | responses:
131 | 200:
132 | description: An array of products
133 | schema:
134 | type: array
135 | items:
136 | $ref: '#/definitions/Product'
137 | default:
138 | description: Unexpected error
139 | schema:
140 | $ref: '#/definitions/Error'
141 | /me:
142 | get:
143 | summary: User Profile
144 | description: The User Profile endpoint returns information about the Uber user that has authorized with the application.
145 | tags:
146 | - User
147 | responses:
148 | 200:
149 | description: Profile information for a user
150 | schema:
151 | $ref: '#/definitions/Profile'
152 | default:
153 | description: Unexpected error
154 | schema:
155 | $ref: '#/definitions/Error'
156 | /history:
157 | get:
158 | summary: User Activity
159 | 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.
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.
160 | parameters:
161 | - name: offset
162 | in: query
163 | type: integer
164 | format: int32
165 | description: Offset the list of returned results by this amount. Default is zero.
166 | - name: limit
167 | in: query
168 | type: integer
169 | format: int32
170 | description: Number of items to retrieve. Default is 5, maximum is 100.
171 | tags:
172 | - User
173 | responses:
174 | 200:
175 | description: History information for the given user
176 | schema:
177 | $ref: '#/definitions/Activities'
178 | default:
179 | description: Unexpected error
180 | schema:
181 | $ref: '#/definitions/Error'
182 | definitions:
183 | Product:
184 | properties:
185 | product_id:
186 | type: string
187 | 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.
188 | description:
189 | type: string
190 | description: Description of product.
191 | display_name:
192 | type: string
193 | description: Display name of product.
194 | capacity:
195 | type: string
196 | description: Capacity of product. For example, 4 people.
197 | image:
198 | type: string
199 | description: Image URL representing the product.
200 | PriceEstimate:
201 | properties:
202 | product_id:
203 | type: string
204 | 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
205 | currency_code:
206 | type: string
207 | description: "[ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code."
208 | display_name:
209 | type: string
210 | description: Display name of product.
211 | estimate:
212 | type: string
213 | 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.
214 | low_estimate:
215 | type: number
216 | description: Lower bound of the estimated price.
217 | high_estimate:
218 | type: number
219 | description: Upper bound of the estimated price.
220 | surge_multiplier:
221 | type: number
222 | description: Expected surge multiplier. Surge is active if surge_multiplier is greater than 1. Price estimate already factors in the surge multiplier.
223 | Profile:
224 | properties:
225 | first_name:
226 | type: string
227 | description: First name of the Uber user.
228 | last_name:
229 | type: string
230 | description: Last name of the Uber user.
231 | email:
232 | type: string
233 | description: Email address of the Uber user
234 | picture:
235 | type: string
236 | description: Image URL of the Uber user.
237 | promo_code:
238 | type: string
239 | description: Promo code of the Uber user.
240 | Activity:
241 | properties:
242 | uuid:
243 | type: string
244 | description: Unique identifier for the activity
245 | Activities:
246 | properties:
247 | offset:
248 | type: integer
249 | format: int32
250 | description: Position in pagination.
251 | limit:
252 | type: integer
253 | format: int32
254 | description: Number of items to retrieve (100 max).
255 | count:
256 | type: integer
257 | format: int32
258 | description: Total number of items available.
259 | history:
260 | type: array
261 | items:
262 | $ref: '#/definitions/Activity'
263 | Error:
264 | properties:
265 | code:
266 | type: integer
267 | format: int32
268 | message:
269 | type: string
270 | fields:
271 | type: string
272 |
--------------------------------------------------------------------------------