'Postman is returning a 404 error on my Spring Boot API

I've built a spring boot rest api. However, when I try to test it in Postman, I am getting a 404 error. I have linked the code below. Please note that there might be a random @component annotation in some files. This was my tired brain trying anything it can.

Student.java

package StudentModel;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "Student")
public class Student {
    public enum status {
        PAID,
        UNPAID,
        PARTIAL
    }
    
    @Column
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long Id;
    
    @Column(nullable = false)
    private String FirstName;
    
    @Column(nullable = false)
    private String LastName;
    
    @Column(nullable = false)
    private long Phone;
    
    @Column(nullable = false)
    private String Email;
    
    @Column(nullable = false)
    private status PaymentStatus;

    public long getId() {
        return Id;
    }

    public void setId(long id) {
        Id = id;
    }

    public String getFirstName() {
        return FirstName;
    }

    public void setFirstName(String firstName) {
        FirstName = firstName;
    }

    public String getLastName() {
        return LastName;
    }

    public void setLastName(String lastName) {
        LastName = lastName;
    }

    public long getPhone() {
        return Phone;
    }

    public void setPhone(long phone) {
        Phone = phone;
    }

    public String getEmail() {
        return Email;
    }

    public void setEmail(String email) {
        Email = email;
    }

    public status getPaymentStatus() {
        return PaymentStatus;
    }

    public void setPaymentStatus(status paymentStatus) {
        PaymentStatus = paymentStatus;
    }   
}

StudentController.java

package StudentController;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import StudentModel.Student;
import StudentService.StudentService;
@Component
@RestController
@RequestMapping("/api/v1")
public class StudentController {
    
    @Autowired
    private StudentService studentService;
    
    @PostMapping("/api/v1/addStudent")
    public Student addStudent(@RequestBody Student student) {
    return studentService.saveStudent(student);
    }
    
    @PostMapping("/api/v1/addStudents")
    public List<Student> addStudents(@RequestBody List<Student> students) {
        return studentService.saveStudents(students);
        }
    @GetMapping("/api/v1/students")
    public List<Student> findAllStudents(){
        return studentService.getStudents();
    }
    @GetMapping("/api/v1/students/{id}")
    public Student findStudentById(@PathVariable long id) {
        return studentService.getStudentById(id);
    }
    @GetMapping("/api/v1/students/{name}")
    public Student findStudentByFirstName(@PathVariable String FirstName) {
        return studentService.getStudentByFirstName(FirstName);
    }
    
    @PutMapping("/api/v1/update")
    public Student updateStudent(@RequestBody Student student) {
    return studentService.updateStudent(student);
    }
    
    @DeleteMapping("/api/v1/delete/{id}")
    public String deleteStudent(@PathVariable long id) {
        return studentService.deleteStudent(id);
    }   
}

StudentService.java

package StudentService;

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

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import StudentModel.Student;
import StudentRepository.StudentRepository;
@Component
@Service
@Transactional
public class StudentService {
    
    @Autowired
    private StudentRepository studentRepository;
    
    public Student saveStudent(Student student) {
        return studentRepository.save(student);
    }
    
    public List<Student> saveStudents(List<Student> students) {
        return studentRepository.saveAll(students);
    }
    
    public List<Student> getStudents() {
        return studentRepository.findAll();
    }

    public Student getStudentById(long id){
        return studentRepository.getById(id);
    }
    
    public Student getStudentByFirstName(String FirstName){
        return studentRepository.findByFirstName(FirstName);
    }
    
    public Student getStudentByLastName(String LastName){
        return studentRepository.findByLastName(LastName);
    }
    
    public Student getStudentByEmail(String Email){
        return studentRepository.findByEmail(Email);
    }
    
    public Student getStudentByPhone(long Phone){
        return studentRepository.findByPhone(Phone);
    }
    
    public String deleteStudent(long id) {
        studentRepository.deleteById(id);
        return "Student Deleted";
    }
    
    public Student updateStudent (Student student) {
        Student existingStudent = studentRepository.getById(student.getId());
        existingStudent.setFirstName(student.getFirstName());
        existingStudent.setLastName(student.getLastName());
        existingStudent.setEmail(student.getEmail());
        existingStudent.setPhone(student.getPhone());
        existingStudent.setPaymentStatus(student.getPaymentStatus());
        return studentRepository.save(existingStudent);
    }
}

StudentRepository.java

package StudentRepository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;

import StudentModel.Student;
@Component
public interface StudentRepository extends JpaRepository <Student, Long>{
//  Student saveStudent (Student student);
    Student findByFirstName(String FirstName);
    Student findByLastName(String LastName);
    Student findByEmail(String Email);
    Student findByPhone(long Phone);

//  Student findById(long id);
}

StudentApplication.java

package com.BusyQA;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@SpringBootApplication
@ComponentScan

public class BusyQaApplication extends SpringBootServletInitializer{

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

Any help would be greatly appreciated. Thank you.



Solution 1:[1]

As Dilermando mentioned in the comments, your @RequestMapping("/api/v1") is setting its mapping, then you're extending onto that with @PostMapping("/api/v1/addStudent") making the address {url}/api/v1/api/v1/addStudent. You can resolve this by removing the /api/v1 from the Post/get mappings:

@RequestMapping("/api/v1")
public class StudentController {
    
    @Autowired
    private StudentService studentService;
    
    @PostMapping("/addStudent")
    public Student addStudent(@RequestBody Student student) {
    return studentService.saveStudent(student);
    }

...etc
}

Solution 2:[2]

There are 2 reason behind 404 not found

Problem 1

You main class is in com.BusyQA package and Controller class is in StudentController package so you have to scan controller class in main class.

Your StudentApplication.java class should become:

@SpringBootApplication
@ComponentScan(basePackageClasses = StudentController.class) // Scan the controller class in main class.

public class BusyQaApplication extends SpringBootServletInitializer{

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

Problem 2

Remove pre path /api/v1 from all url mapping in controller. Now your mapping url should become

@RestController
@RequestMapping("/api/v1")
public class StudentController {
  
    @Autowired
    private StudentService studentService;
  
    @PostMapping("/addStudent")
  
    @PostMapping("/addStudents")
  
    @GetMapping("/students")
 
    @GetMapping("/students/{id}")

    @GetMapping("/students/{name}")
  
    @PutMapping("/update")
  
    @DeleteMapping("/delete/{id}")
  
}

This is another mistake in your code:

  • Remove the @Component annotation from controller.

  • Remove the @Component annotation from Service class.

  • Remove the @Component annotation from Repository interface and add @Repository annotation.

Solution 3:[3]

To make it work, you need some improvements:

  1. For Controller (REST API requests):
  • remove @Component annotation;
  • remove /api/v1/ from request mappings;
  • add DTO to only transfer the required information;
  • fix the name of the variables, following the convention.
import java.util.ArrayList;
import java.util.List;
import com.example.demo.dto.StudentDTO;
import com.example.demo.entity.Student;
import com.example.demo.service.StudentService;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/v1")
public class StudentController {

    private final StudentService studentService;

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

    @PostMapping("/addStudent") 
    public Student addStudent(@RequestBody StudentDTO studentDTO) {
        Student student = new Student(studentDTO);
        return studentService.saveStudent(student);
    }

    @PostMapping("/addStudents") 
    public List<Student> addStudents(@RequestBody List<Student> students) {
        return studentService.saveStudents(students);
    }

    @GetMapping("/students") 
    public List<StudentDTO> findAllStudents() {
        List<StudentDTO> studentDTOList = new ArrayList<>();
        List<Student> studentList = studentService.getStudents();

        for (Student student : studentList) {
            StudentDTO studentDTO = new StudentDTO(student);
            studentDTOList.add(studentDTO);
        }
        return studentDTOList;
    }

    @GetMapping("/students/id/{id}") 
    public Student findStudentById(@PathVariable long id) {
        return studentService.getStudentById(id);
    }

    @GetMapping("/students/firstName/{firstName}") 
    public Student findStudentByFirstName(@PathVariable String firstName) {
        return studentService.getStudentByFirstName(firstName);
    }

    @PutMapping("/update") 
    public Student updateStudent(@RequestBody StudentDTO studentDTO) {
        Student student = new Student(studentDTO);
        return studentService.updateStudent(student);
    }

    @DeleteMapping("/delete/{id}") 
    public String deleteStudent(@PathVariable long id) {
        return studentService.deleteStudent(id);
    }
}
  1. For Service class (Business logic):
  • remove @Component annotation;
  • remove @Transactional annotation;
  • use findById() to retrieve an entity by its Id;
import java.util.List;
import java.util.Optional;
import com.example.demo.entity.Student;
import com.example.demo.repository.StudentRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityNotFoundException;

@Service
public class StudentService {

    private final StudentRepository studentRepository;

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

    public Student saveStudent(Student student) {
        return studentRepository.save(student);
    }

    public List<Student> saveStudents(List<Student> students) {
        return studentRepository.saveAll(students);
    }

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

    public Student getStudentById(long id) {
        return studentRepository.findById(id).orElseThrow(EntityNotFoundException::new);
    }

    public Student getStudentByFirstName(String firstName) {
        return studentRepository.findByFirstName(firstName);
    }

    public Student getStudentByLastName(String lastName) {
        return studentRepository.findByLastName(lastName);
    }

    public Student getStudentByEmail(String email) {
        return studentRepository.findByEmail(email);
    }

    public Student getStudentByPhone(long phone) {
        return studentRepository.findByPhone(phone);
    }

    public String deleteStudent(long id) {
        studentRepository.deleteById(id);
        return "Student Deleted";
    }

    public Student updateStudent(Student student) {
        Student existingStudent = studentRepository.getById(student.getId());
        existingStudent.setFirstName(student.getFirstName());
        existingStudent.setLastName(student.getLastName());
        existingStudent.setEmail(student.getEmail());
        existingStudent.setPhone(student.getPhone());
        existingStudent.setPaymentStatus(student.getPaymentStatus());
        return studentRepository.save(existingStudent);
    }
}
  1. The Model class:
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import com.example.demo.dto.StudentDTO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Builder;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Student {

    public Student(StudentDTO studentDTO) {
        this.id = studentDTO.getId();
        this.firstName = studentDTO.getFirstName();
        this.lastName = studentDTO.getLastName();
        this.phone = studentDTO.getPhone();
        this.email = studentDTO.getEmail();
        this.paymentStatus = studentDTO.getPaymentStatus();
    }

    public enum Status {
        PAID,
        UNPAID,
        PARTIAL
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column
    private long id;

    private String firstName;

    private String lastName;

    private long phone;

    private String email;

    private Status paymentStatus;
}
  1. DTO class:
import com.example.demo.entity.Student;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(NON_NULL)
public class StudentDTO implements Serializable {

    public StudentDTO(Student student) {
        this.id = student.getId();
        this.firstName = student.getFirstName();
        this.lastName = student.getLastName();
        this.phone = student.getPhone();
        this.email = student.getEmail();
        this.paymentStatus = student.getPaymentStatus();
    }

    private long id;

    private String firstName;

    private String lastName;

    private long phone;

    private String email;

    private Student.Status paymentStatus;
}
  1. The Repository class:
import com.example.demo.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
    Student findByFirstName(String firstName);
    Student findByLastName(String lastName);
    Student findByEmail(String email);
    Student findByPhone(long phone);
}

and the main class of a Spring Boot application:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

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

To test it, you can use endpoints by the same principle:

POST: localhost:8080/api/v1/addStudent
POST: localhost:8080/api/v1/addStudents
GET: localhost:8080/api/v1/students
GET: localhost:8080/api/v1/students/id/1
GET: localhost:8080/api/v1/students/firstName/testName
PUT: localhost:8080/api/v1/update
DELETE: localhost:8080/api/v1/delete/1

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 lew
Solution 2
Solution 3