Skip to content

Commit 9d4bce9

Browse files
committed
auto-detect openapi/json schema version
1 parent c40acd9 commit 9d4bce9

5 files changed

Lines changed: 76 additions & 71 deletions

File tree

openapi-parser/src/main/java/io/openapiparser/OpenApiParser.java

Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,84 @@
66
package io.openapiparser;
77

88
import io.openapiprocessor.jsonschema.converter.StringNotNullConverter;
9-
import io.openapiprocessor.jsonschema.schema.Bucket;
10-
import io.openapiprocessor.jsonschema.schema.Resolver;
11-
import io.openapiprocessor.jsonschema.schema.ResolverResult;
9+
import io.openapiprocessor.jsonschema.schema.*;
1210

1311
import java.net.URI;
1412

1513
import static io.openapiparser.Keywords.OPENAPI;
16-
import static io.openapiprocessor.jsonschema.converter.Types.asMap;
1714
import static io.openapiprocessor.jsonschema.support.Nullness.nonNull;
1815

1916
public class OpenApiParser {
20-
private final Resolver resolver;
17+
private final DocumentStore documents;
18+
private final DocumentLoader loader;
2119

22-
public OpenApiParser (Resolver resolver) {
23-
this.resolver = resolver;
20+
public OpenApiParser (DocumentStore documents, DocumentLoader loader) {
21+
this.documents = documents;
22+
this.loader = loader;
2423
}
2524

26-
public OpenApiResult parse(URI baseUri) throws Exception {
25+
public OpenApiResult parse(URI baseUri) {
2726
try {
28-
return createResult (resolver.resolve (baseUri));
27+
return parse(baseUri, loader.loadDocument(baseUri));
2928
} catch (Exception e) {
30-
throw new ParserException (e);
29+
throw new ParserException (baseUri, e);
3130
}
3231
}
3332

3433
public OpenApiResult parse(String resource) {
3534
try {
36-
return createResult (resolver.resolve (resource));
35+
return parse(URI.create (resource), loader.loadDocument(resource));
36+
} catch (Exception e) {
37+
throw new ParserException (e);
38+
}
39+
}
40+
41+
public OpenApiResult parse(URI baseUri, Object document) {
42+
try {
43+
return parseVersion(baseUri, document);
3744
} catch (Exception e) {
3845
throw new ParserException (e);
3946
}
4047
}
4148

42-
private OpenApiResult createResult (ResolverResult result) {
43-
Object document = result.getDocument ();
44-
Bucket api = new Bucket (result.getScope (), asMap (document));
45-
String version = getVersion (api);
46-
47-
if (isVersion30 (version)) {
48-
return new OpenApiResult30 (
49-
new Context (result.getScope (), result.getRegistry ()), api, result.getDocuments ());
50-
} else if (isVersion31 (version)) {
51-
return new OpenApiResult31 (
52-
new Context (result.getScope (), result.getRegistry ()), api, result.getDocuments ());
49+
private OpenApiResult parseVersion(URI baseUri, Object document) {
50+
String version = getVersion(baseUri, document);
51+
52+
if (isVersion30(version)) {
53+
return parse30(baseUri, document);
54+
55+
} else if (isVersion31(version)) {
56+
return parse31(baseUri, document);
57+
5358
} else {
54-
throw new UnknownVersionException (version);
59+
throw new UnknownVersionException(version);
5560
}
5661
}
5762

58-
private String getVersion (Bucket api) {
59-
return nonNull (api.convert (OPENAPI, new StringNotNullConverter ()));
63+
private OpenApiResult31 parse31(URI baseUri, Object document) {
64+
Resolver resolver = new Resolver(documents, loader);
65+
ResolverResult result = resolver.resolve(baseUri, document, new Resolver.Settings(SchemaVersion.Draft202012));
66+
67+
return new OpenApiResult31(
68+
new Context(result.getScope(), result.getRegistry()),
69+
Bucket.toBucket(result.getScope(), document),
70+
documents);
71+
}
72+
73+
private OpenApiResult30 parse30(URI baseUri, Object document) {
74+
Resolver resolver = new Resolver(documents, loader);
75+
ResolverResult result = resolver.resolve(baseUri, document, new Resolver.Settings(SchemaVersion.Draft4));
76+
77+
return new OpenApiResult30(
78+
new Context(result.getScope(), result.getRegistry()),
79+
Bucket.toBucket(result.getScope(), document),
80+
documents);
81+
}
82+
83+
private String getVersion(URI baseUri, Object document) {
84+
Scope scope = Scope.createScope(baseUri, document, SchemaVersion.getLatest());
85+
Bucket api = nonNull(Bucket.toBucket(scope, document));
86+
return api.convert (OPENAPI, new StringNotNullConverter ());
6087
}
6188

6289
private boolean isVersion30(String version) {

openapi-parser/src/main/java/io/openapiparser/ParserException.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,14 @@
55

66
package io.openapiparser;
77

8+
import java.net.URI;
9+
810
public class ParserException extends RuntimeException {
911
public ParserException (Exception e) {
1012
super("failed to parse OpenAPI description", e);
1113
}
14+
15+
public ParserException (URI documentUri, Exception e) {
16+
super(String.format("failed to parse OpenAPI description %s", documentUri) , e);
17+
}
1218
}

openapi-parser/src/test/kotlin/io/openapiparser/OpenApiBundlerSpec.kt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,9 @@ class OpenApiBundlerSpec : StringSpec({
2121

2222
fun resolve(documentUri: String): ResolverResult {
2323
val documents = DocumentStore()
24-
val loader = DocumentLoader(
25-
UriReader(),
26-
SnakeYamlConverter()
27-
)
28-
val resolver = Resolver(
29-
documents,
30-
loader,
31-
Resolver.Settings(SchemaVersion.Draft4)
32-
)
33-
return resolver.resolve(documentUri)
24+
val loader = DocumentLoader(UriReader(), SnakeYamlConverter())
25+
val resolver = Resolver(documents, loader)
26+
return resolver.resolve(documentUri, Resolver.Settings(SchemaVersion.Draft4))
3427
}
3528

3629
fun bundle30(result: ResolverResult): Bucket {

openapi-parser/src/test/kotlin/io/openapiparser/ValidateSpec.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,16 @@ import io.openapiprocessor.jsonschema.validator.Validator
1515
class ValidateSpec: StringSpec({
1616

1717
"validate openapi with \$ref into another file" {
18+
val documents = DocumentStore()
1819
val loader = DocumentLoader(
1920
UriReader(),
2021
SnakeYamlConverter()
2122
)
2223

23-
val documents = DocumentStore()
24-
val settings = Resolver.Settings (SchemaVersion.Draft4)
25-
val resolver = Resolver(documents, loader, settings)
26-
2724
val store = SchemaStore(loader)
2825
store.registerDraft4()
2926

30-
val parser = OpenApiParser(resolver)
27+
val parser = OpenApiParser(documents, loader)
3128
val result = parser.parse("/v30/ref-into-another-file/openapi.yaml")
3229

3330
val validator = Validator()

openapi-parser/src/test/kotlin/io/openapiparser/support/ApiBuilder.kt

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ class ApiBuilder {
2525
private var api: String? = null
2626
private lateinit var apiUri: URI
2727
private var converter: Converter = SnakeYamlConverter()
28-
private var documents: DocumentStore =
29-
DocumentStore()
28+
private var documents: DocumentStore = DocumentStore()
3029

3130
fun withApi(api: String): ApiBuilder {
3231
return withYaml("file:///any", api.trimIndent())
@@ -48,33 +47,25 @@ class ApiBuilder {
4847
}
4948

5049
fun buildParser(): OpenApiParser {
51-
return OpenApiParser(createResolver(SchemaVersion.Draft4))
50+
return OpenApiParser(documents, DocumentLoader(getReader(), converter))
5251
}
5352

5453
fun buildOpenApi30(): OpenApi30 {
55-
val resolver = createResolver(SchemaVersion.Draft4)
56-
val result = resolver.resolve(apiUri)
54+
val resolver = createResolver()
55+
val result = resolver.resolve(apiUri, Resolver.Settings(SchemaVersion.Draft4))
5756

5857
return OpenApi30(
5958
Context(result.scope, result.registry),
60-
Bucket(
61-
result.scope,
62-
Types.asMap(result.document)!!
63-
)
64-
)
59+
Bucket(result.scope, Types.asMap(result.document)!!))
6560
}
6661

6762
fun buildOpenApi31(): OpenApi31 {
68-
val resolver = createResolver(SchemaVersion.Draft201909) // todo
69-
val result = resolver.resolve(apiUri)
63+
val resolver = createResolver()
64+
val result = resolver.resolve(apiUri, Resolver.Settings(SchemaVersion.Draft201909))
7065

7166
return OpenApi31(
7267
Context(result.scope, result.registry),
73-
Bucket(
74-
result.scope,
75-
Types.asMap(result.document)!!
76-
)
77-
)
68+
Bucket(result.scope, Types.asMap(result.document)!!))
7869
}
7970

8071
fun <T> build(clazz: Class<T>): T {
@@ -85,25 +76,16 @@ class ApiBuilder {
8576
}
8677

8778
private fun <T> build(factory: (context: Context, bucket: Bucket) -> T): T {
88-
val resolver = createResolver(SchemaVersion.Draft4) // todo
89-
val result = resolver.resolve(apiUri)
79+
val resolver = createResolver()
80+
val result = resolver.resolve(apiUri, Resolver.Settings(SchemaVersion.Draft4))
9081

9182
return factory(
9283
Context(result.scope, result.registry),
93-
Bucket(
94-
result.scope,
95-
Types.asMap(result.document)!!
96-
)
97-
)
84+
Bucket(result.scope, Types.asMap(result.document)!!))
9885
}
9986

100-
private fun createResolver(version: SchemaVersion): Resolver {
101-
val loader = DocumentLoader(getReader(), converter)
102-
return Resolver(
103-
documents,
104-
loader,
105-
Resolver.Settings(version)
106-
)
87+
private fun createResolver(): Resolver {
88+
return Resolver(documents, DocumentLoader(getReader(), converter))
10789
}
10890

10991
private fun withYaml(baseUri: String, api: String): ApiBuilder {

0 commit comments

Comments
 (0)