Need help understanding why my backend Nodejs isn't receiving my React Redux frontend's image upload request body

Viewed 70

Solved

My Create image request works on my back end, using insomnia, but fails in my front end because my front end's sending an empty request body to my back end. I have tried different ways of setting up my form's handle submit including passing it the files state. But, I have defaulted to the method that my instructor taught us of using a FormData() constructor. I'm not sure if theres conflicts with react-final-form state management library. I have tried moving my multer request after my middleware.

GitHub Repo

Error:

(node:20062) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'originalname' of undefined
    at CreateImage (/Users/weijunxia/GA_SEIR/projects/gentlyused/controllers/ImageController.js:29:65)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:20062) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:20062) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Executing (default): INSERT INTO "images" ("file_name","image_product_id","image_user_id","createdAt","updatedAt") VALUES ($1,$2,$3,$4,$5) RETURNING "file_name","image_product_id","image_user_id","createdAt","updatedAt";
(node:20062) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'originalname' of undefined
    at CreateImage (/Users/weijunxia/GA_SEIR/projects/gentlyused/controllers/ImageController.js:29:65)
    at processTicksAndRejections (internal/process/task_queues.js:95:5)
(node:20062) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)

Front end: Sell Component

import React, { useEffect, useState } from 'react'
import { SetAWSS3ImageUrl } from '../store/actions/ImageActions'
import { connect, useDispatch } from 'react-redux'

const mapStateToProps = ({ imageState, productState, authenticationState }) => {
  return { imageState, productState, authenticationState }
}

const mapDispatchToProps = (dispatch) => {
  return {
    setS3Url: ({ image_user_id, image_product_id, file_name }) =>
      dispatch(
        SetAWSS3ImageUrl({
          image_user_id,
          image_product_id,
          file_name
        })
      ),
  }
}

function Sell(props) {
  const [files, setFiles] = useState()
  const [form, setForm] = useState({
    file_name: null
  })
  const [uploaded, setUploaded] = useState(false)

  function handleFormChange(e) {
    setFiles(e.target.files[0])
  }
  const handleSubmit = async (e) => {
    e.preventDefault()
    let formData = new FormData()


    formData.append(form.file_name, files)
    const res = await props.setS3Url(formData)
    return res
  }
  return (
    <div className="sell">
      <div>{sellPage}</div>
      <form onSubmit={handleSubmit}>
        <label>Upload Your Product Photos</label>
        <input type="file" onChange={handleFormChange}></input>
        <button>Upload</button>
      </form>
    </div>
  )
}
export default connect(mapStateToProps, mapDispatchToProps)(Sell)

Image Service:

import Client from '.'

export const GetUploadUrl = async ({
  image_user_id,
  image_product_id,
  file_name
}) => {
  try {
    const res = await Client.post('/images/upload', {
      image_user_id,
      image_product_id,
      file_name
    })
    return res
  } catch (error) {
    throw error
  }
}

Image Action:

import {
  GetUploadUrl,
  DeleteImage,
  GetAllImages
} from '../../services/ImageServices'
const {
  SET_AWS_S3_IMAGE_URL,
  GET_ALL_IMAGES,
  DELETE_IMAGE
} = require('../types')

export const SetAWSS3ImageUrl = ({
  image_user_id,
  image_product_id,
  file_name
}) => {
  return async (dispatch) => {
    try {
      const s3Url = await GetUploadUrl({
        image_user_id,
        image_product_id,
        file_name
      })
      dispatch({ type: SET_AWS_S3_IMAGE_URL, payload: s3Url })
    } catch (error) {
      throw error
    }
  }
}

Image Reducer:

import { SET_AWS_S3_IMAGE_URL, GET_ALL_IMAGES, DELETE_IMAGE } from '../types'

const iState = {
  allImages: [],
  awsS3ImageUrl: ''
}

const ImageReducer = (state = iState, action) => {
  switch (action.type) {
    case SET_AWS_S3_IMAGE_URL:
      return { ...state, awsS3ImageUrl: action.payload }
    case GET_ALL_IMAGES:
      return { ...state, allImages: action.payload }
    case DELETE_IMAGE:
      return { ...state, allImages: action.payload }
    default:
      return state
  }
}

export default ImageReducer

reducers index.js:

import { createStore, combineReducers, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'
import AuthReducer from './reducers/AuthReducer'
import ProductReducer from './reducers/ProductReducer'
import UserReducer from './reducers/UserReducer'
import ImageReducer from './reducers/ImageReducer'
import OrderReducer from './reducers/OrderReducer'
import FavoriteReducer from './reducers/FavoriteReducer'

const store = createStore(
  combineReducers({
    productState: ProductReducer,
    userState: UserReducer,
    authenticationState: AuthReducer,
    imageState: ImageReducer,
    orderState: OrderReducer,
    favoriteState: FavoriteReducer
  }),
  composeWithDevTools(applyMiddleware(thunk))
)

export default store

Backend:

Image Controller:

const { Image, User, Product } = require('../models')
const uploader = require('../middleware/uploader')
const path = require('path')
const DeleteImage = async (req, res) => {
  try {
    await Image.destroy({ where: { id: req.params.id } })
    res.send({
      msg: 'Your Post has been Deleted',
      payload: req.params.image_id,
      status: 'Ok'
    })
  } catch (error) {
    throw error
  }
}
const GetImage = async (req, res) => {
  try {
    const response = await Image.findAll()
    res.send(response)
  } catch (error) {
    throw error
  }
}
const CreateImage = async (req, res) => {
  try {
    let file = req.file
    // let productId = req.body.image_product_id
    const image = await Image.build({ ...req.body })
    let fileName = `${new Date().getTime()}-${path.extname(file.originalname)}`
    let fileParams = {
      Key: `${fileName}`,
      Body: file.buffer,
      ACL: 'public-read',
      Bucket: 'gently-used',
      ContentEncoding: file.encoding,
      ContentLength: file.size,
      ContentType: file.mimetype
    }
    await uploader.upload(fileParams)
    // const image = await Image.create({
    //   ...req.body,
    //   file_name: `https://d1p3fszk6htgk4.cloudfront.net/${fileName}`
    // })
    image.file_name = `https://d1p3fszk6htgk4.cloudfront.net/${fileName}`
    image.save()
    res.send(image)
  } catch (error) {
    throw error
  }
}

module.exports = {
  GetImage,
  CreateImage,
  DeleteImage
}

Image Router:

const controller = require('../controllers/ImageController')
const middleware = require('../middleware')
const Router = require('express').Router()

const multer = require('multer')
const storage = multer.memoryStorage()
const upload = multer({ storage })

Router.get('/all', controller.GetImage)
Router.post(
  '/upload',
  // middleware.stripToken,
  // middleware.verifyToken,
  upload.single('file_name'),
  controller.CreateImage
)

Router.delete(
  '/delete/:id',
  middleware.stripToken,
  middleware.verifyToken,
  controller.DeleteImage
)

module.exports = Router
0 Answers
Related