A space to discuss GraphQL queries, mutations, troubleshooting, throttling, and best practices.
Afternoon folks,
I'm trying to use the new Files API, in concert with the stagedUploadsCreate mutation, to allow our client to upload images through an Admin app that we are creating for them. The image data is going to be coupled to some other custom product metadata, which we'll handle in the background - hence not wanting to use the out-of-the-box Files interface.
I've reviewed this blog post, as well as the Files API release notes and the fileCreate mutation docs, so I think I understand the process correctly:
My implementation of this in my React (Typescript) app looks something like this:
// given imageFile, which is a File that has been selected by the user using the Polaris DropZone component
const STAGED_UPLOADS_CREATE = gql`
mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
stagedUploadsCreate(input: $input) {
stagedTargets {
resourceUrl
url
parameters {
name
value
}
}
userErrors {
field
message
}
}
}
`;
const FILE_CREATE = gql`
mutation fileCreate($files: [FileCreateInput!]!) {
fileCreate(files: $files) {
files {
alt
createdAt
... on MediaImage {
id
mediaErrors {
code
details
message
}
fileStatus
status
image {
originalSrc
transformedSrc
}
}
}
userErrors {
code
field
message
}
}
}
`;
const [
stagedUploadsCreate,
{ error: stagedUploadsCreateError },
] = useMutation(STAGED_UPLOADS_CREATE);
const [fileCreate, { error: fileCreateError }] = useMutation(FILE_CREATE);
const { data: stagedUploadsCreateData } = await stagedUploadsCreate({
variables: {
input: {
resource: "IMAGE",
filename: imageFile.name,
mimeType: imageFile.type,
fileSize: imageFile.size.toString(),
httpMethod: "POST",
},
},
});
console.log(stagedUploadsCreateData);
const {
stagedUploadsCreate: {
stagedTargets: [{ url, parameters, resourceUrl }],
},
} = stagedUploadsCreateData;
const formData = new FormData();
parameters.forEach(({ name: paramName, value }: any) =>
formData.append(paramName, value),
);
formData.append("file", imageFile);
await axios.post(url, formData);
const { data: fileCreateData } = await fileCreate({
variables: {
files: [{ contentType: "IMAGE", originalSource: resourceUrl }],
},
});
This all goes fine - I stepped through the network requests, and I get a 201 response code back from the file upload request, and then I can see that the fileCreate mutation runs successfully. In the status field of the returned object, I can see that the status is "UPLOADED".
However, when I go to the Files UI in Shopify Admin, I get the error:
3 files failed to upload
The rest of your files uploaded successfully. View failed files for more details.
(As you might guess, I've tried this with 3 different files so far!)
When I query the files resource via the API to get a closer look, I see the follow response:
As far as I can tell, I'm using the API as intended. Unfortunately, there doesn't seem to be a great deal in the way of documented examples for using this API at the moment. Can anyone point me in the right direction please? I'm sure I'm making some small mistake, but just can't for the life of me figure out what.
Thanks in advance, and have a great day folks!
James.
Responding to give this thread a bump.
I've also reached out for support via Shopify Partners live chat, who have told me that they don't have the technical know-how to look into this, and just pointed me back to these forums and the documentation. I've noticed a couple of other comments/threads (here, here) where people are also having problems with this API, which suggests more clarification in general may be needed around this new functionality.
Can anyone help please?
Thanks,
James
Bumping again.
Can anyone offer any suggestions please?
Hey @JBraund - I was able to share some insights on uploading a "FILE" (type text/json) using the stagedUploadsCreate mutation, and shared steps and examples in the first forum post you mentioned was related. If you are still have an issue, please feel free to provide an x-request-id header returned from both mutations in the process? It would also help if could provide examples of the RAW API query and variables that your application is generating, as well as the format of your cURL or HTTP request to the S3 bucket where the upload is meant to be staged. I would be happy to take a closer look from there and pass on any insights I can to help!
awwdam | API Support @ 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
Just in case anyone comes across this and the solution is not clear, I got it working by changing the stagedUploadsCreate "resource" variable to FILE instead of IMAGE.
Example:
let { data } = await stagedUploadsCreate({
variables: {
"input": [
{
"resource": "FILE",
"filename": file.name,
"mimeType": file.type,
"fileSize": file.size.toString(),
"httpMethod": "POST"
}
]
}
});
@mariannef You are a life saver! I was able to make it work by changing "IMAGE" to "FILE"
Thank you so much!
Thank you! This took so long to debug and figure out.
@Shopify - Please make a comprehensive example of how to use this api StagedUploadCreate -> AWS posting -> FileCreate and explain nuances like this. A single article could save a lot of us days of work.
Here is a complete breakdown of how to upload files using the Files API https://community.shopify.com/c/shopify-apis-and-sdks/full-process-for-uploading-files-to-the-files-...
@JBraund @awwdam @mariannef I'm having the same issue, I tried changing from IMAGE to FILE but still the post request returns bad request, I use fetch instead of axios. Would you kindly take a look at my code here:
https://community.shopify.com/c/graphql-basics-and/image-file-upload-through-graphql-api-processing-...