Search code examples
reactjsspringspring-restformikdropzone

Spring rest with React (dropzone and Formik)


I'm trying to build an endpoint where I can post a JSON message with an image to upload. But whenever I send the request from the frontend, I got null values.

I have tested this endpoint with Postman, and it works just fine.

This is my server code:

  @PostMapping
  public ResponseEntity<Product> createProduct(@ModelAttribute @Valid ProductJson product) {
    return new ResponseEntity<>(productService.createNewProduct(product), HttpStatus.CREATED);
  }

And this is the JSON class,

@Getter
@Setter
public class ProductJson {

  @NotNull
  private String productName;
  @NotNull
  private String productPrice;
  @NotNull
  private String categoryId;
  @NotNull
  private MultipartFile productImage;
}

in the frontend I'm using react with Formik and dropzone:

export const addProduct = (data) =>
fetch(MANAGEMENT_PRODUCTS_URL, {
    headers: {
      Authorization: 'Bearer ' + localStorage.getItem(ACCESS_TOKEN)
    },
    method: 'POST',
    body: JSON.stringify(data)
  }).then(checkStatus);

<Formik
        className='pt-4'
        initialValues={{
          productName: '',
          productPrice: '',
          categoryId: '',
          productImage: null
        }}
        validationSchema={validationSchema}
        onSubmit={(productForm, { setSubmitting }) => {
          addProduct(productForm)
            .then(res => {
              console.log(res);
              setSubmitting(false);
            })
            .catch(err => {
              console.log(err);
            });
        }}
      >
        {({ submitForm, setFieldValue }) => (
            <Form>
              <FormGroup row>
                  <Field
                    type='productName'
                    name='productName'
                    placeholder='Insert name of the product'
                    as={Input}
                  />
              </FormGroup>
              <FormGroup row>
                  <Field
                    type='text'
                    name='productPrice'
                    placeholder='Insert price of the product'
                    as={Input}
                  />
              </FormGroup>
              <FormGroup row>
                  <Field name='categoryId' component={CategoryDropDown} />
              </FormGroup>
              <FormGroup row>
                  <Dropzone3D setFieldValue={setFieldValue} />
              </FormGroup>
            </Form>
        )}
      </Formik>

and this is the place where I upload the image:

export const Dropzone3D = props => {
  const onDrop = useCallback(
    acceptedFiles => {
      let productImage = acceptedFiles[0];
      props.setFieldValue("productImage", productImage);
    },
    [props]
  );

  const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });

  return (
    <div
      {...getRootProps({
        onClick: event => event.preventDefault()
      })}
    >
      <input {...getInputProps()} />
      {isDragActive ? (
        <Button color='info'>Drop the image here ...</Button>
      ) : (
        <Button color='info' outline>
          Drag n drop or click to select an image
        </Button>
      )}
    </div>
  );
};

Solution

  • Ok, so I found the solution for this problem.

    1. I used axios library instead of fetch.
    2. I created a new formData object in the Submit method.

    I hope I can help someone with this example!

    <Formik
        className='pt-4'
        initialValues={{
          productName: '',
          productPrice: '',
          categoryId: '',
          productImage: ''
        }}
        validationSchema={validationSchema}
        onSubmit={(product, { setSubmitting }) => {
          const formData = new FormData();
          formData.append('productImage', product.productImage);
          formData.append('productName', product.productName);
          formData.append('productPrice', product.productPrice);
          formData.append('categoryId', product.categoryId);
    
          addProduct(formData)
            .then(res => {
              setSubmitting(false);
            })
            .catch(err => {
              console.log(err);
              setSubmitting(false);
            });
        }}
      >