Skip to content

How to post a form with fetching?

I am trying to send a post with fetch an API.

My fetch is working because it returns 200 and sends the request but it sends an empty form.

It cannot take the values in the form input. Where is my mistake and how can I fix it?

...  
  const [contract, setContract] = useState("");
  const form = useRef(null);
  const submit = (e) => {
    e.preventDefault();
    const data = new FormData(form.current);
    fetch(process.env.REACT_APP_ENDPOINT + "user/me/contract", {
      method: "POST",
      body: data,
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${localStorage.getItem("fray_access_token")}`,
      },
    })
      .then((res) => res.json())
      .then((json) => setContract(json.contract));
  };
return( ...
<form ref={form} onSubmit={submit}>
    
    <Input
        required
        type="text"
        value={contract.name}
        onChange={(e) =>
            setContract({ ...contract, name: e.target.value })
                      }
    />
    <Input
        required
        type="text"
        value={contract.surname}
        onChange={(e) =>
            setContract({ ...contract, surname: e.target.value })
                      }
     />
     <Input
          required
          type="email"
          value={contract.emai}
          onChange={(e) =>
          setContract({ ...contract, email: e.target.value })
          }
      />         
</form>
...)

Answer

[Update]:

You can either remove the application/json header and let browser post the form data implicitly using the multipart/form-data content-type :

const submit = (e) => {
    e.preventDefault();
    const data = new FormData(form.current);
    fetch(process.env.REACT_APP_ENDPOINT + "user/me/contract", {
      method: "POST",
      body: data,
      headers: {
        Authorization: `Bearer ${localStorage.getItem("fray_access_token")}`,
      },
    })
      .then((res) => res.json())
      .then((json) => setContract(json.contract));
  };

As @Quentin pointed out, we cannot serialise FormData using JSON.stringify so it’s better to use explicit function to do it for you:

const serialize = (data) => {
    let obj = {};
    for (let [key, value] of data) {
        if (obj[key] !== undefined) {
            if (!Array.isArray(obj[key])) {
                obj[key] = [obj[key]];
            }
            obj[key].push(value);
        } else {
            obj[key] = value;
        }
    }
    return obj;
}

const submit = (e) => {
    e.preventDefault();
    const data = new FormData(form.current);
    fetch(process.env.REACT_APP_ENDPOINT + "user/me/contract", {
      method: "POST",
      body: typeof data !== 'string' ? JSON.stringify(serialize(data)): data,
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${localStorage.getItem("fray_access_token")}`,
      },
    })
      .then((res) => res.json())
      .then((json) => setContract(json.contract));
  };

More details : https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch