work in progress
It is usable, but has the following limitations at the moment:
-
it does support most but not all OpenAPI object properties
-
minimal documentation (just this README)
source code gifts (i.e pull requests) are welcome :-)
a Java 11 based OpenAPI 3.0.x & 3.1 parser with validation and pluggable document reader & json/yaml converter.
-
parse OpenAPI 3.0.x & 3.1
-
validate OpenAPI 3.0.x & 3.1 (handles $ref’s in the OpenAPI document)
-
JSON schema draft-4 validation of OpenAPI 3.0
-
JSON schema draft-2020-12 validation of OpenAPI 3.1
-
-
separate apis for OpenAPI 3.0 & 3.1
-
easily get resolved $ref object
-
minimal dependencies
-
pluggable document reader
-
pluggable json/yaml converter
-
pluggable
formatvalidators (planned)
the parser tries to provide a user-friendly api in the sense that it
-
minimizes null values where possible
-
throws if required properties are not set
-
it is read only
-
it resolves
$refobjects, i.e. $ref objects have agetRefObject() -
it is very close to the specification (OpenAPI 3.0 & 3.1)
Drawback is, that with the current api it is not possible (for some properties) to detect if a property is set in the OpenAPI description or if it is not given.
It is easy to create an alternative raw api that is based on the structure of the OpenAPI description that provides the raw values of the properties.
I’m not sure yet if I want to mix raw and user-friendly in a single api. Do we need both styles at the same time?
for example, the usr-friendly model.v30.OpenApi (model.v31.OpenApi) model object has a method
Info getInfo ();
to create a raw api
it is possible to extend the existing api with
Info getInfoRaw ();
or to change the existing api to use Optional
Optional<Info> getInfo ();
or to create a new api model.v30r.OpenApi with a @Nullable signature
@Nullable Info getInfo ();
Minimizing null values means that
-
for a missing/optional array properties it will return an empty collection
-
for other missing/optional properties it will return the default value if any is specified by the OpenAPI specification
For example the required property of a parameter has a false default value and the api will return false in case required is not explicitly set in the OpenAPI description.
the parser is internally using Map<String, Object> to represent the OpenAPI object tree to be independent of a specific yaml/json parser. It will work with any yaml/json parser that is able to convert an OpenAPI yaml or json to a Map<String, Object> object tree.
io-jackson provides a default implementation that is based on jackson.
code example for parsing an OpenAPI yaml file and running the JSON Schema validation.
this removes the Resolver from the previous (i.e 2023.2) setup at step 2.
package io.openapiparser;
import io.openapiparser.model.v30.OpenApi;
import io.openapiparser.model.v30.PathItem;
import io.openapiprocessor.interfaces.Converter;
import io.openapiprocessor.interfaces.Reader;
import io.openapiprocessor.jsonschema.reader.UriReader;
import io.openapiprocessor.jsonschema.schema.*;
import io.openapiprocessor.jsonschema.validator.Validator;
import io.openapiprocessor.jsonschema.validator.ValidatorSettings;
import io.openapiprocessor.snakeyaml.SnakeYamlConverter;
import org.junit.jupiter.api.Test;
import java.util.Collection;
public class SetupExampleTest {
//@Test
void parseAndValidate () {
// 1. create a document loader.
// It loads a document by uri and converts it to a Map<String, Object>
// object tree that represents the OpenAPI document. The parser
// operates on that Object tree which makes it independent of the
// object mapper (e.g. jackson, snakeyaml etc.).
// Both (Reader and Converter) have a very simple interface which makes
// it easy to implement your own.
Reader reader = new UriReader ();
Converter converter = new SnakeYamlConverter ();
// Converter converter = new JacksonConverter ();
DocumentLoader loader = new DocumentLoader (reader, converter);
// 2. create a parser.
DocumentStore documents = new DocumentStore ();
OpenApiParser parser = new OpenApiParser (documents, loader);
// 3. parse the OpenAPI from resource or url.
// here it loads an OpenAPI document from a resource file, but URI works too.
OpenApiResult result = parser.parse ("openapi.yaml");
// 4. get the API model from the result to navigate the OpenAPI document.
// OpenAPI 3.1.x with model.v31.OpenAPI import
OpenApi model = result.getModel (OpenApi.class);
// 5. navigate the model
PathItem pathItem = model.getPaths ().getPathItem ("/foo");
// 6. create Validator to validate the OpenAPI schema.
SchemaStore store = new SchemaStore (loader);
ValidatorSettings settings = new ValidatorSettings ();
Validator validator = new Validator (settings);
// 7. validate the OpenAPI schema.
boolean valid = result.validate (validator, store);
// 8. print validation errors
Collection<ValidationError> errors = result.getValidationErrors ();
ValidationErrorTextBuilder builder = new ValidationErrorTextBuilder ();
for (ValidationError error : errors) {
System.out.println (builder.getText(error));
}
}
}package io.openapiparser;
import io.openapiparser.model.v30.OpenApi;
import io.openapiparser.model.v30.PathItem;
import io.openapiprocessor.interfaces.Converter;
import io.openapiprocessor.interfaces.Reader;
import io.openapiprocessor.jsonschema.reader.UriReader;
import io.openapiprocessor.jsonschema.schema.*;
import io.openapiprocessor.jsonschema.validator.Validator;
import io.openapiprocessor.jsonschema.validator.ValidatorSettings;
import io.openapiprocessor.snakeyaml.SnakeYamlConverter;
import org.junit.jupiter.api.Test;
import java.util.Collection;
public class SetupExampleTest {
@Test
void parseAndValidate () {
// 1. create a document loader.
// It loads a document by uri and converts it to a Map<String, Object>
// object tree that represents the OpenAPI document. The parser
// operates on that Object tree which makes it independent of the
// object mapper (e.g. jackson, snakeyaml etc.).
// Both (Reader and Converter) have a very simple interface which makes
// it easy to implement your own.
Reader reader = new UriReader ();
Converter converter = new SnakeYamlConverter ();
// Converter converter = new JacksonConverter ();
DocumentLoader loader = new DocumentLoader (reader, converter);
// 2. create a resolver.
// it is responsible for resolving the $ref'erences in the OpenAPI document.
// The Settings object is initialized with the JSON schema version used by
// OpenAPI (here Draft 4 for OpenAPI 3.0.x).
DocumentStore documents = new DocumentStore ();
Resolver.Settings resolverSettings = new Resolver.Settings (SchemaVersion.Draft4);
Resolver resolver = new Resolver (documents, loader, resolverSettings);
// 3. parse the OpenAPI from resource or url.
// here it loads an OpenAPI document from a resource file, but URI works too.
OpenApiParser parser = new OpenApiParser (resolver);
OpenApiResult result = parser.parse ("openapi.yaml");
// 4. get the API model from the result to navigate the OpenAPI document.
// OpenAPI 3.1.x with model.v31.OpenAPI import
OpenApi model = result.getModel (OpenApi.class);
// 5. navigate the model
PathItem pathItem = model.getPaths ().getPathItem ("/foo");
// 6. create Validator to validate the OpenAPI schema.
SchemaStore store = new SchemaStore (loader);
ValidatorSettings settings = new ValidatorSettings ();
Validator validator = new Validator (settings);
// 7. validate the OpenAPI schema.
boolean valid = result.validate (validator, store);
// 8. print validation errors
Collection<ValidationError> errors = result.getValidationErrors ();
ValidationErrorTextBuilder builder = new ValidationErrorTextBuilder ();
for (ValidationError error : errors) {
System.out.println (builder.getText(error));
}
}
}import io.openapiparser.jackson.JacksonConverter;
import io.openapiparser.model.v30.OpenApi;
import io.openapiparser.reader.UriReader;
import io.openapiparser.schema.*;
import io.openapiparser.snakeyaml.SnakeYamlConverter;
import io.openapiparser.validator.Validator;
import io.openapiparser.validator.ValidatorSettings;
import io.openapiparser.validator.result.*;
public class Example {
void parseAndValidate () {
// setup resolver (handles documents and $refs)
Reader reader = new UriReader ();
DocumentStore documents = new DocumentStore ();
Converter converter = new SnakeYamlConverter ();
// Converter converter = new JacksonConverter ();
Resolver resolver = new Resolver (reader, converter, documents);
// parser OpenAPI file or url
OpenApiParser parser = new OpenApiParser (resolver);
OpenApiResult result = parser.parse ("openapi.yaml");
// OpenAPI 3.1.x with model.v31.OpenAPI import
OpenApi model = result.getModel (OpenApi.class);
// validate OpenAPI
SchemaStore store = new SchemaStore (resolver);
ValidatorSettings settings = new ValidatorSettings ();
Validator validator = new Validator (settings);
boolean valid = result.validate (validator, store);
// print validation messages (i.e. errors)
MessageCollector collector = new MessageCollector (result.getValidationMessages ());
LinkedList<Message> messages = collector.collect ();
MessageTextBuilder builder = new MessageTextBuilder ();
for (Message message : messages) {
System.out.println (builder.getText(message));
}
}
}