Show List

Using Swagger UI with Spring Boot Rest Web Service

Swagger helps to document the API. It provides the information such as the operations allowed. Parameters to pass and sample payload. It can be used for both top down and bottom up API development. In the top down approach the design is prepared first using the swagger UI and API is developed. In the bottom up approach, documentation is created after the API is developed. In this example, we are going to use bottom up approach to create the API documentation after the API is developed.

Below is the structure of the project we are going to create for this example
1. Go to Spring initializr website and create a Java Maven Project with dependencies: H2, Spring Data JPA and Web. Download the project zip and extract to a folder.

2. Import the project into IDE (I am using IntelliJ Idea). Add the springdoc-openapi-ui dependency in the Pom.xml. This is the library that will generate the documentation for swagger UI.

The <parent> element specifies the parent project from which this project inherits configurations. In this case, the parent is spring-boot-starter-parent with version 2.7.3. The <groupId>, <artifactId>, and <version> elements define the unique identifier, name, and version of the project being built. In this example, the project has the group ID com.example, artifact ID demo, and version 0.0.1-SNAPSHOT.

The <name> and <description> elements provide a name and description for the project, respectively.

The <properties> element allows defining project-specific properties. In this case, it sets the java.version property to 11, indicating that the project uses Java 11.

The <dependencies> section lists the project's dependencies. Dependencies are defined using <dependency> elements.

  • spring-boot-starter-data-jpa is a starter dependency for working with Spring Data JPA.
  • h2 is a runtime dependency for the H2 in-memory database.
  • springdoc-openapi-ui is a dependency for adding OpenAPI (Swagger) documentation and UI support to the Spring Boot project. Version 1.6.4 is specified.
  • spring-boot-starter-test is a starter dependency for writing tests in a Spring Boot application.
  • spring-boot-starter-web is a starter dependency for building web applications using Spring MVC.
<?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>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
2. Create Student class in the com.example.demo.model package. 
  • The @Entity annotation indicates that the Student class is an entity that can be persisted to a database.
  • The @Table annotation specifies the table name associated with the entity. In this case, the table name is assumed to be the same as the class name ("Student").
  • The class provides two constructors: An empty default constructor (public Student()) that can be used to create instances of the Student class without providing any initial values for the fields. A parameterized constructor (public Student(String name, String grade)) that allows initializing the name and grade fields when creating an instance of the Student class.
  • The class provides getter and setter methods for accessing and modifying the private fields.
package com.example.demo.model;

import javax.persistence.*;

@Entity
@Table
public class Student {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int student_id;
private String name;
private String grade;

public Student(){

}
public Student( String name, String grade) {
this.name = name;
this.grade = grade;
}

public int getStudent_id() {
return student_id;
}

public void setStudent_id(int student_id) {
this.student_id = student_id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getGrade() {
return grade;
}

public void setGrade(String grade) {
this.grade = grade;
}
}
3. Create StudentRepo class extending CrudRepository. CrudRepository will provide the Create, Read, Update and Delete methods.
package com.example.demo.dao;

import com.example.demo.model.Student;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepo extends CrudRepository<Student, Long> {}
4. Create controller class StudentController. 

The @RestController annotation indicates that this class serves as a RESTful controller that handles HTTP requests and returns the response directly to the client.
The controller defines several HTTP request mapping methods to handle different operations:
  • getAllStudents(): Handles a GET request to the /students endpoint and returns a list of all students by invoking the findAll() method of the repository.
  • getStudents(Long id): Handles a GET request to the /student/{id} endpoint (where {id} is a path variable) and returns an Optional<Student> by invoking the findById() method of the repository with the provided id.
  • addStudent(Student newStudent): Handles a POST request to the /students endpoint and saves a new student by invoking the save() method of the repository with the provided newStudent object. It returns the saved student.
  • removeStudent(Long id): Handles a DELETE request to the /students/{id} endpoint (where {id} is a path variable) and deletes the student with the given id by invoking the deleteById() method of the repository.
  • updateStudent(Student newStudent, Long id): Handles a PUT request to the /students/{id} endpoint (where {id} is a path variable) and updates an existing student. It first tries to find the student with the given id using the findById() method of the repository. If the student exists, it updates the student's name and grade with the values from newStudent and saves it using the save() method of the repository. If the student doesn't exist, it sets the student_id of newStudent based on the provided id and saves it as a new student.
package com.example.demo.controller;

import com.example.demo.dao.StudentRepo;
import com.example.demo.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
public class StudentController {

@Autowired
private StudentRepo repo;

@GetMapping("/students")
private List<Student> getAllStudents(){
return (List<Student>) repo.findAll();
}

@GetMapping("/student/{id}")
private Optional<Student> getStudents(@PathVariable Long id){
return repo.findById(id);
}

@PostMapping("/students")
private Student addStudent(@RequestBody Student newStudent){
return repo.save(newStudent);
}

@DeleteMapping("/students/{id}")
private void removeStudent(@PathVariable Long id){
repo.deleteById(id);
}

@PutMapping("/students/{id}")
private Student updateStudent(@RequestBody Student newStudent, @PathVariable Long id){
return repo.findById(id)
.map(student -> {
student.setName(newStudent.getName());
student.setGrade(newStudent.getGrade());
return repo.save(student);
})
.orElseGet(() -> {
newStudent.setStudent_id(Math.toIntExact(id));
return repo.save(newStudent);
});
}
}
5. Create LoadData class in the com.example.demo.dataload package to load sample data in the H2 database when the application loads.

  • The LoadData class implements the ApplicationRunner interface, which allows you to perform certain tasks when the Spring Boot application starts.
  • The LoadData class has a dependency on the StudentRepo interface, which is likely a repository interface for performing CRUD operations on the Student entity.
  • The @Autowired annotation is used to inject an instance of the StudentRepo into the class, allowing access to the repository methods.
  • The run(ApplicationArguments args) method is overridden from the ApplicationRunner interface and is executed when the Spring Boot application starts.
  • Within the run() method, several Student objects are created with different names and grades, and they are saved to the database using the save() method of the repository. This is done to populate some initial data into the Student table.
 package com.example.demo.dataload;

import com.example.demo.dao.StudentRepo;
import com.example.demo.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;

@Configuration
public class LoadData implements ApplicationRunner {

@Autowired
StudentRepo repo;

@Override
public void run(ApplicationArguments args) throws Exception {
repo.save(new Student("Ana", "One"));
repo.save(new Student("Bob", "Two"));
repo.save(new Student("Charlie", "One"));
repo.save(new Student("David", "Three"));
}
}

6. Add below line in the application.properties file under resources folder. This will make JPA queries appear in the log
 spring.jpa.show-sql=true
7. Run the Spring Boot application and test using web service client (such as Postman)
"C:\Program Files\Java\jdk-11.0.15\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2\lib\idea_rt.jar=65505:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\mail2\Downloads\Spring-Boot-angular-full-stack\target\classes;D:\.m2\repository\org\springframework\boot\spring-boot-starter-data-jpa\2.7.3\spring-boot-starter-data-jpa-2.7.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-aop\2.7.3\spring-boot-starter-aop-2.7.3.jar;D:\.m2\repository\org\springframework\spring-aop\5.3.22\spring-aop-5.3.22.jar;D:\.m2\repository\org\aspectj\aspectjweaver\1.9.7\aspectjweaver-1.9.7.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-jdbc\2.7.3\spring-boot-starter-jdbc-2.7.3.jar;D:\.m2\repository\com\zaxxer\HikariCP\4.0.3\HikariCP-4.0.3.jar;D:\.m2\repository\org\springframework\spring-jdbc\5.3.22\spring-jdbc-5.3.22.jar;D:\.m2\repository\jakarta\transaction\jakarta.transaction-api\1.3.3\jakarta.transaction-api-1.3.3.jar;D:\.m2\repository\jakarta\persistence\jakarta.persistence-api\2.2.3\jakarta.persistence-api-2.2.3.jar;D:\.m2\repository\org\hibernate\hibernate-core\5.6.10.Final\hibernate-core-5.6.10.Final.jar;D:\.m2\repository\org\jboss\logging\jboss-logging\3.4.3.Final\jboss-logging-3.4.3.Final.jar;D:\.m2\repository\net\bytebuddy\byte-buddy\1.12.13\byte-buddy-1.12.13.jar;D:\.m2\repository\antlr\antlr\2.7.7\antlr-2.7.7.jar;D:\.m2\repository\org\jboss\jandex\2.4.2.Final\jandex-2.4.2.Final.jar;D:\.m2\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;D:\.m2\repository\org\hibernate\common\hibernate-commons-annotations\5.1.2.Final\hibernate-commons-annotations-5.1.2.Final.jar;D:\.m2\repository\org\glassfish\jaxb\jaxb-runtime\2.3.6\jaxb-runtime-2.3.6.jar;D:\.m2\repository\org\glassfish\jaxb\txw2\2.3.6\txw2-2.3.6.jar;D:\.m2\repository\com\sun\istack\istack-commons-runtime\3.0.12\istack-commons-runtime-3.0.12.jar;D:\.m2\repository\com\sun\activation\jakarta.activation\1.2.2\jakarta.activation-1.2.2.jar;D:\.m2\repository\org\springframework\data\spring-data-jpa\2.7.2\spring-data-jpa-2.7.2.jar;D:\.m2\repository\org\springframework\data\spring-data-commons\2.7.2\spring-data-commons-2.7.2.jar;D:\.m2\repository\org\springframework\spring-orm\5.3.22\spring-orm-5.3.22.jar;D:\.m2\repository\org\springframework\spring-context\5.3.22\spring-context-5.3.22.jar;D:\.m2\repository\org\springframework\spring-tx\5.3.22\spring-tx-5.3.22.jar;D:\.m2\repository\org\springframework\spring-beans\5.3.22\spring-beans-5.3.22.jar;D:\.m2\repository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;D:\.m2\repository\org\springframework\spring-aspects\5.3.22\spring-aspects-5.3.22.jar;D:\.m2\repository\com\h2database\h2\2.1.214\h2-2.1.214.jar;D:\.m2\repository\org\springdoc\springdoc-openapi-ui\1.6.4\springdoc-openapi-ui-1.6.4.jar;D:\.m2\repository\org\springdoc\springdoc-openapi-webmvc-core\1.6.4\springdoc-openapi-webmvc-core-1.6.4.jar;D:\.m2\repository\org\springdoc\springdoc-openapi-common\1.6.4\springdoc-openapi-common-1.6.4.jar;D:\.m2\repository\io\swagger\core\v3\swagger-core\2.1.12\swagger-core-2.1.12.jar;D:\.m2\repository\org\apache\commons\commons-lang3\3.12.0\commons-lang3-3.12.0.jar;D:\.m2\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.13.3\jackson-dataformat-yaml-2.13.3.jar;D:\.m2\repository\io\swagger\core\v3\swagger-annotations\2.1.12\swagger-annotations-2.1.12.jar;D:\.m2\repository\io\swagger\core\v3\swagger-models\2.1.12\swagger-models-2.1.12.jar;D:\.m2\repository\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;D:\.m2\repository\org\webjars\swagger-ui\4.1.3\swagger-ui-4.1.3.jar;D:\.m2\repository\org\webjars\webjars-locator-core\0.50\webjars-locator-core-0.50.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.13.3\jackson-core-2.13.3.jar;D:\.m2\repository\io\github\classgraph\classgraph\4.8.138\classgraph-4.8.138.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter\2.7.3\spring-boot-starter-2.7.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot\2.7.3\spring-boot-2.7.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.7.3\spring-boot-autoconfigure-2.7.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.7.3\spring-boot-starter-logging-2.7.3.jar;D:\.m2\repository\ch\qos\logback\logback-classic\1.2.11\logback-classic-1.2.11.jar;D:\.m2\repository\ch\qos\logback\logback-core\1.2.11\logback-core-1.2.11.jar;D:\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;D:\.m2\repository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;D:\.m2\repository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;D:\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\.m2\repository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;D:\.m2\repository\jakarta\xml\bind\jakarta.xml.bind-api\2.3.3\jakarta.xml.bind-api-2.3.3.jar;D:\.m2\repository\jakarta\activation\jakarta.activation-api\1.2.2\jakarta.activation-api-1.2.2.jar;D:\.m2\repository\org\springframework\spring-core\5.3.22\spring-core-5.3.22.jar;D:\.m2\repository\org\springframework\spring-jcl\5.3.22\spring-jcl-5.3.22.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-web\2.7.3\spring-boot-starter-web-2.7.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-json\2.7.3\spring-boot-starter-json-2.7.3.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.13.3\jackson-databind-2.13.3.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.13.3\jackson-annotations-2.13.3.jar;D:\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.3\jackson-datatype-jdk8-2.13.3.jar;D:\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.3\jackson-datatype-jsr310-2.13.3.jar;D:\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.3\jackson-module-parameter-names-2.13.3.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\2.7.3\spring-boot-starter-tomcat-2.7.3.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.65\tomcat-embed-core-9.0.65.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.65\tomcat-embed-el-9.0.65.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.65\tomcat-embed-websocket-9.0.65.jar;D:\.m2\repository\org\springframework\spring-web\5.3.22\spring-web-5.3.22.jar;D:\.m2\repository\org\springframework\spring-webmvc\5.3.22\spring-webmvc-5.3.22.jar;D:\.m2\repository\org\springframework\spring-expression\5.3.22\spring-expression-5.3.22.jar com.example.demo.DemoApplication

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.3)

2022-09-10 17:26:34.654  INFO 6556 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication using Java 11.0.15 on sm15 with PID 6556 (C:\Users\mail2\Downloads\Spring-Boot-angular-full-stack\target\classes started by mail2 in C:\Users\mail2\Downloads\Spring-Boot-angular-full-stack)
2022-09-10 17:26:34.658  INFO 6556 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to 1 default profile: "default"
2022-09-10 17:26:35.770  INFO 6556 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2022-09-10 17:26:35.838  INFO 6556 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 56 ms. Found 1 JPA repository interfaces.
2022-09-10 17:26:36.734  INFO 6556 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-09-10 17:26:36.747  INFO 6556 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-09-10 17:26:36.748  INFO 6556 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.65]
2022-09-10 17:26:36.882  INFO 6556 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-09-10 17:26:36.882  INFO 6556 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2155 ms
2022-09-10 17:26:37.079  INFO 6556 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2022-09-10 17:26:37.343  INFO 6556 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2022-09-10 17:26:37.417  INFO 6556 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2022-09-10 17:26:37.515  INFO 6556 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.6.10.Final
2022-09-10 17:26:37.749  INFO 6556 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2022-09-10 17:26:37.928  INFO 6556 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
Hibernate: drop table if exists student CASCADE 
Hibernate: create table student (student_id integer generated by default as identity, grade varchar(255), name varchar(255), primary key (student_id))
2022-09-10 17:26:38.586  INFO 6556 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2022-09-10 17:26:38.597  INFO 6556 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2022-09-10 17:26:39.059  WARN 6556 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2022-09-10 17:26:39.995  INFO 6556 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-09-10 17:26:40.006  INFO 6556 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 5.908 seconds (JVM running for 6.558)
Hibernate: insert into student (student_id, grade, name) values (default, ?, ?)
Hibernate: insert into student (student_id, grade, name) values (default, ?, ?)
Hibernate: insert into student (student_id, grade, name) values (default, ?, ?)
Hibernate: insert into student (student_id, grade, name) values (default, ?, ?)


Swagger UI can be accessed from http://localhost:8080/swagger-ui/index.html
Sample request and response can be viewed by going to the operations:


Source Code:
https://github.com/NumeroUnoDeveloper/swagger-with-Spring-Boot

    Leave a Comment


  • captcha text