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

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Extending Swagger and Springdoc Open API
  • DDD and Spring Boot Multi-Module Maven Project
  • Be Punctual! Avoiding Kotlin’s lateinit In Spring Boot Testing
  • Exploring Hazelcast With Spring Boot

Trending

  • Ethical AI in Agile
  • Agentic AI for Automated Application Security and Vulnerability Management
  • From Zero to Production: Best Practices for Scaling LLMs in the Enterprise
  • How to Practice TDD With Kotlin
  1. DZone
  2. Coding
  3. Frameworks
  4. OpenAPI 3 Documentation With Spring Boot

OpenAPI 3 Documentation With Spring Boot

In this tutorial, try out a Spring Boot Open API 3-enabled REST project and explore some of its capabilities.

By 
Raghuraman Ramaswamy user avatar
Raghuraman Ramaswamy
DZone Core CORE ·
Updated Apr. 17, 24 · Tutorial
Likes (16)
Comment
Save
Tweet
Share
116.7K Views

Join the DZone community and get the full member experience.

Join For Free

Java adoption has shifted from version 1.8 to at least Java 17. Concurrently, Spring Boot has advanced from version 2.x to 3.2.2. The springdoc project has transitioned from the older library 'springdoc-openapi-ui' to 'springdoc-openapi-starter-webmvc-ui' for its functionality. These updates mean that readers relying on older articles may find themselves years behind in these technologies. The author has updated this article so that readers are using the latest versions and don't struggle with outdated information during migration. 


This is part one of a three-part series. You can check out the other articles below.

  1. OpenAPI 3 Documentation With Spring Boot
  2. Doing More With Springdoc OpenAPI
  3. Extending Swagger and Springdoc Open API

In this tutorial, we are going to try out a Spring Boot Open API 3-enabled REST project and explore some of its capabilities. The springdoc-openapi Java library has quickly become very compelling.

We are going to refer to Building a RESTful Web Service and springdoc-openapi v2.5.0.

Prerequisites

  • Java 17.x
  • Maven 3.x

Steps

Start by creating a Maven JAR project. Below, you will see the pom.xml to use:

XML
 
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.2.2</version>
		<relativePath ></relativePath> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>sample</artifactId>
	<version>0.0.1</version>
	<name>sample</name>
	<description>Demo project for Spring Boot with openapi 3 documentation</description>
	<properties>
		<java.version>17</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springdoc</groupId>
			<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
			<version>2.5.0</version>
		</dependency>
		
		
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>


Note the "springdoc-openapi-starter-webmvc-ui" dependency.

Now, let's create a small Java bean class. 

Java
 
package sample;

import org.hibernate.validator.constraints.CreditCardNumber;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;


public class Person {
   
	private long id;
    private String firstName;
    @NotNull
    @NotBlank
    private String lastName;
    @Pattern(regexp = ".+@.+\\..+", message = "Please provide a valid email address" )
    private String email;
    @Email()
    private String email1;
    @Min(18)
    @Max(30)
    private int age;
    @CreditCardNumber
    private String creditCardNumber;

    public String getCreditCardNumber() {
        return creditCardNumber;
    }

    public void setCreditCardNumber(String creditCardNumber) {
        this.creditCardNumber = creditCardNumber;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
    public String getEmail1() {
        return email1;
    }

    public void setEmail1(String email1) {
        this.email1 = email1;
    }

    @Size(min = 2)
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {

        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
-


This is an example of a Java bean. Now, let's create a controller.

Java
 
package sample;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import jakarta.validation.Valid;

@RestController
public class PersonController {
	@RequestMapping(path = "/person", method = RequestMethod.POST)
	@io.swagger.v3.oas.annotations.parameters.RequestBody(required = true, content = @Content(examples = {
			@ExampleObject(value = INVALID_REQUEST, name = "invalidRequest", description = "Invalid Request"),
			@ExampleObject(value = VALID_REQUEST, name = "validRequest", description = "Valid Request") }))
	public Person person(@Valid @RequestBody Person person) {
		return person;
	}

	private static final String VALID_REQUEST = """
			{
			  "id": 0,
			  "firstName": "string",
			  "lastName": "string",
			  "email": "abc@abc.com",
			  "email1": "abc@abc.com",
			  "age": 20,
			  "creditCardNumber": "4111111111111111"
			}""";

	private static final String INVALID_REQUEST = """
			{
			  "id": 0,
			  "firstName": "string",
			  "lastName": "string",
			  "email": "abcabc.com",
			  "email1": "abcabc.com",
			  "age": 17,
			  "creditCardNumber": "411111111111111"
			}""";
}
-


Above is a sample REST Controller.

Side Note: Normally I don't like to clutter already annotation-cluttered code with additional annotations, but I do think having ready-made examples like these can be useful. Another reason that forced me to do this was the default examples now generated from Swagger UI appear to be generating some confusing text when using @Pattern. It appears to be a Spring UI issue and not a Springdoc issue.

Let's make some entries in src\main\resources\application.properties.

Properties files
 
application-description=@project.description@
application-version=@project.version@
logging.level.org.springframework.boot.autoconfigure=ERROR
# server.error.include-binding-errors is now needed if we 
# want to display the errors as shown in this article
# this can also be avoided in other ways as we will see 
# in later articles
server.error.include-binding-errors=always


The above entries will pass on Maven build-related information to the OpenAPI documentation and also include the new server.error.include-binding-errors property.

Finally, let's write the Spring Boot application class:

Java
 
package sample;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;

@SpringBootApplication
public class SampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SampleApplication.class, args);
    }

    @Bean
    public OpenAPI customOpenAPI(@Value("${application-description}") String appDesciption, 
    		@Value("${application-version}") String appVersion) {
     return new OpenAPI()
          .info(new Info()
          .title("sample application API")
          .version(appVersion)
          .description(appDesciption)
          .termsOfService("http://swagger.io/terms/")
          .license(new License().name("Apache 2.0").url("http://springdoc.org")));
    }
}
-


Also, note how the API version and description are being leveraged from application.properties.

At this stage, this is what the project looks like in Eclipse:

Project in Eclipse

The project contents are above. Next, execute the mvn clean package from the command prompt or terminal. Then, execute java -jar target\sample-0.0.1.jar.

You can also launch the application by running the SampleApplication.java class from your IDE.

Now, let's visit the Swagger UI — http://localhost:8080/swagger-ui.html.

Sample application with Swagger

Click the green Post button and expand the > symbol on the right of Person under Schemas.

Click the green Post button and expand the > symbol on the right of Person under Schemas

Let's expand the last schemas section a bit more:

Expansion of last schema section

The nice thing is how the contract is automatically detailed leveraging JSR-303 annotations on the model. It out-of-the-box covers many of the important annotations and documents them. However, I did not see it support out of the box @javax.validation.constraints.Email and @org.hibernate.validator.constraints.CreditCardNumber at this point. The issue is that they are not documented in the generated Swagger specs, but those constraints are functional. We will discuss more on this in the subsequent article.

For completeness, let's post a request. Press the Try it out button.

Post a request

Press the blue Execute button.

Click blue execute button

Let's feed in a valid input by copying the below or by selecting the valid Input drop-down.

JSON
 
{
  "id": 0,
  "firstName": "string",
  "lastName": "string",
  "email": "abc@abc.com",
  "email1": "abc@abc.com",
  "age": 20,
  "creditCardNumber": "4111111111111111"
}


Let's feed that valid input into the Request body section. (We can also select "validRequest" from the Examples dropdown as shown below.)

Feeding valid input into the Request Body section.

Upon pressing the blue Execute button, we see the below:

Output of execution

This was only a brief introduction to the capabilities of the dependency:

XML
 
<dependency>
		<groupId>org.springdoc</groupId>
		<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
		<version>2.5.0</version>
</dependency>


Troubleshooting Tips

  • Ensure prerequisites.
  • If using the Eclipse IDE, we might need to do a Maven update on the project after creating all the files.
  • In the Swagger UI, if you are unable to access the “Schema” definitions link, it might be because you need to come out of the “try it out “ mode. Click on one or two Cancel buttons that might be visible.
  • Source code
  • Git Clone URL, Branch: springdoc-openapi-intro-update1.
Spring Framework Spring Boot Java (programming language) Apache Maven

Opinions expressed by DZone contributors are their own.

Related

  • Extending Swagger and Springdoc Open API
  • DDD and Spring Boot Multi-Module Maven Project
  • Be Punctual! Avoiding Kotlin’s lateinit In Spring Boot Testing
  • Exploring Hazelcast With Spring Boot

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!