Swagger UI

  1. Swagger UI is an interactive web page that displays your REST API and lets you call it directly from the browser.
  2. It is used so that developers and testers can explore endpoints, send real requests and see real responses without Postman.
  3. It reads the OpenAPI document (/v3/api-docs) and builds a clickable page from it automatically.
  4. In Spring Boot, the springdoc library serves Swagger UI at /swagger-ui.html with no extra code.

Features

  • Lists all endpoints, grouped by tag, with their methods and URLs.
  • Try it out button sends a real request to your running application.
  • Pre-filled request bodies, with a dropdown of example payloads.
  • Shows the response body, status code, headers and a ready-made curl command.
  • Displays the data model (schema) of each request and response.
  • Needs no separate tool or installation.

Annotations that shape what Swagger UI shows

  • @Tag names and describes a group of endpoints.
  • @Operation gives each endpoint a summary and description.
  • @ApiResponse lists the status codes an endpoint can return.
  • @Parameter describes a path variable or query parameter, with an example value.
  • @ExampleObject adds a ready-made request body to the dropdown in Swagger UI.
  • @Schema describes each field of the model and its example value.

Hands-on Experiment: Creating a spring boot application to understand how REST API endpoints can be formally described using the Swagger UI.

The following steps are involved in developing this hands-on experiment.

Step 1: Generate the Project

Step 2: Project Structure

Step 3: pom.xml

Step 4: application.properties

Step 5: Create Entity Class

Step 6: Create Repository Interface

Step 7: Create Service Class

Step 8: Create Controller Class

Step 9: Main Application Class

Step 10: Run the Main Application Class

Step 1: Configure the Project on Spring Initializr

Go to start.spring.io and set:

  • Project: Maven
  • Language: Java
  • Spring Boot version: 3.2.x
  • Group: com.example
  • Artifact: swaggerdemo
  • Name: swaggerdemo
  • Package name: com.example.swaggerdemo
  • Packaging: Jar
  • Java: 17
  • Dependencies: Spring Web, Spring Data JPA, MySQL Driver, SpringDoc OpenAPI.

Click Generate to download the ZIP, then extract and import it into your IDE as a Maven project.

Step 2: Generated Project Structure

Step 3: Explore pom.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.5</version>
        <relativePath/>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>student-swagger-demo</artifactId>
    <version>1.0.0</version>
    <name>student-swagger-demo</name>
    <description>Student CRUD operations explored and executed through Swagger UI</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-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- OpenAPI document generator + Swagger UI web page -->
        <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>

4. application.properties

spring.application.name=student-swagger-demo
server.port=8081

# MySQL (database is created automatically if it does not exist) - change username/password as needed
spring.datasource.url=jdbc:mysql://localhost:3306/studentdb?createDatabaseIfNotExist=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=password

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

# ---------- Swagger UI settings ----------
# Address of the Swagger UI page
springdoc.swagger-ui.path=/swagger-ui.html
# Address of the OpenAPI document that Swagger UI reads
springdoc.api-docs.path=/v3/api-docs
# Show the "Try it out" button on every endpoint
springdoc.swagger-ui.try-it-out-enabled=true
# Show how long each executed request took
springdoc.swagger-ui.display-request-duration=true
# Expand operations of each tag when the page opens (none | list | full)
springdoc.swagger-ui.doc-expansion=list
# Sort tags alphabetically and operations in the order of the methods in the code
springdoc.swagger-ui.tags-sorter=alpha
springdoc.swagger-ui.operations-sorter=methodCode language: PHP (php)

Step 5: Create Entity Class

package com.example.swaggerdemo.entity;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Schema(description = "Student details")
@Entity
@Table(name = "students")
public class Student {

    @Schema(description = "Auto-generated student id", example = "1", accessMode = Schema.AccessMode.READ_ONLY)
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Schema(description = "Full name of the student", example = "Ravi Kumar")
    private String name;

    @Schema(description = "Unique email address", example = "ravi@mail.com")
    @Column(unique = true)
    private String email;

    @Schema(description = "Department of the student", example = "CSE")
    private String department;

    public Student() {
    }

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

    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }

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

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

    public String getDepartment() { return department; }
    public void setDepartment(String department) { this.department = department; }
}

Step 6: Create below Repository Interface

package com.example.swaggerdemo.repository;

import com.example.swaggerdemo.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {

    boolean existsByEmail(String email);
}

Step 7: Create below Service class

package com.example.swaggerdemo.service;

import com.example.swaggerdemo.entity.Student;
import com.example.swaggerdemo.repository.StudentRepository;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;

@Service
public class StudentService {

    private final StudentRepository studentRepository;

    public StudentService(StudentRepository studentRepository) {
        this.studentRepository = studentRepository;
    }

    public Student addStudent(Student student) {
        if (studentRepository.existsByEmail(student.getEmail())) {
            throw new ResponseStatusException(HttpStatus.CONFLICT,
                    "Email already registered: " + student.getEmail());
        }
        return studentRepository.save(student);
    }

    public List<Student> getAllStudents() {
        return studentRepository.findAll();
    }

    public Student getStudentById(Long id) {
        return studentRepository.findById(id)
                .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND,
                        "Student not found with id: " + id));
    }

    public Student updateStudent(Long id, Student updated) {
        Student existing = getStudentById(id);
        existing.setName(updated.getName());
        existing.setDepartment(updated.getDepartment());
        return studentRepository.save(existing);
    }

    public void deleteStudent(Long id) {
        if (!studentRepository.existsById(id)) {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND,
                    "Student not found with id: " + id);
        }
        studentRepository.deleteById(id);
    }
}

Step 8: Create Controller class

package com.example.swaggerdemo.controller;

import com.example.swaggerdemo.entity.Student;
import com.example.swaggerdemo.service.StudentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Tag(name = "Student", description = "Create, read, update and delete students")
@RestController
@RequestMapping("/students")
public class StudentController {

    private final StudentService studentService;

    public StudentController(StudentService studentService) {
        this.studentService = studentService;
    }

    // CREATE - Swagger UI shows a dropdown with these ready-made request bodies
    @Operation(summary = "Create a student", description = "Creates a student. The email must be unique.")
    @io.swagger.v3.oas.annotations.parameters.RequestBody(
            content = @Content(mediaType = "application/json", examples = {
                    @ExampleObject(name = "CSE student",
                            value = "{\"name\":\"Ravi Kumar\",\"email\":\"ravi@mail.com\",\"department\":\"CSE\"}"),
                    @ExampleObject(name = "ECE student",
                            value = "{\"name\":\"Sita Devi\",\"email\":\"sita@mail.com\",\"department\":\"ECE\"}")
            }))
    @ApiResponses({
            @ApiResponse(responseCode = "201", description = "Student created"),
            @ApiResponse(responseCode = "409", description = "Email already registered", content = @Content)
    })
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Student addStudent(@RequestBody Student student) {
        return studentService.addStudent(student);
    }

    // READ ALL
    @Operation(summary = "Get all students")
    @ApiResponse(responseCode = "200", description = "List of all students")
    @GetMapping
    public List<Student> getAllStudents() {
        return studentService.getAllStudents();
    }

    // READ ONE
    @Operation(summary = "Get a student by id")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "Student found"),
            @ApiResponse(responseCode = "404", description = "Student not found", content = @Content)
    })
    @GetMapping("/{id}")
    public Student getStudentById(
            @Parameter(description = "Id of the student", example = "1") @PathVariable Long id) {
        return studentService.getStudentById(id);
    }

    // UPDATE
    @Operation(summary = "Update a student", description = "Updates name and department of an existing student")
    @io.swagger.v3.oas.annotations.parameters.RequestBody(
            content = @Content(mediaType = "application/json", examples = {
                    @ExampleObject(name = "Move to IT",
                            value = "{\"name\":\"Ravi Reddy\",\"email\":\"ravi@mail.com\",\"department\":\"IT\"}")
            }))
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "Student updated"),
            @ApiResponse(responseCode = "404", description = "Student not found", content = @Content)
    })
    @PutMapping("/{id}")
    public Student updateStudent(
            @Parameter(description = "Id of the student", example = "1") @PathVariable Long id,
            @RequestBody Student student) {
        return studentService.updateStudent(id, student);
    }

    // DELETE
    @Operation(summary = "Delete a student")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "Student deleted"),
            @ApiResponse(responseCode = "404", description = "Student not found", content = @Content)
    })
    @DeleteMapping("/{id}")
    public String deleteStudent(
            @Parameter(description = "Id of the student", example = "1") @PathVariable Long id) {
        studentService.deleteStudent(id);
        return "Student deleted with id: " + id;
    }
}

Step 9: Main Application

package com.example.swaggerdemo;

import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@OpenAPIDefinition(
        info = @Info(
                title = "Student CRUD API",
                version = "1.0",
                description = "Explore and execute Student CRUD operations from the Swagger UI page"
        )
)
@SpringBootApplication
public class SwaggerDemoApplication {

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

Step 10: Run the SwaggerDemoApplication

Scroll to Top