Search code examples
javascriptnode.jsreactjsgraphqlantd

Not able to upload image from react Ant to Node.js server via GraphQL


I am trying to upload image from (react + Ant Design) client-side to (Node.js) server via GraphQL but I am getting this error in the form server

Could not create Operator: TypeError: Cannot read properties of undefined (reading 'filename')

I have tested the mutation through Postman and it works correctly

enter image description here

This is the frontend code:

const [fileList, setFileList] = useState<File[]>([]);

<Form.Item name={"files"} label="Image" valuePropName='fileList'
           getValueFromEvent={(event)=>{
              return event?.fileList
           }}>
         <Upload  accept="image/png, image/jpeg" maxCount={1}
              fileList={fileList as any}
              beforeUpload={(_, fileList) => {
                  setFileList(fileList);
                  return false;
              }}
              customRequest={(info)=>{
               setFileList([info?.file as File]) 
              }}
              showUploadList={false}
              listType="picture-card">
                <div>
                  <PlusOutlined />
                  <div style={{ marginTop: 8 }}>Upload image</div>
                  {fileList[0]?.name}
                </div>
          </Upload>
 </Form.Item>

The mutation takes 2 arguments (input data and file):

    type Mutation {
       createOperator(request: OperatorInput, file: Upload): Operator
    }

I'm passing the params to the mutation like this:

    const [mutation, { loading }] = useMutation<Response, Request>(CREATE_OPERATOR);
    const result = await mutation({ variables: { request, file } });

What I realized that via postman request the file will reach the server and it includes:

Upload {
 resolve: [Function (anonymous)],
 reject: [Function (anonymous)],
 promise: Promise {
  {
    fieldName: '0',
    filename: 'IMG_20230411_181040.jpg',
    mimetype: 'image/jpeg',
    encoding: '7bit',
    createReadStream: [Function: createReadStream]
  }
},
file: {
  fieldName: '0',
  filename: 'IMG_20230411_181040.jpg',
  mimetype: 'image/jpeg',
  encoding: '7bit',
  createReadStream: [Function: createReadStream]
 }
}

And this is correct, then I am using it to save the image in the Cloud. But from the client-side am not getting this promise and the above attributes.

It just an object contains the following:

{
  uid: 'rc-upload-1690197951111-71',
  lastModified: 1688137614360,
  lastModifiedDate: '2023-06-30T15:06:54.360Z',
  name: 'IMG_20230411_181040.jpg',
  size: 13313470,
  type: 'image/jpeg',
  percent: 0,
  originFileObj: { uid: 'rc-upload-1690197951111-71' }
}

I assume that my frontend code is not sending the file correctly.


Solution

  • The solution was to enable the multipart request on the client-side in the index.js file by adding link: createUploadLink() instead of link: new HttpLink

    I am using graphql-upload on server-side

    See below:

    import { createUploadLink } from 'apollo-upload-client';
    
    const option = {
      uri: "http://localhost:4000/graphql",
      credentials: "include"
    }
     const client = new ApolloClient({
        cache: new InMemoryCache(),
        link: createUploadLink(option),
    
        /*link: new HttpLink({
            uri: "http://localhost:4000/graphql",
            credentials: "include"
        }),*/
    });
    

    For more details, see the installation section of apollo-upload-client