<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Arshad M Patel</title>
    <description>The latest articles on Forem by Arshad M Patel (@arshadpatel).</description>
    <link>https://forem.com/arshadpatel</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3637227%2F124a1bff-d25d-46a9-a58a-ecb005fca6aa.jpeg</url>
      <title>Forem: Arshad M Patel</title>
      <link>https://forem.com/arshadpatel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/arshadpatel"/>
    <language>en</language>
    <item>
      <title>Implementing a RESTful Web API with Spring Boot</title>
      <dc:creator>Arshad M Patel</dc:creator>
      <pubDate>Sun, 14 Dec 2025 10:34:45 +0000</pubDate>
      <link>https://forem.com/arshadpatel/implementing-a-restful-web-api-with-spring-boot-2241</link>
      <guid>https://forem.com/arshadpatel/implementing-a-restful-web-api-with-spring-boot-2241</guid>
      <description>&lt;p&gt;Building a REST API is one of the most essential skills for any backend developer. Spring Boot makes this incredibly simple by providing a production-ready environment with minimal configuration. In this article, we’ll walk through the core concepts of REST and how to implement a clean, scalable REST API using Spring Boot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RESTful API?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;REST (Representational State Transfer) is an architectural style that defines a set of rules for creating scalable web services. REST APIs use HTTP methods like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GET – Retrieve data&lt;/li&gt;
&lt;li&gt;POST – Create data&lt;/li&gt;
&lt;li&gt;PUT – Update data&lt;/li&gt;
&lt;li&gt;DELETE – Remove data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;REST APIs are stateless, meaning each request is independent and contains all required information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What We Are Going to Build?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this project, we will build a &lt;strong&gt;Task Tracker REST API&lt;/strong&gt; using Spring Boot. The goal is to design a clean, meaningful, and production-ready API that allows users to manage their daily tasks efficiently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Endpoints We Will Build (with Use Cases)&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create a Task &lt;code&gt;POST /api/tasks&lt;/code&gt;&lt;br&gt;
Use case: Add a new task with title, description, category, and default status as PENDING.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get All Tasks &lt;code&gt;GET /api/tasks&lt;/code&gt;&lt;br&gt;
Use case: Retrieve all tasks available in the system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get Task by ID &lt;code&gt;GET /api/tasks/{id}&lt;/code&gt;&lt;br&gt;
Use case: Fetch details of a single task using its ID.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update a Task &lt;code&gt;PUT /api/tasks/{id}&lt;/code&gt;&lt;br&gt;
Use case: Modify a task’s details such as title, description, category, or status.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Delete a Task &lt;code&gt;DELETE /api/tasks/{id}&lt;/code&gt;&lt;br&gt;
Use case: Remove a task from the system.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get Tasks by Status &lt;code&gt;GET /api/tasks/status/{status}&lt;/code&gt;&lt;br&gt;
Use case: Filter tasks based on their status — PENDING, COMPLETED.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Database Used : H2 In-Memory Database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For simplicity and ease of demonstration, we will use H2 in-memory database, which allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero installation&lt;/li&gt;
&lt;li&gt;Automatic console UI&lt;/li&gt;
&lt;li&gt;Fast development&lt;/li&gt;
&lt;li&gt;Easy testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note : It resets on application restart, which is perfect for tutorial purposes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To build a clean and maintainable REST API, we follow a layered architecture consisting of three main layers: &lt;strong&gt;Controller&lt;/strong&gt; (handles incoming API requests), &lt;strong&gt;Service&lt;/strong&gt; (contains business logic), and &lt;strong&gt;Repository&lt;/strong&gt; (manages database interactions). Now that we understand what we’re building, let’s begin with the Controller layer and implement all our endpoints one by one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnophr7x2geqt2qix788w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnophr7x2geqt2qix788w.png" alt="Structure of our project" width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting Up the Project
&lt;/h3&gt;

&lt;p&gt;Now that we understand our architecture and API structure, let’s start building the application. The first step is to create a Spring Boot project with the necessary dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Create a New Spring Boot Project&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Head over to Spring Initializr at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;https://start.spring.io/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here, we will generate a fresh Spring Boot project with all the required configurations.&lt;/p&gt;

&lt;p&gt;Fill in the following project details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project: Maven&lt;/li&gt;
&lt;li&gt;Language: Java&lt;/li&gt;
&lt;li&gt;Spring Boot Version: Latest stable version&lt;/li&gt;
&lt;li&gt;Group: com.example (or your preferred package)&lt;/li&gt;
&lt;li&gt;Artifact: task-tracker-api&lt;/li&gt;
&lt;li&gt;Name: Task Tracker API&lt;/li&gt;
&lt;li&gt;Packaging: Jar&lt;/li&gt;
&lt;li&gt;Java Version: 17 or above&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Add the Required Dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To build a functional REST API, we need to add the following dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring Web - Allows us to create REST controllers and expose HTTP endpoints.&lt;/li&gt;
&lt;li&gt;Spring Data JPA - Helps us interact with the database in an easy, ORM-based way.&lt;/li&gt;
&lt;li&gt;H2 Database - A lightweight in-memory database ideal for development and testing.&lt;/li&gt;
&lt;li&gt;Lombok - Reduces boilerplate code (getters, setters, constructors, etc.).
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcclzh55ejagjm8fy8fzv.png" alt="Spring initializer for reference" width="800" height="425"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have added these dependencies, click Generate.&lt;br&gt;
This will download a ZIP project which you can extract and open in your IDE (IntelliJ IDEA / Eclipse / VS Code).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Run the Application&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Navigate to the main class: &lt;code&gt;TaskTrackerApiApplication.java&lt;/code&gt; and run the application. If everything is configured correctly, you’ll see: &lt;code&gt;Started TaskTrackerApiApplication in X seconds&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Congratulations!!!&lt;br&gt;
Your Spring Boot application is now running...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Controller Layer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a class named &lt;code&gt;TaskController&lt;/code&gt; and place it in the &lt;code&gt;controller&lt;/code&gt; package. This layer handles incoming HTTP requests and sends responses back to the client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.controller;

import org.springframework.web.bind.annotation.RestController;

@RestController
public class TaskController {

    // 1. Create a Task

    // 2. Get All Tasks

    // 3. Get Task by ID

    // 4. Update a Task

    // 5. Delete a Task

    // 6. Get Tasks by Status
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;5. Model&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next, create &lt;code&gt;Task.java&lt;/code&gt; a model class in the &lt;code&gt;model&lt;/code&gt; package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.model;

import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Task {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;
    private String status;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Meaning of annotations in simple terms:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;@ Data → Automatically generates getters, setters, toString(), equals(), and hashCode().&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;@NoArgsConstructor → Creates a constructor with no arguments.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;@AllArgsConstructor → Creates a constructor with all fields.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;@Entity → Marks this class as a database table.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;@ Id → Marks the primary key of the table.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;@GeneratedValue → Automatically generates a value for the primary key.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;6. Repository and Service Layers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;TaskRepository.java&lt;/code&gt; : This layer interacts directly with the database. All database queries are handled here. In our case, the database is H2.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.repository;

import com.arshadpatel.task_tracker_api.model.Task;
import org.springframework.data.jpa.repository.JpaRepository;

public interface TaskRepository extends JpaRepository&amp;lt;Task, Long&amp;gt; {

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;TaskService.java&lt;/code&gt; : This layer contains the core logic and decides how responses are sent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.service;

import com.arshadpatel.task_tracker_api.model.Task;
import com.arshadpatel.task_tracker_api.repository.TaskRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TaskService {

    @Autowired
    private TaskRepository taskRepository;

    // 1. Create a Task

    // 2. Get All Tasks

    // 3. Get Task by ID

    // 4. Update Task

    // 5. Delete Task

    // 6. Get Tasks by Status
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7. Connecting Controller and Service&lt;/strong&gt;&lt;br&gt;
Now we will implement the first API method in the controller to create a task. After that, we can test it using Postman or any API client by sending a POST request with a JSON body. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;TaskController.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.controller;

import com.arshadpatel.task_tracker_api.model.Task;
import com.arshadpatel.task_tracker_api.service.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class TaskController {

    @Autowired
    private TaskService taskService;

    // 1. Create a Task
    @PostMapping("/task")
    public String createTask(@RequestBody Task task) {
        taskService.createTask(task);
        return "Task created successfully";
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;TaskService.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.service;

import com.arshadpatel.task_tracker_api.model.Task;
import com.arshadpatel.task_tracker_api.repository.TaskRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TaskService {

    @Autowired
    private TaskRepository taskRepository;

    // 1. Create a Task
    public void createTask(Task task) {
        taskRepository.save(task);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Test it using Postman or any API client by sending a POST request with a JSON body like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "title" : "Rest API",
    "status": "Pending"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkztwf0ii8k6tuzsdd9ry.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkztwf0ii8k6tuzsdd9ry.png" alt="Postman reference" width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hit it at &lt;code&gt;http://localhost:8080/task&lt;/code&gt;, and you should get the response: &lt;code&gt;Task created successfully&lt;/code&gt; To verify that the task is really saved in the database, we will implement the next method to fetch all tasks. After adding the method, you can create a GET request to see the saved tasks.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;TaskController.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.controller;

import com.arshadpatel.task_tracker_api.model.Task;
import com.arshadpatel.task_tracker_api.service.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class TaskController {

    @Autowired
    private TaskService taskService;

    // 1. Create a Task
    @PostMapping("/task")
    public String createTask(@RequestBody Task task) {
        taskService.createTask(task);
        return "Task created successfully";
    }

    // 2. Get All Tasks
    @GetMapping("/tasks")
    public List&amp;lt;Task&amp;gt; getAllTasks() {
        return taskService.getAllTasks();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;TaskService.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.service;

import com.arshadpatel.task_tracker_api.model.Task;
import com.arshadpatel.task_tracker_api.repository.TaskRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TaskService {

    @Autowired
    private TaskRepository taskRepository;

    // 1. Create a Task
    public void createTask(Task task) {
        taskRepository.save(task);
    }

    // 2. Get All Tasks
    public List&amp;lt;Task&amp;gt; getAllTasks() {
        return taskRepository.findAll();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the application, first send the POST request you created recently to add a task. Once that is done, create another request with the HTTP method GET and the URL: &lt;code&gt;http://localhost:8080/tasks&lt;/code&gt;. This will fetch all the tasks stored in the database and allow you to verify that your POST request successfully added a new task.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzq0i8pxk4vlc61d0rsgi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzq0i8pxk4vlc61d0rsgi.png" alt="Postman Reference" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Completing the Remaining API Methods&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now that we have implemented the “Create” and “Get All” methods, it's time to complete the remaining CRUD operations. These include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get a Task by ID&lt;/li&gt;
&lt;li&gt;Update a Task&lt;/li&gt;
&lt;li&gt;Delete a Task&lt;/li&gt;
&lt;li&gt;Get Tasks by Status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;TaskController.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.controller;

import com.arshadpatel.task_tracker_api.model.Task;
import com.arshadpatel.task_tracker_api.service.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class TaskController {

    @Autowired
    private TaskService taskService;

    // 1. Create a Task
    @PostMapping("/task")
    public String createTask(@RequestBody Task task) {
        taskService.createTask(task);
        return "Task created successfully";
    }

    // 2. Get All Tasks
    @GetMapping("/tasks")
    public List&amp;lt;Task&amp;gt; getAllTasks() {
        return taskService.getAllTasks();
    }

    // 3. Get Task by ID
    @GetMapping("task/{id}")
    public Task getTaskById(@PathVariable Long id) {
        return taskService.getTaskById(id);
    }

    // 4. Update a Task
    @PutMapping("task/{id}")
    public Task updateTask(@PathVariable Long id, @RequestBody Task task) {
        taskService.updateTask(id, task);
        return taskService.getTaskById(id);
    }

    // 5. Delete a Task
    @DeleteMapping("task/{id}")
    public String deleteTask(@PathVariable Long id) {
        taskService.deleteTask(id);
        return "Task deleted successfully";
    }

    // 6. Get Tasks by Status
    @GetMapping("/status/{status}")
    public String getTasksByStatus(@PathVariable String status) {
        taskService.getTasksByStatus(status);
        return "Fetching tasks with status: " + status;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;TaskService.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.service;

import com.arshadpatel.task_tracker_api.model.Task;
import com.arshadpatel.task_tracker_api.repository.TaskRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TaskService {

    @Autowired
    private TaskRepository taskRepository;

    // 1. Create a Task
    public void createTask(Task task) {
        taskRepository.save(task);
    }

    // 2. Get All Tasks
    public List&amp;lt;Task&amp;gt; getAllTasks() {
        return taskRepository.findAll();
    }

    // 3. Get Task by ID
    public Task getTaskById(Long id) {
        return taskRepository.findById(id)
                .orElse(null);
    }

    // 4. Update Task
    public Task updateTask(Long id, Task updatedTask) {
        return taskRepository.findById(id).map(task -&amp;gt; {
            task.setTitle(updatedTask.getTitle());
            task.setStatus(updatedTask.getStatus());
            return taskRepository.save(task);
        }).orElse(null);
    }


    // 5. Delete Task
    public String deleteTask(Long id) {
        taskRepository.deleteById(id);
        return "successfully deleted";
    }

    // 6. Get Tasks by Status
    public List&amp;lt;Task&amp;gt; getTasksByStatus(String status) {
        return taskRepository.findByStatus(status);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;TaskRepository.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.repository;

import com.arshadpatel.task_tracker_api.model.Task;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface TaskRepository extends JpaRepository&amp;lt;Task, Long&amp;gt; {
    List&amp;lt;Task&amp;gt; findByStatus(String status);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have now implemented all major features of a REST API using Spring Boot!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Congratulations! You Have Successfully Completed All CRUD Operations!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a huge milestone in backend development.&lt;br&gt;
At this point, you have built a fully functional REST API that can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create data&lt;/li&gt;
&lt;li&gt;Retrieve data&lt;/li&gt;
&lt;li&gt;Update data&lt;/li&gt;
&lt;li&gt;Delete data&lt;/li&gt;
&lt;li&gt;Filter data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly what real-world APIs do.&lt;/p&gt;

&lt;p&gt;You’ve officially reached the stage where you're not just "learning Spring Boot" you are actually building meaningful backend applications.&lt;br&gt;
Be proud of this progress — you have earned it!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenarios Where This Application Will Break&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Right now, your API works — but it’s not safe.&lt;br&gt;
There are several scenarios where the backend will crash, or return wrong responses, or behave unpredictably.&lt;/p&gt;

&lt;p&gt;Below are some real examples based on your current code:&lt;br&gt;
&lt;strong&gt;Deleting a Task that Does NOT Exist&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;DELETE /task/500&lt;/code&gt;&lt;br&gt;
If task with ID 500 doesn’t exist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deleteById() will throw an exception (EmptyResultDataAccessException)&lt;/li&gt;
&lt;li&gt;The server will crash internally&lt;/li&gt;
&lt;li&gt;The user sees a 500 Internal Server Error&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Updating a Task that Does NOT Exist&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;PUT /task/999&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "title": "New Title",
  "status": "Pending"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what happens?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend returns null&lt;/li&gt;
&lt;li&gt;Controller still calls taskService.getTaskById(id)&lt;/li&gt;
&lt;li&gt;That returns null again&lt;/li&gt;
&lt;li&gt;User sees an empty response (not meaningful)&lt;/li&gt;
&lt;li&gt;No clear indication that the task was not found
This is confusing for the client.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;No HTTP Status Codes Are Being Sent&lt;/strong&gt;&lt;br&gt;
Every response from your controller returns:&lt;/p&gt;

&lt;p&gt;“Task created successfully”&lt;br&gt;
but without proper status codes like 201, 404, 400, 500, etc.&lt;/p&gt;

&lt;p&gt;Clients expect these:&lt;br&gt;
200 - OK (Success)&lt;br&gt;
201 - Created (Resource created successfully)&lt;br&gt;
400 - Bad Request (Invalid input)&lt;br&gt;
404 - Not Found (Resource missing)&lt;br&gt;
500 - Internal Server Error (Something broke internally)&lt;/p&gt;

&lt;p&gt;Your current API sends only plain text → not good for real consumers.&lt;/p&gt;

&lt;p&gt;All these issues can be solved by introducing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom Exceptions&lt;/li&gt;
&lt;li&gt;ResponseEntity&lt;/li&gt;
&lt;li&gt;Proper HTTP Status Codes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes your API professional, predictable, and user-friendly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Adding Proper HTTP Status Codes Using ResponseEntity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Until now, our API has been returning plain Strings as responses.&lt;br&gt;
But RESTful APIs must return proper HTTP status codes to clearly communicate whether a request was successful or failed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is ResponseEntity?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;- ResponseEntity is a Spring class that lets you send both the response body and the HTTP status code together.&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- It gives you full control over what the client receives.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For example, instead of just returning &lt;code&gt;"Task created successfully"&lt;/code&gt;, we can return:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;201 Created (when a new task is added)&lt;/li&gt;
&lt;li&gt;200 OK (when data is fetched or updated)&lt;/li&gt;
&lt;li&gt;404 Not Found (when a task does not exist)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let’s improve our API to use ResponseEntity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Creating a Standard Error Response (JSON)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To keep our API responses clean and consistent, we will create a simple Response class that can handle both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;success messages&lt;/li&gt;
&lt;li&gt;error messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures clients always receive a clear JSON object instead of plain text.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Response.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.response;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Response {
    private String message;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;11. Updating Controller With ResponseEntity and Basic If-Else Handling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now we modify our controller so all responses are RESTful and predictable.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;TaskController.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.controller;

import com.arshadpatel.task_tracker_api.model.Task;
import com.arshadpatel.task_tracker_api.response.Response;
import com.arshadpatel.task_tracker_api.service.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class TaskController {

    @Autowired
    private TaskService taskService;

    // 1. Create a Task
    @PostMapping("/task")
    public ResponseEntity&amp;lt;?&amp;gt; createTask(@RequestBody Task task) {
        Task savedTask = taskService.createTask(task);
        return new ResponseEntity&amp;lt;&amp;gt;(savedTask, HttpStatus.CREATED);
    }

    // 2. Get All Tasks
    @GetMapping("/tasks")
    public ResponseEntity&amp;lt;?&amp;gt; getAllTasks() {
        return ResponseEntity.ok(taskService.getAllTasks());
    }

    // 3. Get Task by ID
    @GetMapping("task/{id}")
    public ResponseEntity&amp;lt;?&amp;gt; getTaskById(@PathVariable Long id) {
        Task task = taskService.getTaskById(id);
        if (task == null) {
            return new ResponseEntity&amp;lt;&amp;gt;(new Response("Task not found"), HttpStatus.NOT_FOUND);
        }
        return ResponseEntity.ok(task);
    }

    // 4. Update a Task
    @PutMapping("task/{id}")
    public ResponseEntity&amp;lt;?&amp;gt; updateTask(@PathVariable Long id, @RequestBody Task updatedTask) {
        Task task = taskService.updateTask(id, updatedTask);
        if (task == null) {
            return new ResponseEntity&amp;lt;&amp;gt;(new Response("Task not found"), HttpStatus.NOT_FOUND);
        }
        return ResponseEntity.ok(task);
    }

    // 5. Delete a Task
    @DeleteMapping("task/{id}")
    public ResponseEntity&amp;lt;?&amp;gt; deleteTask(@PathVariable Long id) {
        boolean deleted = taskService.deleteTask(id);
        if (!deleted) {
            return new ResponseEntity&amp;lt;&amp;gt;(new Response("Task not found"), HttpStatus.NOT_FOUND);
        }
        return ResponseEntity.ok(new Response("Task deleted successfully"));
    }

    // 6. Get Tasks by Status
    @GetMapping("/status/{status}")
    public ResponseEntity&amp;lt;?&amp;gt; getTasksByStatus(@PathVariable String status) {
        List&amp;lt;Task&amp;gt; tasks = taskService.getTasksByStatus(status);
        return ResponseEntity.ok(tasks);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;12. Updating Service Layer for Safe Operations&lt;/strong&gt;&lt;br&gt;
We now update the service to support our if–else based checks.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;TaskService.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.arshadpatel.task_tracker_api.service;

import com.arshadpatel.task_tracker_api.model.Task;
import com.arshadpatel.task_tracker_api.repository.TaskRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TaskService {

    @Autowired
    private TaskRepository taskRepository;

    // 1. Create a Task
    public Task createTask(Task task) {
        return taskRepository.save(task);
    }

    // 2. Get All Tasks
    public List&amp;lt;Task&amp;gt; getAllTasks() {
        return taskRepository.findAll();
    }

    // 3. Get Task by ID
    public Task getTaskById(Long id) {
        return taskRepository.findById(id)
                .orElse(null);
    }

    // 4. Update Task
    public Task updateTask(Long id, Task updatedTask) {
        return taskRepository.findById(id).map(task -&amp;gt; {
            task.setTitle(updatedTask.getTitle());
            task.setStatus(updatedTask.getStatus());
            return taskRepository.save(task);
        }).orElse(null);
    }


    // 5. Delete Task
    public boolean deleteTask(Long id) {
        if (!taskRepository.existsById(id)) {
            return false;
        }
        taskRepository.deleteById(id);
        return true;
    }

    // 6. Get Tasks by Status
    public List&amp;lt;Task&amp;gt; getTasksByStatus(String status) {
        return taskRepository.findByStatus(status);
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Congratulations — Your API Is Now Fully RESTful!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At this point, your backend is no longer a simple CRUD application.&lt;/p&gt;

&lt;p&gt;It now supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean REST URLs&lt;/li&gt;
&lt;li&gt;Proper HTTP status codes&lt;/li&gt;
&lt;li&gt;JSON error messages&lt;/li&gt;
&lt;li&gt;Safe handling of invalid IDs&lt;/li&gt;
&lt;li&gt;Professional ResponseEntity usage&lt;/li&gt;
&lt;li&gt;Fully functional CRUD + filtering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This is just the beginning. Stay tuned for more articles where we’ll explore advanced Spring Boot and real-world REST API concepts.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>restapi</category>
      <category>java</category>
      <category>springboot</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
