DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • The Pros and Cons of API-Led Connectivity
  • 3 Reasons for the Mounting Demand for Smart Cloud-Native Application Development
  • Manage Microservices With Docker Compose
  • Split the Monolith: What, When, How

Trending

  • Strategies for Securing E-Commerce Applications
  • Designing AI Multi-Agent Systems in Java
  • Yet Another GenAI Nightmare: Seven Shadow AI Pitfalls to Avoid
  • How Kubernetes Cluster Sizing Affects Performance and Cost Efficiency in Cloud Deployments
  1. DZone
  2. Data Engineering
  3. Databases
  4. Get More Transparency on Your Microservices API With OpenAPI

Get More Transparency on Your Microservices API With OpenAPI

By 
Otavio Santana user avatar
Otavio Santana
DZone Core CORE ·
Aug. 03, 20 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
7.0K Views

Join the DZone community and get the full member experience.

Join For Free

Every Friday, Platform.sh has a nice tech discussion about several discussions, such as Jakarta EE, Payara, Quarkus, and so on (To check the calendar you can click here). On Episode number 15 there was a great discussion about Open API and Postman. That's worth watching if you don't yet.

First, let's start with Open API definition, from the website it says:

The OpenAPI Specification (OAS) defines a standard, language-agnostic interface to RESTful APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined, a consumer can understand and interact with the remote service with a minimal amount of implementation logic.

Hello World Open API With Postman

To absorb that knowledge and practice what we learned from this episode, let's create a Hello world Open API and then test it with Postman. We'll create a small Java API that will handle all Deploy-Fridays episodes and store it on MongoDB. Why do we want to use MongoDB? Just because we're hipsters!!

We're going to be using Eclipse MicroProfile. This will make our life easier when we want to create a microservices application. In this tutorial, we'll use Helidon version 2.0. To integrate with a NoSQL database let's use Jakarta NoSQL.

Eclipse MicroProfile has a subproject to integrate with Open API that's annotation-driven.

Annotation

Description

@APIResponses

A container for multiple responses from an API operation. This annotation is optional, but it can be helpful to organize a method with multiple responses.

@APIResponse

Describes a single response from an API operation.

@Content

Provides a schema and examples for a particular media type.

@Schema

Defines the input and output data types.

@Operation

Describes a single API operation on a path.

@Parameter

Describes a single operation parameter.


Let's start with the entities; remember that those entities will also be the data inputs, so we'll define them as a schema.

As you can see in the code, beyond the Eclipse MicroProfile Open API annotations, there are also the Jakarta NoSQL entities annotations and JSON Binding to check the fields instead of methods.

Java
xxxxxxxxxx
1
53
 
1
import jakarta.nosql.mapping.Column;
2
import jakarta.nosql.mapping.Entity;
3
import jakarta.nosql.mapping.Id;
4
import org.eclipse.microprofile.openapi.annotations.media.Schema;
5
6
import javax.json.bind.annotation.JsonbVisibility;
7
import java.util.Set;
8
9
@Schema(name = "Episode", description = "The entity that represents Episode")
10
@Entity
11
@JsonbVisibility(FieldVisibility.class)
12
public class Episode {
13
14
    @Schema(required = true, name = "id", description = "The episode ID", example = "1")
15
    @Id
16
    private Long id;
17
18
    @Column
19
    @Schema(required = true, name = "url", description = "The episode URL", example = "https://www.youtube.com/playlist?list=PLn5EpEMtxTCmLsbLgaN3djvEkRdp-YmlE")
20
    private String url;
21
22
    @Schema(required = true, description = "the hosts")
23
    @Column
24
    private Set<String> hosts;
25
26
    @Schema(required = true, description = "the guests")
27
    @Column
28
    private Set<Guest> guests;
29
30
}
31
32
import jakarta.nosql.mapping.Column;
33
import jakarta.nosql.mapping.Entity;
34
import org.eclipse.microprofile.openapi.annotations.media.Schema;
35
36
import javax.json.bind.annotation.JsonbVisibility;
37
import java.util.Objects;
38
39
@Schema(name = "Guest", description = "The entity that represents Guest")
40
@Entity
41
@JsonbVisibility(FieldVisibility.class)
42
public class Guest {
43
44
    @Schema(required = true, description = "The guest name", example = "Ada Lovelace")
45
    @Column
46
    private String name;
47
48
    @Schema(required = true, description = "The guest twitter handle", example = "adalovelace")
49
    @Column
50
    private String twitter;
51
52
}
53


After creating the entity, the next step to create the resource. As the usual JAX-RS annotation to define the path and the HTTP verbs such as GET, POST, and DELETE, there are also the Open API annotations.

Java
xxxxxxxxxx
1
101
 
1
import org.eclipse.microprofile.openapi.annotations.Operation;
2
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
3
import org.eclipse.microprofile.openapi.annotations.media.Content;
4
import org.eclipse.microprofile.openapi.annotations.media.Schema;
5
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
6
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
7
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
8
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
9
10
import javax.enterprise.context.ApplicationScoped;
11
import javax.inject.Inject;
12
import javax.ws.rs.Consumes;
13
import javax.ws.rs.DELETE;
14
import javax.ws.rs.GET;
15
import javax.ws.rs.POST;
16
import javax.ws.rs.Path;
17
import javax.ws.rs.PathParam;
18
import javax.ws.rs.Produces;
19
import javax.ws.rs.WebApplicationException;
20
import javax.ws.rs.core.MediaType;
21
import javax.ws.rs.core.Response;
22
import java.util.Optional;
23
import java.util.logging.Logger;
24
25
@Path("episodes")
26
@ApplicationScoped
27
@Consumes(MediaType.APPLICATION_JSON)
28
@Produces(MediaType.APPLICATION_JSON)
29
public class EpisodeResource {
30
31
    private static final Logger LOGGER = Logger.getLogger(EpisodeResource.class.getName());
32
33
    @Inject
34
    private EpisodeRepository repository;
35
36
    @GET
37
    @Operation(summary = "Get all episodes", description = "Returns all available episodes")
38
    @APIResponse(responseCode = "500", description = "Server unavailable")
39
    @APIResponse(responseCode = "200", description = "The episodes")
40
    @Tag(name = "BETA", description = "This API is currently in beta state")
41
    @APIResponse(description = "The episodes",
42
            responseCode = "200",
43
            content = @Content(mediaType = MediaType.APPLICATION_JSON,
44
                    schema = @Schema(implementation = Episodes.class,
45
                            readOnly = true,
46
                            description = "the episodes",
47
                            required = true,
48
                            name = "Episodes")))
49
    public Episodes getAll() {
50
        return new Episodes(repository.findAll());
51
    }
52
53
    @GET
54
    @Path("{id}")
55
    @Operation(summary = "Find an episode by id", description = "Find an episode by id")
56
    @APIResponse(responseCode = "200", description = "The episodes")
57
    @APIResponse(responseCode = "404", description = "When the id does not exist")
58
    @APIResponse(responseCode = "500", description = "Server unavailable")
59
    @Tag(name = "BETA", description = "This API is currently in beta state")
60
    @APIResponse(description = "The episode",
61
            content = @Content(mediaType = MediaType.APPLICATION_JSON,
62
                    schema = @Schema(implementation = Episode.class)))
63
    public Episode findById(@Parameter(description = "The Episode ID", required = true,
64
            example = "1", schema = @Schema(type = SchemaType.INTEGER)) @PathParam("id") Long id) {
65
66
        LOGGER.info("Finds episode by id: " + id);
67
        final Optional<Episode> episode = repository.findById(id);
68
        return episode.orElseThrow(() -> new WebApplicationException(Response.Status.NOT_FOUND));
69
    }
70
71
72
    @POST
73
    @Operation(summary = "Insert an Episode", description = "Insert an Episode")
74
    @APIResponse(responseCode = "201", description = "When creates an episode")
75
    @APIResponse(responseCode = "500", description = "Server unavailable")
76
    @Tag(name = "BETA", description = "This API is currently in beta state")
77
    public void insert(@RequestBody(description = "Create a new Episode.",
78
            content = @Content(mediaType = "application/json",
79
                    schema = @Schema(implementation = Episode.class))) Episode episode) {
80
        LOGGER.info("Episode: " + episode);
81
        repository.save(episode);
82
    }
83
84
    @DELETE
85
    @Path("{id}")
86
    @Operation(summary = "Delete an episode by ID", description = "Delete an episode by ID")
87
    @APIResponse(responseCode = "200", description = "When deletes the episode")
88
    @APIResponse(responseCode = "404", description = "When the id does not exist")
89
    @APIResponse(responseCode = "500", description = "Server unavailable")
90
    @Tag(name = "BETA", description = "This API is currently in beta state")
91
    @APIResponse(description = "The episode",
92
            content = @Content(mediaType = MediaType.APPLICATION_JSON,
93
                    schema = @Schema(implementation = Episode.class)))
94
    public void delete(@Parameter(description = "The Episode ID", required = true,
95
            example = "1", schema = @Schema(type = SchemaType.INTEGER))
96
                       @PathParam("id") Long id) {
97
        LOGGER.info("Deletes episode by id: " + id);
98
        repository.deleteById(id);
99
    }
100
}
101


The code is ready, to run locally let's use Docker with the command below:

Shell
xxxxxxxxxx
1
 
1
docker run -d --name mongodb-instance -p 27017:27017 mongo


The application is ready, and with MongoDB instance running, you can execute the application:

Shell
xxxxxxxxxx
1
 
1
mvn clean package
2
java -jar target/deploy-friday-ep15.jar


When the application is running, you can access the URL http://localhost:8080/openapi/ to get the open API result.

Let's go to the Postman to test your API; the first step is to import the API from the URL that we already showed.

Let's go to the Postman to test your API. The first step is to install the application itself where it has support for Linux, Windows or Mac OS. When we installed the Postman application, the next step is to import the API from the Open API URL.

It works like magic, don't forget to set the variables inside Postman.

Cloud: To Infinity and Beyond With Platform.sh

The application is ready to go, and you can run the application.  The next step is to move to the cloud with Platform.sh.

 To move your application to the cloud, briefly, you need three files:

 One to define the routes: 

YAML
xxxxxxxxxx
1
 
1
"https://{default}/":
2
  type: upstream
3
  upstream: "app:http"
4
5
"https://www.{default}/":
6
  type: redirect
7
  to: "https://{default}/"


One file to define the services that you need in your application.

To point out, you don't need to worry to handle it. Platform.sh will be the infrastructure for you.

YAML
 




xxxxxxxxxx
1


 
1
mongodb:
2
  type: mongodb:3.6
3
  disk: 1024



The last file is to configure the application, basically, you'll teach how to build and execute your application to Platform.sh. In this sample, we'll create a Java 11 container,  build with a maven command, and start the application from an uberjar.

YAML
xxxxxxxxxx
1
10
 
1
name: app
2
type: "java:11"
3
disk: 1024
4
hooks:
5
  build: mvn clean package
6
relationships:
7
  mongodb: 'mongodb:mongodb'
8
web:
9
  commands:
10
    start: java -jar $JAVA_OPTS $CREDENTIAL -Dserver.port=$PORT target/deploy-friday-ep15.jar


As you can see, we set the CREDENTIAL environment. The goal is to overwrite the database credentials on the cloud, so we can have a configuration to run locally and another one to run in the cloud with Platform.sh.

Shell
xxxxxxxxxx
1
 
1
export MONGO_PORT=`echo $PLATFORM_RELATIONSHIPS|base64 -d|json_pp|jq -r ".mongodb[0].port"`
2
export MONGO_HOST=`echo $PLATFORM_RELATIONSHIPS|base64 -d|json_pp|jq -r ".mongodb[0].host"`
3
export MONGO_ADDRESS="${MONGO_HOST}:${MONGO_PORT}"
4
export MONGO_PASSWORD=`echo $PLATFORM_RELATIONSHIPS|base64 -d|json_pp|jq -r ".mongodb[0].password"`
5
export MONGO_USER=`echo $PLATFORM_RELATIONSHIPS|base64 -d|json_pp|jq -r ".mongodb[0].username"`
6
export MONGO_DATABASE=`echo $PLATFORM_RELATIONSHIPS|base64 -d|json_pp|jq -r ".mongodb[0].path"`
7
export JAVA_MEMORY=-Xmx$(jq .info.limits.memory /run/config.json)m
8
export JAVA_OPTS="$JAVA_MEMORY -XX:+ExitOnOutOfMemoryError"
9
export CREDENTIAL="-Ddocument.settings.jakarta.nosql.host=$MONGO_ADDRESS -Ddocument.database=$MONGO_DATABASE -Ddocument.settings.jakarta.nosql.user=$MONGO_USER -Ddocument.settings.jakarta.nosql.password=$MONGO_PASSWORD -Ddocument.settings.mongodb.authentication.source=$MONGO_DATABASE"


The application is now ready, so it’s time to move it to the cloud with Platform.sh using the following steps:

  • Create a new free trial account.

  • Sign up with a new user and password, or login using a current GitHub, Bitbucket, or Google account. If you use a third-party login, you’ll be able to set a password for your Platform.sh account later.

  • Select the region of the world where your site should live.

  • Select the blank template.

You have the option to either integrate to GitHub, GitLab, or Platform.sh will provide it to you. Finally, push to the remote repository.

The example is ready and in a GitHub repository.

That is it; we finished a tutorial about how to integrate and connect a Java application with Open API and test with Postman. Stay tuned to the next Deploy Friday episodes.

API application microservice

Opinions expressed by DZone contributors are their own.

Related

  • The Pros and Cons of API-Led Connectivity
  • 3 Reasons for the Mounting Demand for Smart Cloud-Native Application Development
  • Manage Microservices With Docker Compose
  • Split the Monolith: What, When, How

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!