Spring Boot Course
Spring Boot offers excellent support for building RESTful Web Services, making it a great choice for enterprise applications.
To start building a RESTful web service, add the Spring Boot Starter Web dependency to your project's build configuration file (pom.xml for Maven).
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
Lets see key annotations for RESTful Web Services.
Rest Controller
The @RestController annotation is used to define RESTful web services in Spring Boot. It combines @Controller and @ResponseBody, meaning it will handle HTTP requests and directly return data (usually in JSON or XML format) instead of views.
@RestController public class TaskController { // Define methods for handling requests here }
Request Mapping
The @RequestMapping annotation is used to define the Request URI for accessing the REST endpoints. It can also be used to specify the request method (GET, POST, etc.) and the media type to consume or produce.
@RestController @RequestMapping("/api/v1") // Base path for the controller public class TaskController { // Define endpoint methods here }
By default, @RequestMapping handles GET requests, but you can specify other HTTP methods using annotations like @GetMapping, @PostMapping, etc.
Request Parameter
The @RequestParam annotation is used to bind query parameters from the URI to method parameters.
Let's see an example to extract the query parameter page and size from the URL.
@Tag(name = "Task Controller", description = "Manage tasks") @RestController @RequestMapping("/api/v1") @RequiredArgsConstructor @Validated public class TaskController { private final TaskService taskService; /** * Retrieves all tasks with pagination. * * @param page the page number (zero-based) * @param size the number of tasks per page * @return paginated list of tasks wrapped in an API response with page metadata */ @Operation( summary = "Get all tasks", responses = { @ApiResponse(responseCode = "200", description = "Tasks retrieved successfully"), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "403", description = "Forbidden"), @ApiResponse(responseCode = "500", description = "Internal server error") } ) @GetMapping(value="/tasks") public ResponseEntity<ApiResult<List<TaskResponse>>> getAllTasks( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size ) { Page<TaskResponse> taskPage = taskService.getAllTasks(page, size); return buildResponse(taskPage); } /** * Builds a standardized API response for paginated results. * * @param page the Page object containing content and pagination metadata * @param <T> the type of the response data in the page * @return a ResponseEntity containing the standardized API result with page info */ private <T> ResponseEntity<ApiResult<List<T>>> buildResponse(Page<T> page) { return ResponseEntity.status(HttpStatus.OK).body(ApiResult.<List<T>>builder() .status(HttpStatus.OK.value()) .message("Tasks retrieved successfully") .data(page.getContent()) .timestamp(Instant.now()) .pageInfo(new PageInfo(page)) .build()); } }
If you visit http://localhost:8080/api/v1/tasks?page=0&size=1, the response will be:
{ "status": 200, "message": "Tasks retrieved successfully", "data": [ { "id": "e891c9de-804f-488f-9e3a-558aced274f2", "title": "Design UI mockups", "description": "Create wireframes for the new dashboard UI", "status": "TODO", "priority": "HIGH", "dueDate": "2025-06-18T20:31:32", "createdAt": "2025-06-14T02:04:28.732593", "updatedAt": "2025-06-14T02:04:28.732593" } ], "timestamp": "2025-06-23T20:43:25.145459700Z", "pageInfo": { "currentPage": 0, "pageSize": 1, "totalItems": 2, "totalPages": 2 } }
Path Variable
The @PathVariable annotation is used to extract values from the URI path.
Let's see an example to extract the id which is part of the URL path.
@Tag(name = "Task Controller", description = "Manage tasks") @RestController @RequestMapping("/api/v1") @RequiredArgsConstructor @Validated public class TaskController { private final TaskService taskService; /** * Retrieves a single task by its ID. * * @param id the UUID of the task * @return the task wrapped in an API response */ @Operation( summary = "Get task by ID", responses = { @ApiResponse(responseCode = "200", description = "Task retrieved successfully"), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "403", description = "Forbidden"), @ApiResponse(responseCode = "404", description = "Task not found"), @ApiResponse(responseCode = "500", description = "Internal server error") } ) @GetMapping("/tasks/{id}") public ResponseEntity<ApiResult<TaskResponse>> getTaskById(@PathVariable @NotNull UUID id) { TaskResponse task = taskService.getTaskById(id); return buildResponse(task, HttpStatus.OK, "Task retrieved successfully"); } /** * Builds a standardized API response for single or list results without pagination. * * @param data the response payload * @param status the HTTP status code * @param message the status message * @param <T> the type of the response data * @return a ResponseEntity containing the standardized API result */ private <T> ResponseEntity<ApiResult<T>> buildResponse(T data, HttpStatus status, String message) { return ResponseEntity.status(status).body(ApiResult.<T>builder() .status(status.value()) .message(message) .data(data) .timestamp(Instant.now()) .build()); } }
If you visit http://localhost:8080/api/v1/tasks/e891c9de-804f-488f-9e3a-558aced274f2, the response will be:
{ "status": 200, "message": "Task retrieved successfully", "data": { "id": "e891c9de-804f-488f-9e3a-558aced274f2", "title": "Design UI mockups", "description": "Create wireframes for the new dashboard UI", "status": "TODO", "priority": "HIGH", "dueDate": "2025-06-18T20:31:32", "createdAt": "2025-06-14T02:04:28.732593", "updatedAt": "2025-06-14T02:04:28.732593" }, "timestamp": "2025-06-23T20:52:54.884696100Z", "pageInfo": null }
Request Body
The @RequestBody annotation is used to bind the HTTP request body to a method parameter. This is commonly used for POST requests where the body contains data (usually JSON or XML) to be processed.
@Tag(name = "Task Controller", description = "Manage tasks") @RestController @RequestMapping("/api/v1/tasks") @RequiredArgsConstructor public class TaskController { private final TaskService taskService; /** * Creates a new task. * * @param taskRequest the task details * @return the created task wrapped in an API response */ @Operation( summary = "Create a single task", responses = { @ApiResponse(responseCode = "201", description = "Task created successfully"), @ApiResponse(responseCode = "401", description = "Unauthorized"), @ApiResponse(responseCode = "403", description = "Forbidden"), @ApiResponse(responseCode = "500", description = "Internal server error") } ) @PostMapping public ResponseEntity<ApiResult<TaskResponse>> createTask(@RequestBody @Valid TaskRequest taskRequest) { TaskResponse created = taskService.createTask(taskRequest); return buildResponse(created, HttpStatus.CREATED, "Task created successfully"); } /** * Builds a standardized API response for single or list results without pagination. * * @param data the response payload * @param status the HTTP status code * @param message the status message * @param <T> the type of the response data * @return a ResponseEntity containing the standardized API result */ private <T> ResponseEntity<ApiResult<T>> buildResponse(T data, HttpStatus status, String message) { return ResponseEntity.status(status).body(ApiResult.<T>builder() .status(status.value()) .message(message) .data(data) .timestamp(Instant.now()) .build()); } }
Let's post the request, http://localhost:8080/api/v1/tasks with below request body
{ "title": "Optimize database queries", "description": "Analyze and optimize slow queries to improve application performance", "status": "TODO", "priority": "HIGH", "dueDate": "2025-07-15T09:30:45.123456789Z" }
The response will be
{ "status": 201, "message": "Task created successfully", "data": { "id": "db00cb19-d1b5-4cee-bd70-bf62a5a00bba", "title": "Optimize database queries", "description": "Analyze and optimize slow queries to improve application performance", "status": "TODO", "priority": "HIGH", "dueDate": "2025-07-15T09:30:45.123456789Z", "createdAt": "2025-06-23T21:17:10.672691500Z", "updatedAt": "2025-06-23T21:17:10.672691500Z" }, "timestamp": "2025-06-23T21:17:10.812630800Z", "pageInfo": null }
To conclude, With Spring Boot, creating RESTful web services is straightforward and efficient. By using annotations like @RestController, @RequestMapping, @RequestParam, @PathVariable, and @RequestBody, you can quickly build enterprise-grade applications that serve JSON or XML data to clients.