javascriptjavareactjsspring-boot

react delete request not reaching spring boot api, 404 error


My react app successfully gets and posts from/to Spring Boot JPA MySql db. But delete fails with 404, meaning it can find the endpoint.

MedaverterApplication.java

@SpringBootApplication
@ComponentScan(basePackages = { "net.tekknow.medaverter.*" })
@EntityScan(basePackages = "net.tekknow.medaverter.*") 
public class MedaverterApplication {

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

      @Bean
      public WebMvcConfigurer corsConfigurer() {
          return new WebMvcConfigurer() {
              @Override
              public void addCorsMappings(CorsRegistry registry) {
                  registry.addMapping("/**")
                          .allowedOrigins("http://localhost:3000") 
                          .allowedMethods("GET", "POST", "PUT", "DELETE")
                          .allowedHeaders("*")
                          .allowCredentials(true);
              }
          };
      }
}

EventController.java

package net.tekknow.medaverter.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import java.util.List;
import net.tekknow.medaverter.models.Event;
import net.tekknow.medaverter.repository.EventRepo;

@CrossOrigin
@RestController
public class EventController {
    @Autowired
    EventRepo eventRepo;

    @GetMapping("/get-events")
    public List<Event> getEvents(int user_id) {
        List<Event> events = eventRepo.findEventsByUserId(user_id);
        return events;
    }

    @PostMapping(path = "/save-event", consumes = MediaType.APPLICATION_JSON_VALUE)
    @ResponseStatus(HttpStatus.OK)
    public ResponseEntity<Event> addEvent(@RequestBody Event event) {
        return ResponseEntity.ok().body(eventRepo.save(event));
    }

    @DeleteMapping("/delete-event/{id}")
    public ResponseEntity<String> deleteEvent(@PathVariable Integer id) {
        try {
            eventRepo.deleteById(id);
            return new ResponseEntity<>("Item deleted successfully", HttpStatus.OK);
        } catch (Exception e) {
            return new ResponseEntity<>("Error deleting item", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

Note that both GET and POST work, but not DELETE

events.tsx

const deleteEvent = async (id: GridRowId) => {
  const response = await fetch(`/delete-event?id=${id}`, {
    method: 'DELETE',
    headers: {
      'Content-Type': 'application/json' // Or the appropriate content type
    },
  })
    .then((response) => {
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      return response.json();
    })
    .then((data) => {
      console.log('Row deleted successfully:', data);
    })
    .catch((error) => {
      console.error('Error deleting row:', error);
    });
}

I also tried:

  const response = await fetch(`http://localhost:3000/delete-event?id=${id}`, {...
  const response = await fetch(`http://localhost:8080/delete-event?id=${id}`, {...

How is it that I can get and save data, but not delete? I thought maybe the browser was blocking due to CORS, but I've got that covered. Can anybody see what I am doing wrong?


Solution

  • You have a mismatch in the endpoint. Your backend controller expects "/delete-event/{id}" which means a path variable. But from frontend side, you are calling the API via query parameter like /delete-event?id=${id}.

    The correct way should be:

    const deleteEvent = async (id: GridRowId) => {
      await fetch(`/delete-event/${id}`, {
        method: 'DELETE',
        headers: {
          'Content-Type': 'application/json',
        },
      })
        .then((response) => {
          if (!response.ok) {
            throw new Error('Network response was not ok');
          }
          return response.json();
        })
        .then((data) => {
          console.log('Row deleted successfully:', data);
        })
        .catch((error) => {
          console.error('Error deleting row:', error);
        });
    };

    Now your frontend will call the /delete-event/${id} properly. This matches the @DeleteMapping("/delete-event/{id}").