Skip to content

Commit 0108a35

Browse files
committed
implement parse, options and 3.1 support
1 parent 37c1f4f commit 0108a35

36 files changed

+9972
-366
lines changed

README.md

+11-6
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22

33
[![Build Status](https://img.shields.io/jenkins/build.svg?jobUrl=https://jenkins.swagger.io/job/oss-swagger-validator-badge-master)](https://jenkins.swagger.io/view/OSS%20-%20Java/job/oss-swagger-validator-badge-master)
44

5-
This project shows a "valid swagger" badge on your site, supporting Swagger/OpenAPI 2.0 and OpenAPI 3.0 specifications.
5+
This project shows a "valid swagger" badge on your site, supporting Swagger/OpenAPI 2.0 and OpenAPI 3.x specifications.
66

77
There is an online version hosted on http://validator.swagger.io.
88

99
You can also pull a docker image of the validator directly from [DockerHub](https://hub.docker.com/r/swaggerapi/swagger-validator-v2/), e.g.:
1010

1111
```
12-
docker pull swaggerapi/swagger-validator-v2:v2.0.13
13-
docker run -it -p 8080:8080 --name swagger-validator-v2 swaggerapi/swagger-validator-v2:v2.0.13
12+
docker pull swaggerapi/swagger-validator-v2:v2.1.0
13+
docker run -it -p 8080:8080 --name swagger-validator-v2 swaggerapi/swagger-validator-v2:v2.1.0
1414
```
1515

1616
Since version `2.0.2` local and non http/https urls are rejected by default, along with redirects; this is controllable with docker env variables / java system properties:
1717

1818
```
19-
docker run -it -p 8080:8080 -e "REJECT_LOCAL=false" -e "REJECT_REDIRECT=false" --name swagger-validator-v2 swaggerapi/swagger-validator-v2:v2.0.13
19+
docker run -it -p 8080:8080 -e "REJECT_LOCAL=false" -e "REJECT_REDIRECT=false" --name swagger-validator-v2 swaggerapi/swagger-validator-v2:v2.1.0
2020
```
2121

2222
In non docker environments, system properties `rejectLocal` and `rejectRedirect` can be used.
@@ -27,7 +27,10 @@ Web UI is reachable at http://localhost:8080/index.html and OpenAPI spec at http
2727

2828

2929

30-
You can validate any OpenAPI specification against the [Swagger/OpenAPI 2.0 Schema](https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v2.0/schema.json) and [OpenAPI 3.0 Schema](https://github.com/OAI/OpenAPI-Specification/blob/v3.0.1/versions/3.0.1.md) as follows:
30+
You can validate OpenAPI specifications version 2.0 (Swagger), 3.0 and 3.1. [Swagger Parser](https://github.com/swagger-api/swagger-parser/blob/master/README.md) is used for semantic validation.
31+
Depending on `jsonSchemaValidation` query parameter value also JSON Schema validation can be executed (default to `true`)
32+
33+
Additional parameters allow to customize parsing and validation mode.
3134

3235
```
3336
<img src="https://validator.swagger.io/validator?url={YOUR_URL}">
@@ -51,10 +54,12 @@ curl -X POST -d @swagger.json -H 'Content-Type:application/json' https://validat
5154

5255
In this example, `swagger.json` is the swagger definition in JSON format, in the CWD.
5356

54-
Note that all the above is also applicable to OpenAPI 3.0 specifications; for example, using [https://petstore3.swagger.io/api/v3/openapi.json](https://petstore3.swagger.io/api/v3/openapi.json) as a source, we get ...
57+
Note that all the above is also applicable to OpenAPI 3.x specifications; for example, using [https://petstore3.swagger.io/api/v3/openapi.json](https://petstore3.swagger.io/api/v3/openapi.json) as a source, we get ...
5558

5659
![](https://validator.swagger.io/validator?url=https://petstore3.swagger.io/api/v3/openapi.json)
5760

61+
Since version 2.1.0 a `/parseByUrl` and `/parseByContent` are available, returning a serialized parsed specification, with parsing and result configurable by
62+
parameters, e.g. passing `resolve`, etc. See [Swagger Parser](https://github.com/swagger-api/swagger-parser/blob/master/README.md#options)
5863

5964
### Running locally
6065

inflector.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ rootPath: /validator
1010

1111
exposedSpecOptions:
1212
useOriginalNotParsed: true
13+
14+
environment: production

pom.xml

+17-12
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<artifactId>swagger-validator</artifactId>
1010
<packaging>war</packaging>
1111
<name>swagger-validator</name>
12-
<version>2.0.13</version>
12+
<version>2.1.0-SNAPSHOT</version>
1313
<prerequisites>
1414
<maven>2.2.0</maven>
1515
</prerequisites>
@@ -178,10 +178,14 @@
178178
</execution>
179179
</executions>
180180
</plugin>
181-
182181
</plugins>
183182
</build>
184183
<dependencies>
184+
<dependency>
185+
<groupId>io.swagger.parser.v3</groupId>
186+
<artifactId>swagger-parser</artifactId>
187+
<version>${swagger-parser-version}</version>
188+
</dependency>
185189
<!-- inflector library -->
186190
<dependency>
187191
<groupId>io.swagger</groupId>
@@ -196,9 +200,9 @@
196200
</dependency>
197201

198202
<dependency>
199-
<groupId>io.swagger.parser.v3</groupId>
200-
<artifactId>swagger-parser</artifactId>
201-
<version>${swagger-parser-version}</version>
203+
<groupId>com.networknt</groupId>
204+
<artifactId>json-schema-validator</artifactId>
205+
<version>1.0.73</version>
202206
</dependency>
203207

204208
<dependency>
@@ -210,7 +214,7 @@
210214
<dependency>
211215
<groupId>com.fasterxml.jackson.core</groupId>
212216
<artifactId>jackson-databind</artifactId>
213-
<version>${jackson.version}</version>
217+
<version>${jackson-databind.version}</version>
214218
</dependency>
215219

216220
<dependency>
@@ -269,15 +273,16 @@
269273
</repositories>
270274
<properties>
271275
<testng-version>6.9.6</testng-version>
272-
<jackson.version>2.11.1</jackson.version>
273-
<snakeyaml.version>1.27</snakeyaml.version>
276+
<jackson.version>2.13.4</jackson.version>
277+
<jackson-databind.version>2.13.4.2</jackson-databind.version>
278+
<snakeyaml.version>1.33</snakeyaml.version>
274279
<httpclient-version>4.5.13</httpclient-version>
275280
<maven-plugin-version>1.0.0</maven-plugin-version>
276-
<swagger-parser-version>2.0.24</swagger-parser-version>
277-
<swagger-inflector-version>2.0.4</swagger-inflector-version>
281+
<swagger-parser-version>2.1.5</swagger-parser-version>
282+
<swagger-inflector-version>2.0.8</swagger-inflector-version>
278283
<jetty-version>9.4.18.v20190429</jetty-version>
279-
<logback-version>1.0.1</logback-version>
280-
<slf4j-version>1.6.3</slf4j-version>
284+
<logback-version>1.2.10</logback-version>
285+
<slf4j-version>1.7.36</slf4j-version>
281286
<surefire-version>2.18.1</surefire-version>
282287
<json-schema-validator-version>2.2.14</json-schema-validator-version>
283288
</properties>

src/main/java/io/swagger/Utils.java

+183
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package io.swagger;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import io.swagger.v3.core.util.Json;
5+
import io.swagger.v3.core.util.Yaml;
6+
import org.apache.commons.lang3.StringUtils;
7+
import org.apache.http.HttpEntity;
8+
import org.apache.http.StatusLine;
9+
import org.apache.http.client.config.RequestConfig;
10+
import org.apache.http.client.methods.CloseableHttpResponse;
11+
import org.apache.http.client.methods.HttpGet;
12+
import org.apache.http.conn.ssl.NoopHostnameVerifier;
13+
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
14+
import org.apache.http.impl.client.CloseableHttpClient;
15+
import org.apache.http.impl.client.HttpClientBuilder;
16+
import org.apache.http.impl.client.HttpClients;
17+
import org.apache.http.ssl.SSLContextBuilder;
18+
import org.apache.http.ssl.TrustStrategy;
19+
import org.apache.http.util.EntityUtils;
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
22+
23+
import java.io.BufferedReader;
24+
import java.io.IOException;
25+
import java.io.InputStream;
26+
import java.io.InputStreamReader;
27+
import java.net.InetAddress;
28+
import java.net.URL;
29+
import java.security.KeyManagementException;
30+
import java.security.KeyStoreException;
31+
import java.security.NoSuchAlgorithmException;
32+
import java.security.cert.CertificateException;
33+
import java.security.cert.X509Certificate;
34+
import java.util.stream.Collectors;
35+
36+
public class Utils {
37+
38+
public static enum VERSION {
39+
V1,
40+
V20,
41+
V30,
42+
V31,
43+
NONE
44+
}
45+
46+
static Logger LOGGER = LoggerFactory.getLogger(Utils.class);
47+
public static String getVersionString(JsonNode node) {
48+
if (node == null) {
49+
return null;
50+
}
51+
52+
JsonNode version = node.get("openapi");
53+
if (version != null) {
54+
return version.toString();
55+
}
56+
57+
version = node.get("swagger");
58+
if (version != null) {
59+
return version.toString();
60+
}
61+
version = node.get("swaggerVersion");
62+
if (version != null) {
63+
return version.toString();
64+
}
65+
66+
LOGGER.debug("version not found!");
67+
return null;
68+
}
69+
70+
public static VERSION getVersion(JsonNode node) {
71+
String version = getVersionString(node);
72+
if (StringUtils.isBlank(version)) {
73+
return VERSION.NONE;
74+
}
75+
if (version.startsWith("\"1") || version.startsWith("1")) {
76+
return VERSION.V1;
77+
}
78+
if (version.startsWith("\"2") || version.startsWith("2")) {
79+
return VERSION.V20;
80+
}
81+
if (version.startsWith("\"3.0") || version.startsWith("3.0")) {
82+
return VERSION.V30;
83+
}
84+
if (version.startsWith("\"3.1") || version.startsWith("3.1")) {
85+
return VERSION.V31;
86+
}
87+
return VERSION.NONE;
88+
89+
}
90+
91+
92+
public static JsonNode readNode(String text) {
93+
try {
94+
if (text.trim().startsWith("{")) {
95+
return Json.mapper().readTree(text);
96+
} else {
97+
return Yaml.mapper().readTree(text);
98+
}
99+
} catch (IOException e) {
100+
return null;
101+
}
102+
}
103+
104+
public static CloseableHttpClient getCarelessHttpClient(boolean disableRedirect) {
105+
CloseableHttpClient httpClient = null;
106+
107+
try {
108+
SSLContextBuilder builder = new SSLContextBuilder();
109+
builder.loadTrustMaterial(null, new TrustStrategy() {
110+
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
111+
return true;
112+
}
113+
});
114+
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE);
115+
HttpClientBuilder httpClientBuilder = HttpClients
116+
.custom()
117+
.setSSLSocketFactory(sslsf);
118+
if (disableRedirect) {
119+
httpClientBuilder.disableRedirectHandling();
120+
}
121+
httpClientBuilder.setUserAgent("swagger-validator");
122+
httpClient = httpClientBuilder.build();
123+
} catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
124+
LOGGER.error("can't disable SSL verification", e);
125+
}
126+
127+
return httpClient;
128+
}
129+
130+
131+
public static String getUrlContents(String urlString) throws IOException {
132+
return getUrlContents(urlString, false, false);
133+
}
134+
public static String getUrlContents(String urlString, boolean rejectLocal, boolean rejectRedirect) throws IOException {
135+
LOGGER.trace("fetching URL contents");
136+
URL url = new URL(urlString);
137+
if(rejectLocal) {
138+
InetAddress inetAddress = InetAddress.getByName(url.getHost());
139+
if(inetAddress.isAnyLocalAddress() || inetAddress.isLoopbackAddress() || inetAddress.isLinkLocalAddress()) {
140+
throw new IOException("Only accepts http/https protocol");
141+
}
142+
}
143+
final CloseableHttpClient httpClient = getCarelessHttpClient(rejectRedirect);
144+
145+
RequestConfig.Builder requestBuilder = RequestConfig.custom();
146+
requestBuilder = requestBuilder
147+
.setConnectTimeout(5000)
148+
.setSocketTimeout(5000);
149+
150+
HttpGet getMethod = new HttpGet(urlString);
151+
getMethod.setConfig(requestBuilder.build());
152+
getMethod.setHeader("Accept", "application/json, */*");
153+
154+
155+
if (httpClient != null) {
156+
final CloseableHttpResponse response = httpClient.execute(getMethod);
157+
158+
try {
159+
160+
HttpEntity entity = response.getEntity();
161+
StatusLine line = response.getStatusLine();
162+
if(line.getStatusCode() > 299 || line.getStatusCode() < 200) {
163+
throw new IOException("failed to read swagger with code " + line.getStatusCode());
164+
}
165+
return EntityUtils.toString(entity, "UTF-8");
166+
} finally {
167+
response.close();
168+
httpClient.close();
169+
}
170+
} else {
171+
throw new IOException("CloseableHttpClient could not be initialized");
172+
}
173+
}
174+
175+
public static String getResourceFileAsString(String fileName) {
176+
InputStream is = Utils.class.getClassLoader().getResourceAsStream(fileName);
177+
if (is != null) {
178+
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
179+
return reader.lines().collect(Collectors.joining(System.lineSeparator()));
180+
}
181+
return null;
182+
}
183+
}

0 commit comments

Comments
 (0)