URLs
-
Project home (this page)
Do you want to improve this page? Please edit it on GitHub. |
Description
Eclipse MicroProfile OpenAPI is a standardisation effort around OpenAPI.
In particular, it offers an API to model OpenAPI specification (interfaces in the org.eclipse.microprofile.openapi.models
package and sub-packages).
This repository contains different projects (implementations and utilities) for this API. Providing a complete vendor implementation for the Eclipse MicroProfile OpenAPI is out-of-scope.
---
openapi: 3.0.1
info:
title: Ping Specification
version: "1.0"
servers:
- url: http://localhost:8000/
paths:
/ping:
get:
operationId: pingGet
responses:
"200":
description: OK
A typical OpenAPI specification as presented in Listing 1 can be created in Java using Eclipse MicroProfile OpenAPI project with the code presented in Listing 2.
import static org.eclipse.microprofile.openapi.OASFactory.*;
import org.eclipse.microprofile.openapi.models.OpenAPI;
public final class PingSpec {
public static OpenAPI create() {
return createOpenAPI()
.openapi("3.0.1")
.info(
createInfo()
.title("Ping Specification")
.version("1.0")
)
.addServer(
createServer()
.url("http://localhost:8000/")
)
.paths(
createPaths()
.addPathItem(
"/ping", createPathItem()
.GET(
createOperation()
.operationId("pingGet")
.responses(
createAPIResponses()
.addAPIResponse(
"200", createAPIResponse()
.description("OK")
)
)
)
)
);
}
}
The code in Listing 2 requires only microprofile-openapi-api
to be on the classpath (see Listing 3 for the complete maven coordinates).
<dependency>
<groupId>org.eclipse.microprofile.openapi</groupId>
<artifactId>microprofile-openapi-api</artifactId>
<version>2.0</version>
</dependency>
All EMPOA projects of this repository (EMPOA stands for Eclipse MicroProfile OpenAPI) are based on the interfaces representing OpenAPI specifications from the Eclipse MicroProfile OpenAPI project. Either by implementing them (see Implementation projects) or by providing additional features (see Serializer projects and Other projects).
Implementation projects
Without any implementation on the classpath, the code presented in Listing 2 will throw an exception IllegalStateException
(see Listing 4 for the stacktrace).
java.lang.IllegalStateException: No OASFactoryResolver implementation found!
at org.eclipse.microprofile.openapi.spi.OASFactoryResolver.instance(OASFactoryResolver.java:77)
at org.eclipse.microprofile.openapi.OASFactory.createObject(OASFactory.java:49)
at org.openapitools.empoa.extended.tck.specs.PingSpec.create(PingSpec.java:16)
at ...
This is why you need to provide one implementation on your classpath.
EMPOA Simple models
<dependency>
<groupId>org.openapitools.empoa</groupId>
<artifactId>empoa-simple-models-impl</artifactId>
<version>2.1.0</version>
</dependency>
This project provides a simple implementation for the interfaces defined in the org.eclipse.microprofile.openapi.models
package and sub-packages.
The implementation are simple POJO.
There is no dependency to any other frameworks.
EMPOA Swagger-Core
<dependency>
<groupId>org.openapitools.empoa</groupId>
<artifactId>empoa-swagger-core</artifactId>
<version>2.1.0</version>
</dependency>
Swagger-Core is a well known library to handle OpenAPI specification in Java. Swagger-Parser is using this representation when serializing and deserializing JSON or YAML files.
This project provides a simple implementation for the interfaces defined in the org.eclipse.microprofile.openapi.models
package and sub-packages by delegating all methods to Swagger-Core object.
It can be used as a bridge between both libraries.
One usage could be a project programmed on top of the Eclipse MicroProfile APIs but using Swagger-Parser to parse OpenAPI Specifications,
As for any other implementation project of the Eclipse MicroProfile APIs, the org.eclipse.microprofile.openapi.OASFactory
can be used to create OpenAPI instance programmatically (making usage of Swagger-Core invisible).
An other approach, if you have an existing instance of Swagger-Core models (for example the output of Swagger-Parser), org.openapitools.empoa.swagger.core.internal.SwAdapter
can be used as proposed in Listing 7.
io.swagger.v3.oas.models.OpenAPI swaggerOpenAPI = parserResult.getOpenAPI();
OpenAPI openAPI = SwAdapter.toOpenAPI(swaggerOpenAPI);
If you are looking for factory methods where no Swagger project elements are part of the method signature, you can use org.openapitools.empoa.swagger.core.SwOASFactory
.
Its createObject(Object)
method expects the Swagger instance that will be wrapped in the corresponding object implementing the Eclipse MicroProfile interface.
The Swagger library (io.swagger.core.v3:swagger-models
) is only an "implementation" dependency.
Serializer projects
Given an OpenAPI specification represented by instances of objects implementing the Eclipse MicroProfile OpenAPI interfaces (org.eclipse.microprofile.openapi.models
package and sub-packages), you can use one of the following projects to serialize them to JSON or YAML.
Those projects work only with the API interfaces and are not bound to a specific implementation.
EMPOA Gson Serializer
<dependency>
<groupId>org.openapitools.empoa</groupId>
<artifactId>empoa-gson-serializer</artifactId>
<version>2.1.0</version>
</dependency>
This project is using Gson to serialize classes implementing the Eclipse MicroProfile OpenAPI interfaces (org.eclipse.microprofile.openapi.models
package and sub-pacakges) to JSON.
The code presented in Listing 9 shows how the library can be used to serialize an org.eclipse.microprofile.openapi.models.OpenAPI
to JSON
Gson gson = OASGsonSerializer.instance();
String json = gson.toJson(openAPI);
EMPOA Jackson Serializer
<dependency>
<groupId>org.openapitools.empoa</groupId>
<artifactId>empoa-jackson-serializer</artifactId>
<version>2.1.0</version>
</dependency>
This project is using Jackson to serialize classes implementing the Eclipse MicroProfile OpenAPI interfaces (org.eclipse.microprofile.openapi.models
package and sub-pacakges) to YAML or JSON.
It is adapted from the SmallRye OpenAPI project.
The code presented in Listing 11 shows how the library can be used to serialize an org.eclipse.microprofile.openapi.models.OpenAPI
to JSON.
String json = OpenAPISerializer.serialize(openAPI, OpenAPISerializer.Format.JSON);
Other projects
EMPOA Javapoet
<dependency>
<groupId>org.openapitools.empoa</groupId>
<artifactId>empoa-javapoet</artifactId>
<version>2.1.0</version>
</dependency>
Javapoet is a library that can be used to generate Java code.
Given an instance of org.eclipse.microprofile.openapi.models.OpenAPI
(or of any other interface in the org.eclipse.microprofile.openapi.models
package or sub-packages), this project is using Javapoet to create the corresponding java-code to recreate an other instance holding the same values.
The code presented in Listing 13 shows how code can be generated: a complete class holding a single static method create()
is generated.
JavaFile javaFile = JavaFileConverter.createOpenAPI(openAPI, packageName, className);
String javaCode = javaFile.toString();
The methods in a second class org.openapitools.empoa.javapoet.CodeBlockConverter
might be useful to create only the CodeBlock
corresponding to the generated OASFactory.createObject(..)
code.
EMPOA Util
<dependency>
<groupId>org.openapitools.empoa</groupId>
<artifactId>empoa-util</artifactId>
<version>2.1.0</version>
</dependency>
This project is adding some features to the Eclipse MicroProfile OpenAPI interfaces (org.eclipse.microprofile.openapi.models
package and sub-pacakges):
Visitor pattern
If you need to apply a visitor pattern approach to an OpenAPI specification, you can implement the OASVisitor
interface or extends the OASVisitorAdapter
class.
Then all the accept methods are defined in the OASAccept
class.
When the visit(..)
method is called for a member of the OpenAPI specification, in addition to the instance of the object, you also get the JSONPath value that you could use to navigate to this object when the specification is serialized to JSON.
Example:
If you want to collect all operationId
of all operations, you can use a visitor as implemented in Listing 15.
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.microprofile.openapi.models.Components;
import org.eclipse.microprofile.openapi.models.Operation;
public class OperationIdVisitor extends OASVisitorAdapter {
private Map<String, String> operationIds = new HashMap<>();
public Map<String, String> getOperationIds() {
return Collections.unmodifiableMap(operationIds);
}
@Override
public OASVisitResult visit(Operation operation, String jsonPath) {
operationIds.put(jsonPath + ".operationId", operation.getOperationId()); (1)
return OASVisitResult.CONTINUE; (2)
}
@Override
public OASVisitResult visit(Components components, String jsonPath) {
return OASVisitResult.TERMINATE; (3)
}
}
1 | Store the jsonPath and the operationId value in the map. |
2 | Indicates to continue with with the traversal of the OpenAPI specification |
3 | Indicates to stop, because we do not need to check the entities inside the components section |
For a given OpenAPI specification, this visitor can be used to collect all the values as presented in Listing 16.
OperationIdVisitor visitor = new OperationIdVisitor();
OASAccept.accept(visitor, openAPI); (1)
Map<String, String> operationIds = visitor.getOperationIds();
1 | Start visiting the OpenAPI tree |
After visiting the simple Ping
specification (see the OpenAPI file: ping.json on GitHub), the operationIds
map contains one single entry:
-
key:
$.paths.['/ping'].get.operationId
-
value:
pingGet
Equals utility
The OASEquals
utility checks if two instances of an OpenAPI element are equals or not, from an OpenAPI point of view (regardless of the implementation of their equals
methods).
They are considered equals if they produce the same JSON or YAML tree when they are serialized.
See Listing 17 for a usage example.
Schema firstSchema;
Schema secondSchema;
// ... instantiate the 'firstSchema' and 'secondSchema' variables
boolean equals = OASEquals.equals(firstSchema, secondSchema);
Copy utility
The OASCopy
utility class creates a copy of a given OpenAPI element instance.
See Listing 18 for a usage example.
PathItem original;
// ... instantiate the 'original' variable
PathItem copy = OASCopy.copy(original);
Merge utility
The OASMerge
utility provides methods to merge the content of one element of an OpenAPI specification into an other element of the same type.
Only non-null values are copied.
Maps are merged (if two entry have the same key those items are merged).
List are also merged: items of the list are added only if they are not already present.
See Listing 19 for a usage example.
Operation fromOperation;
Operation intoOperation;
// ... instantiate the 'fromOperation' and 'intoOperation' variables
OASMerge.merge(fromOperation, intoOperation);
Helper projects
EMPOA Extended TCK
<dependency>
<groupId>org.openapitools.empoa</groupId>
<artifactId>empoa-extended-tck</artifactId>
<version>2.1.0</version>
</dependency>
This project contains some abstract test classes that add additional TCK tests.
Those tests ensure that the implementations are working properly.
They are complementary (and sometime also redundant) with the official TCK tests provided in org.eclipse.microprofile.openapi.tck.ModelConstructionTest
.
EMPOA SmallRye
This project is used to validate the 'EMPOA Extended TCK' project with an independent implementation.
Download
The artifacts are hosted on maven central.
Snapshots version are hosted in the sonatype repository:
https://oss.sonatype.org/content/repositories/snapshots/
Build
This project is using gradle.
Command to build the sources locally:
./gradlew build
Command to deploy to your local maven repository:
./gradlew publishToMavenLocal
Command to build the documentation page:
./gradlew asciidoctor
The output of this command is an HTML page located at <git repo root>/build/docs/html5/index.html
.
For project maintainers
signing.gnupg.keyName
and signing.gnupg.passphrase
are expected to be set in your local gradle.properties
file to be able to sign.
sonatypeUser
and sonatypePassword
are expected to be set in order to be able to publish to a distant repository.
Command to build and publish the result to maven central:
./gradlew publishToSonatype
Command to upload the documentation page on GitHub pages:
./gradlew gitPublishPush
Command to perform a release:
./gradlew release -Prelease.useAutomaticVersion=true
Using ssh-agent
Some tasks requires to push into the distant git repository (release task or updating the gh-pages
branch).
If they are failing with errors like this:
org.eclipse.jgit.api.errors.TransportException: ... Permission denied (publickey).
Then ssh-agent
can be used.
eval `ssh-agent -s` ssh-add ~/.ssh/id_rsa
(source for this approach)
Get in touch
Use the issue tracker on GitHub.
You can also contact me on Twitter: @j2r2b