Swagger Core Tutorial
In this article, we will see what Swagger Core is and what it is used for.
1. Introduction
The OpenAPI specification defines the standard of describing HTTP API for any project. This is programming-language agnostic. This helps humans and computers to know about the System/API without the need to look into the code. If the specification is properly implemented it helps a consumer to understand the interaction with the remote system effectively without much hassle.
OpenAPI specification can be compared to an Interface in Java. Interfaces in Java define the contract between the client and the server. It tells the caller what it needs to send and the expected value which will be returned. This helps the caller to reduce the guesswork. Similarly, OpenAPI is a specification that defines how to document your HTTP API so that the consumer of your API has to do minimal guesswork.
One of the big use cases for a machine-readable API definition is to automatically generate the Client code. The OpenAPI documents are generally described in YAML or JSON. The best part is that these documents can be created statically or generated at runtime. One this to note is that OpenAPI can not be integrated with all the available HTPP API implementations – but they are available for RESTful HTTP Apis. The current version of OpenAPI specification is 3.1.0.
2. Swagger Core
Swagger Core is an open-source Java implementation of the Swagger/OpenAPI specification. Swagger uses Maven for build and deployment and its artifacts are available at Maven Central. Integrating swagger-core into a JAX-RS application can be as easy as adding its dependency to the project POM:
<dependency> <groupid>io.swagger.core.v3</groupid> <artifactid>swagger-jaxrs2</artifactid> <version>2.1.1</version> </dependency> <dependency> <groupid>io.swagger.core.v3</groupid> <artifactid>swagger-jaxrs2-servlet-initializer</artifactid> <version>2.1.1</version> </dependency>
Consider a simple JAX-RS application with an endpoint like below:
@Path("/customer") public class CustomerResource { @GET @Path("/customers/{customerId}") @Produces("application/json") public Customer getCustomer(@PathParam("customerId") Long customerId) { // return Customer details } @POST @Consumes("application/json") public Response addCustomer( @Parameter(description = "New customer details", required = true) Customer newCustomer) { // add new customer return Response.ok().entity("SUCCESS").build(); } }
Just by adding the dependencies, an endpoint <baseUrl>/<contextRoot>/openapi.json
is activated, exposing the OpenAPI definition of the app APIs serialized as json or yaml, as resolved by swagger-core
processing JAX-RS resources defined in the application. If you hit this endpoint your response will look similar to:
openapi: 3.0.1 paths: /sample/customer/{customerId}: get: operationId: getCustomer parameters: - name: customerId in: path required: true schema: type: integer format: int64 responses: default: description: default response content: application/json: schema: $ref: '#/components/schemas/Customer' application/xml: schema: $ref: '#/components/schemas/Customer' /sample/customer: post: operationId: addCustomer requestBody: description: New customer details content: application/json: schema: $ref: '#/components/schemas/Customer' required: true responses: default: description: default response content: application/json: {} application/xml: {} components: schemas: Tag: type: object properties: id: type: integer format: int64 name: type: string xml: name: Tag Customer: type: object properties: id: type: integer format: int64 name: type: string tags: type: array xml: wrapped: true items: $ref: '#/components/schemas/Tag' xml: name: Customer
While the Swagger resolver mechanism is able to analyze resource classes structure and various annotations there are cases where metadata is simply not available (for example determining the response schema of an operation, when the resource method is returning an instance of JAX-RS Response instead of a model POJO) and/or we want to completely customize the definition. To handle this and other cases, and to be able to have full control over the resolved API definition, usage of Swagger annotations comes in handy.
Annotations can be applied to resource classes and whatever model POJOs (particularly used in this context is the @Schema
annotation. You can refer to the full list of available annotations here.
Once an API definition is available, you might want to visualize it in a nice UI, and interact with it, for example testing the endpoint with an actual call. Such functionality is provided by swagger-UI which is nicely integrated with swagger-core
3. Conclusion
In this article, we learned about OpenAPI specifications. We then looked into how to implement this specification using Swagger. We also discussed a working example and saw how the swagger-API response to a simple REST API will look like. Please note that the above example uses the default configuration, you can provide your own configuration as well. To do that you will need to create a file named openapi.yaml or openapi-configuration.yaml in the classpath of your application.