Search code examples
javascriptpostbackendfetch-api

Fetch post redirecting to API response body


I have the following code:

 const form = document.querySelector('form');
   form.addEventListener('submit', handleSubmit());

    async function handleSubmit(event) {
        const url = new URL(form.action);
        const formData = new FormData(form);
    
        @type {Parameters<fetch>[1]}
        const fetchOptions = {
            method: form.method,
            body: formData,
        };
    
        const response = await fetch(url, fetchOptions);
        alert (response);
    
        event.preventDefault();
      }

With it, I'm trying to upload a file to an external API and receive a server generated id once the upload is complete. However, when the upload completes, I'm redirected to the API response body containing the id. How do I prevent the redirect and instead get the id stored into a variable?

fetch(url, fetchOptions)
    .then(function(response)
            {
              return response.json();
            }).then(async function(response)
            {
             alert(response);
            });

I tried the above and was still redirected. I also tried moving the preventDefault call up to the top of the function as suggested by @Quentin, to no avail.


Solution

  • JavaScript executes your code synchronously until it meets await

    event.preventDefault() is used to cancel the default browser behavior on form submission. It works because a browser uses only 1 thread for JS execution, so the order is the following:

    1. Form submit event fired
    2. handleSubmit function called
    3. Default browser action if it is not canceled

    Browser expects that handleSubmit is a regular function and does not await it. Any async function executes as a regular one until the first await, so in your case order is the following:

    1. Form submit event fired
    2. handleSubmit function is called and executes until the first await
    3. Default browser action
    4. Browser doing redirect so the rest of handleSubmit makes no sense.

    I always recommend adding event.preventDefault() on top of an event handler if you going to cancel its default behavior. You can try this variant:

    async function handleSubmit(event) {
        event.preventDefault();
    
        const url = new URL(form.action);
        const formData = new FormData(form);
    
        const fetchOptions = {
            method: form.method,
            body: formData,
        };
    
        const response = await fetch(url, fetchOptions);
        alert(JSON.stringify(await response.json(), null, 2))
    }
    
    form.addEventListener('submit', handleSubmit);
    <form action="https://jsonplaceholder.typicode.com/posts" method="POST" id="form">
      <input value="Post Title" name="title"/>
      <button type="submit">submit</button>
    </form>