Search code examples
asp.net-core-webapiwebapiasp.net-web-api-routing

Why is PUT throwing an Error 400 in my WebAPI?


First time working with web APIs and I can't seem to make the PUT method work, while everything works fine (get, post and delete).

I'm trying to do, what I think it is, a very simple call to update testimonials. These will have an image file, name and text. The problem is I'm getting error 400 when trying to update them using a PUT call.

I'm using FormData to send the data since I need to also send the image file and the rest of the form (the URI is "/api/testimonials", and the Id is a guid):

function updateItem() {
    const itemId = document.getElementById('edit-id').value;
    const item = {
        id: itemId,
        name: document.getElementById('edit-name').value.trim(),
        text: document.getElementById('edit-text').value.trim(),
    };

    const formData = new FormData();
    formData.append('file', document.getElementById('edit-file').files[0]);
    formData.append('jsonString', JSON.stringify(item));

    fetch(`${uri}/${itemId}`, {
        method: 'PUT',
        contentType: 'false',
        processData: 'false',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json'
        },
        body: formData
    })
        .then(() => getItems())
        .catch(error => console.error('Unable to update item.', error));

    closeInput();

    return false;
}

and this is the method in the TestimonialsController:

[HttpPut("{id}")]
public async Task<IActionResult> PutTestimonial(string id, [FromForm] IFormFile? file, [FromForm] string jsonString)
{
    ...
}

Other methods like POST and Delete, that also pass an Id or data work just fine, but PUT is not being called.

POST method

[HttpPost]
public async Task<ActionResult<TestimonialDTO>> PostDepoimento([FromForm] IFormFile? arquivo, [FromForm] string jsonString)
{
    ...
}
function addItem() {
    const addNameTextbox = document.getElementById('add-name');
    const addTextTextbox = document.getElementById('add-text');

    const item = {
        name: addNameTextbox.value.trim(),
        text: addTextTextbox.value.trim(),
    };

    const formData = new FormData();
    formData.append('file', document.getElementById('add-file').files[0]);
    formData.append('jsonString', JSON.stringify(item));

    fetch(uri, {
        method: 'POST',
        contentType: 'false',
        processData: 'false',
        body: formData
    })
        .then(response => response.json())
        .then(() => {
            getItems();
            addNameTextbox.value = '';
            addTextTextbox.value = '';
        })
        .catch(error => console.error('Unable to add item.', error));
}

DELETE method

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTestimonial(string id)
{
    ...
}
function deleteItem(id) {
    fetch(`${uri}/${id}`, {
        method: 'DELETE'
    })
        .then(() => getItems())
        .catch(error => console.error('Unable to delete item.', error));
}

Could you help me identify why is the PUT method not being called? Is there anything wrong in the way I'm calling the method/passing data?


Solution

  • 400 error is because [FromForm] does not allow application/json Content-Type. Just remove the header in your updateItem function:

    headers: {
        'Accept': 'application/json',
        //'Content-Type': 'application/json'
    },
    

    FromForm occurs at the parameter binding stage, which is part of the request pipeline that necessarily occurs before entry into the endpoint. This is why under debug, for example, your breakpoints wouldn't hit.