Search code examples
reactjsmultipartform-datamulter

React file upload with FormData


Trying to upload file using FormData. File is uploading to server successfully and appears in uploads folder, but server sends back "Bad request". On server

"message": "\"file\" is required"

Seems like multer not parsing file to body so req.body.file doesn't exist. Similar code in Angular works as clock. Where's the difference?

React:

onSubmit(e) {
    e.preventDefault();
    let body = new FormData();

    let data = Array.prototype.filter.call(e.target.elements, 
      (input) => {
        if (input.nodeName === 'BUTTON') return false;
        return true;
      });
    Array.prototype.map.call(data, (input) => {
      input.id !== 'file' ? body.append( input.id, input.value )
      : body.append('file', input.files[0]);
      
    });
    fetch('http://localhost:4040/api/books/create', {
      method: 'POST',
      headers: { 
        'Authorization': 'Bearer ' + localStorage.getItem('jwtToken')
     },
     body: body,
    }).then(res => res.json())
      .then(response => {
        console.log(response);
      })
      .catch(error => console.error('Error:', error));
  }

  render() {
    return (
      <form onSubmit={this.onSubmit} encType="multipart/form-data" className="form-add">
        <input type="file" id="file" accept=".jpg, .png" required />
        <input type="text" id="author" placeholder="author" required />
        <input type="text" id="title" placeholder="Title" required />
        <textarea id="description" rows="10" placeholder="Description..." required ></textarea>
        <input type="number" id="rating" placeholder="Number from 1 to 5" min="1" max="5" required/>
        <select name="status" id="status">
          <option value="true">true</option>
          <option value="false">false</option>
        </select>
        <button type="submit">Submit</button>
      </form>
    );
  }

Angular:

@ViewChild("fileInput") fileInput;
  // Loading file
  addFile(): any {
    let fi = this.fileInput.nativeElement;
    if (fi.files && fi.files[0]) {
        return fi.files[0];
    }
    return null;
  }

  onSubmit(value: string) {
    let body = new FormData();
    body.append("file",this.addFile());
    Object.keys(this.form.value).forEach(k => {
      body.append(k, this.form.value[k]);
    });
    let httpOptions = {
      headers: new HttpHeaders({ 'Authorization': 'Bearer ' + localStorage.getItem('jwtToken') })
    };
    this.http.post('http://localhost:4040/api/books/create', body, httpOptions).subscribe(
      data => {
        console.log(data);
        alert('Success!');
      }
    );
  }


Solution

  • Problem was on server side in validation params. Now it looks likefile: Joi.any()