0

I'm getting 405 in console, when I send PUT request.

Here is my ajax call, which is part of bigger function:

triggerPutRequest(id, stringDate, isDone, title)
                .then((data) => {
                    console.log(data);
                })
                .catch((error) => {
                    alert(error);
                });


function triggerPutRequest(isDone, id, stringDate, title) {
    
        return new Promise((resolve, reject) => {
    
            $.ajax({
                type: 'PUT',  // http method
                url: window.location + "api/tasks", //endpoint on our backend
                contentType: "application/json; charset=utf-8",
                dataType: 'json',
                data: JSON.stringify({
                    "id": id,
                    "title": title,
                    "dueDate":  convertDateToString(new Date(datepicker.value)),
                    "done": isDone,                                         
                }),
    
                success: function (data) {
                    resolve(data)
                },
                error: function () {
                    reject("string")
                }
            });
    
        })
    
    }

In my Spring Boot I have simple Task model object with omitted unrelevant fields:

public class Task {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id", unique = true, nullable = false)
        private int id;

        @Column(name = "due_date", unique = false, nullable = false)
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")
        private LocalDate dueDate;

        @NotEmpty(message = "cannot be empty string")
        @Column(name = "title", unique = true, nullable = false)
        private String title;
    
        @Column(name = "done", unique = false, nullable = false)
        private boolean done;
}

My controller class in Spring Boot and endpoint method for updating look like this:

@RestController
@RequestMapping(value="/api/tasks")

public class TaskController {
    @PutMapping(value="/", consumes="application/json")
    public ResponseEntity<Task> updateTask(@RequestBody Task taskToBeUpdated){
        //update object logic
        return new ResponseEntity<Task>(newlyAddedTask, HttpStatus.OK);
    }
}
Wrapper
  • 794
  • 10
  • 25
  • Just use `POST`, browsers don't supported `PUT` and `DELETE` anymore. – Seldo97 Aug 20 '20 at 10:15
  • @Seldo97 There has to be a way to sent PUT with ajax...I'm newbie to JavaScript..but I'm pretty much sure this can be done... – Wrapper Aug 20 '20 at 10:30
  • I see now. You have `@PostMapping` in controler method. Change it to `@PutMapping`. – Seldo97 Aug 20 '20 at 10:46
  • @Seldo97 Sorry man, I copied wrong method from my controller class. I just updated, it is still not working. Keep getting 405. – Wrapper Aug 20 '20 at 11:09
  • On the server in the console I get: DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'PUT' not supported] – Wrapper Aug 20 '20 at 11:21
  • How come that PUT method is not supported? – Wrapper Aug 20 '20 at 11:21
  • https://stackoverflow.com/questions/35381402/http-status-405-request-method-put-not-supported check this out, we need more information – Toerktumlare Aug 20 '20 at 12:35
  • @ThomasAndolf Tnx for the comment. Yes I included it that debug line as suggested. Also I edited my endpoint, just wanted to be sure to differentiate it from some other PUT requests. Strangely enough, I got 400 know, which is improvement if I may say so :) – Wrapper Aug 20 '20 at 12:53
  • Here is the log from console: PUT "/api/tasks/update", parameters={}; Mapped to com.marbleit.todo.controllers.TaskController#updateTask(Task); Could not resolve parameter [0] in public org.springframework.http.ResponseEntity com.marbleit.todo.controllers.TaskController.updateTask; HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `int` from String "20-08-2020": not a valid Integer value; nested exception is; Completed 400 BAD_REQUEST – Wrapper Aug 20 '20 at 12:56
  • According to this, I have different problem, that is how to send date object from ajax as part of the object so Jackson can deserialize object? – Wrapper Aug 20 '20 at 12:58
  • 1
    Please dont post it in the comments, its unreadable. Edit your question and add the log with proper formatting pls. – Toerktumlare Aug 20 '20 at 17:30

2 Answers2

0

Your problem is this:

Could not resolve parameter [0] in public org.springframework.http.ResponseEntity<com.marbleit.todo.model.Task> com.marbleit.todo.controllers.TaskController.updateTask; HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type int from String "20-08-2020": not a valid Integer

The first value you are sending in is a string and you are trying to place it into an int. So you should print the requestbody from the client.

You have mixed up the variable order in your code:

triggerPutRequest(id, stringDate, ...

function triggerPutRequest(isDone, id, ...

Also.

It is common practice to keep the api against the client separated from the api against the database.

So what does this mean? Well it means that if you would for example change something in the database it would now have a ripple effect out to the client since you are serializing/deserializing straight into the database entity. This makes the client tightly coupled with the database.

So you should avoid taking data from the client and put it straight into your database entity and instead have a intermittent object for instanse a TaskRequest. Then from this take the data and place into your entity so both the client api and the database api can evolve independently from eachother.

Toerktumlare
  • 12,548
  • 3
  • 35
  • 54
0

Ahh...and here is the bug..

In my class I had this:

public class Task {

  ...

    @Column(name = "due_date", unique = false, nullable = false)
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
    private LocalDate dueDate;

    ...

}

Somehow, I manged to post correct way here in SO, but in my code it was wrong...I dont't know how I pull this off..day and a half just wasted.

Regarding Thomas's answer..Doesn't that sounds a bit redundant to do that extra step? If I have all the data from the object I need while doing editing of an object? Why I cant just take that object as a placeholder for new values. Then from db, just take object with same id and set new variables...

Wrapper
  • 794
  • 10
  • 25