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.
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