Shopify Processing Error On File Upload Through JS/GraphQL

Shopify Processing Error On File Upload Through JS/GraphQL

ma123456
Shopify Partner
2 0 0
0

I am implementing a simple solution that allows the user to select a file (any type of image). Once selected, the user clicks on "Upload Image," and the API call is triggered. I am receiving a status 200 in response, but when I check the Shopify Files directory in the admin panel, it shows me a "Processing error." As you can see in the screenshot, the resourceUrl is generated correctly. I am also facing an issue in fetching the image; this is because the image has not been uploaded to Shopify, which is why the **data.data.node.image** is null. Please review the JavaScript code below and let me know the possible reasons that could be causing this Processing error.

I have tried to upload different image types png,jpg with small size but still same issue.

Screenshot_3.png
api-responsee.png

<h1>Upload Image</h1>
<input type="file" id="file-input">
<button id="upload-button">Upload Image</button>

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>

const adminApiUrl = 'GRAPHQL_URL';

document.getElementById('upload-button').addEventListener('click', async () => {
    const fileInput = document.getElementById('file-input');
    const selectedFile = fileInput.files[0];
    
    if (selectedFile) {
        // const fileSize = selectedFile.size.toString();
        const file = selectedFile.name;
        try {
            console.error('selectedFile', selectedFile);

            const stagedUploadsQuery = `mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
              stagedUploadsCreate(input: $input) {
                stagedTargets {
                  resourceUrl
                  url
                  parameters {
                    name
                    value
                  }
                }
                userErrors {
                  field
                  message
                }
              }
            }`;

            // Variables
            const stagedUploadsVariables = {
                input: {
                    resource: 'FILE',
                    filename: selectedFile.name,
                    mimeType: selectedFile.type,
                    fileSize: selectedFile.size.toString(),
                    httpMethod: 'POST',
                },
            };

            const stagedUploadsQueryResult = await axios.post(
                adminApiUrl, {
                    query: stagedUploadsQuery,
                    variables: stagedUploadsVariables,
                }, {
                    headers: {
                        "X-Shopify-Access-Token": 'ACCESS_TOKEN',
                    },
                }
            );
            const target = stagedUploadsQueryResult.data.data.stagedUploadsCreate.stagedTargets[0];
            const url = target.url;
            const resourceUrl = target.resourceUrl;
            const params = target.parameters;
            await performFileCreateTest(target.resourceUrl);
            console.log("resourceUrl", resourceUrl);
          
            const formData = new FormData();
            params.forEach(({ name, value }) => {
              formData.append(name, value);
            });
            formData.append("file", selectedFile);
            await axios.post(url, formData);
          
            alert('Image uploaded successfully!');
        } catch (error) {
            console.error('Error uploading image:', error);
            alert('Error uploading image. Please try again.');
        }
    } else {
        alert('Please select an image to upload.');
    }
});

async function performFileCreateTest(resourceUrl) {

    // Query
    const createFileQuery = `mutation fileCreate($files: [FileCreateInput!]!) {
      fileCreate(files: $files) {
          files {
              fileStatus
              ... on MediaImage {
                  id
              }
          }
          userErrors {
              field
              message
          }
      }
    }`;

    // Variables
    const createFileVariables = {
        files: {
            alt: "alt-tag",
            contentType: "IMAGE",
            originalSource: resourceUrl, 
        },
    };

    // Finally post the file to shopify. It should appear in Settings > Files.
    const createFileQueryResult = await axios.post(
        adminApiUrl, {
            query: createFileQuery,
            variables: createFileVariables,
        }, {
            headers: {
                "X-Shopify-Access-Token": `ACCESS_TOKEN`,
            },
        }
    );
    console.log("createFileQueryResult",createFileQueryResult.data.data.fileCreate.files[0].id);    
    const imageId = createFileQueryResult.data.data.fileCreate.files[0].id;
    await fetchImage(imageId);
}

const fetchImage = async (imageId) => {
  const query = `
    query getFileByID($imageId: ID!) {
      node(id: $imageId) {
        ... on MediaImage {
          id
          image {
            url
          }
        }
      }
    }
  `;

  const variables = { imageId };

  try {
    const response = await axios({
      url: adminApiUrl,
      method: 'post',
      headers: {
        'X-Shopify-Access-Token': 'ACCESS_TOKEN', 
      },
      data: {
        query: query,
        variables: variables,
      },
    });

    const image = response;
    console.log('Image originalSrc:', image);
    //console.log('Image transformedSrc:', image.transformedSrc);
    // You can now use the image URL as needed in your application
  } catch (error) {
    console.error('Error fetching image:', error);
    // Handle errors appropriately in your application
  }
};  
</script>
Replies 3 (3)

Liam
Shopify Staff
2873 312 821

Hi Ma123456,

 

Here are a few suggestions that could help troubleshoot the issue:

  1. Check your Access Token: Ensure that the 'ACCESS_TOKEN' you're using in your 'X-Shopify-Access-Token' header is valid. Any issues with the access token could lead to a processing error.

  2. Check the Order of Your Parameters: When constructing your 'formData' object, the order in which you append the parameters matters. The 'file' parameter should be the last one to be appended. If you are appending 'file' before any other parameters, Shopify may not be able to process the file.

  3. Check the Response of the 'fileCreate' Mutation: You are logging the 'id' of the created file, but not the eventual response of the 'fileCreate' mutation. There might be user errors in the response that could provide a clue as to why the file is not being processed.

  4. Check for any Errors returned by the 'stagedUploadsCreate' mutation: The 'stagedUploadsCreate' mutation may return user errors that could indicate why the file isn't uploading correctly. Make sure to log and check these errors.

I hope these help you debug and solve your issue. Good luck!

Liam | Developer Advocate @ Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

ma123456
Shopify Partner
2 0 0
stagedUploadsQueryResult

stagedUploadsQueryResult.png

createFileQueryResult

createFileQueryResult.png

For suggestion 3 and 4 please check both responses. There are 0 userErrors.
For suggestion 2, i am already appending data in the last before making post axios call so not sure what you are trying to say here.
For suggestion 1, already checked and i am using the right access token from my private app.

RohitGohel001
Shopify Partner
2 0 0

Hello, have you got a solution? because I had the same issue when I tried to upload the image below I have attached my full code.

 

 

import React, { useCallback, useEffect, useState, useRef } from "react";
import { json } from "@remix-run/node";
import { useActionData, useNavigation, useSubmit } from "@remix-run/react";
import {
  Page,
  Layout,
  Card,
  Button,
  BlockStack,
  Box,
  InlineStack,
  DropZone,
  LegacyStack,
  Thumbnail,
  Text,
} from "@shopify/polaris";
import { authenticate } from "../shopify.server";
import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node";

export const loader = async ({ request }: LoaderFunctionArgs) => {
    await authenticate.admin(request);

    return null;
};

export const action = async ({ request }: ActionFunctionArgs) => {
    const { admin } = await authenticate.admin(request);

    const requestBody = await request.text();

    const formData = new URLSearchParams(requestBody);
    const name = formData.get("filename");
    const type = formData.get("filetype");
    const size = formData.get("filesize");
    const files = [
        {
            name: name,
            type: type,
            size: size,
        },
    ];

    const prepareFiles = (files: { name: string | null; type: string | null; size: string | null; }[]) =>
        files.map((file) => ({
            filename: file.name,
            mimeType: file.type,
            resource: file.type?.includes("image") ? "IMAGE" : "FILE",
            fileSize: file.size?.toString(),
            httpMethod: "PUT",
        }));


    const preparedFiles = prepareFiles(files);

    const uploadFileResponse = await admin.graphql(
        `#graphql
        mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
        stagedUploadsCreate(input: $input) {
            stagedTargets {
            resourceUrl
            url
            parameters {
                name
                value
            }
            }
            userErrors {
            field
            message
            }
        }
        }
    `,
        { variables: { input: preparedFiles } },
    );

    const uplodeFileJson = await uploadFileResponse.json();

    const resourceurl = uplodeFileJson.data.stagedUploadsCreate.stagedTargets[0].resourceUrl;

    const fileCreateResponse = await admin.graphql(
        `#graphql
        mutation fileCreate($files: [FileCreateInput!]!) {
            fileCreate(files: $files) {
                files {
                    alt
                    createdAt
                    fileErrors {
                        code
                        details
                        message
                    }
                    fileStatus
                    preview {
                        image {
                        url
                        }
                        status
                    }
                }
                userErrors {
                    field
                    message
                }
            }
        }`,
        {
            variables: {
                files: {
                    alt: "Image",
                    contentType: "IMAGE",
                    originalSource: resourceurl,
                },
            },
        },
    );

    const fileCreateJson = await fileCreateResponse.json();

    return json({
        stagedUpload: uplodeFileJson,
        fileCreate: fileCreateJson,
        resourceurl: resourceurl,
        prepareFiles: prepareFiles
    });
};

export default function Index() {
    const nav = useNavigation();
    const actionData = useActionData();
    const submit = useSubmit();
    const isLoading = ["loading", "submitting"].includes(nav.state) && nav.formMethod === "POST";

    useEffect(() => {
        if (actionData) {
        shopify.toast.show("Product created");
        }
    }, [actionData]);

    const [files, setFiles] = useState<File[]>([]);
    const inputRef = useRef<HTMLInputElement>(null);

    const handleDropZoneDrop = useCallback(
        async (_dropFiles: File[], acceptedFiles: File[], _rejectedFiles: File[]) => {
        if (acceptedFiles.length) {
            setFiles((prevFiles) => [...prevFiles, ...acceptedFiles]);
            for (const file of acceptedFiles) {
                // console.log(file.name);
                // console.log(file.size);
                // console.log(file.type);
            }
        }
        },
        [],
    ); 
    const validImageTypes = ["image/gif", "image/jpeg", "image/png"];

    const fileUpload = !files.length && <DropZone.FileUpload />;
    const uploadedFiles = files.length > 0 && (
        <div style={{ padding: "0" }}>
        <LegacyStack vertical>
            {files.map((file, index) => (
            <LegacyStack alignment="center" key={index}>
                <Thumbnail
                size="small"
                alt={file.name}
                source={
                    validImageTypes.includes(file.type)
                    ? window.URL.createObjectURL(file)
                    : ""
                }
                />
                <div>
                {file.name}{" "}
                <Text variant="bodySm" as="p">
                    {file.size} bytes
                </Text>
                </div>
            </LegacyStack>
            ))}
        </LegacyStack>
        </div>
    );

    const generateProduct = () => {
        const filename = files[0]?.name;
        const filetype = files[0]?.type;
        const filesize = files[0]?.size;
        submit({ filename, filetype, filesize }, { replace: true, method: "PUT" });
    };

    return (
        <Page>
        <BlockStack gap="500">
            <Layout>
            <Layout.Section>
                <Card>
                <InlineStack gap="300">
                    <DropZone onDrop={handleDropZoneDrop}>
                        {uploadedFiles}
                        {fileUpload}
                    </DropZone>
                    <Button loading={isLoading} onClick={generateProduct}>
                        Generate a product
                    </Button>
                </InlineStack>
                </Card>
            </Layout.Section>
            </Layout>
        </BlockStack>
        </Page>
    );
};