A space to discuss GraphQL queries, mutations, troubleshooting, throttling, and best practices.
I am following a number of resources on the Shopify documentation website and blog around using the `stagedUploadsCreate` mutation to create a staged URL, however, once I try and use the staged resource URL in a later `productCreateMedia` mutation, the image is not attached to the product.
Docs: https://shopify.dev/api/examples/product-media
I suspect that there may be an issue with the S3 object being uploaded as private. If I manually try to visit the S3 object URL represented by `resourceUrl`, I receive an "access denied" response. I suspect that this may be resulting in the Shopify backend being unable to request the file during the `productCreateMedia` mutation as well. The strange thing is that `productCreateMedia` does not return any errors, the errors only show on the Shopify admin dashboard. Example below.
Is the URL given to `productCreateMedia` supposed to be a signed S3 object URL? If so, how would you produce such a URL?
I did notice that when using `PUT` for the `httpMethod` for `stagedUploadsCreate`, the uploadUrl seems to come back as signed or with additional query params, however when using `POST` that is not the case.
Example Code (stagedUploadsCreate)
const input = [
{
fileSize: file.size.toString(),
filename: file.originalname,
httpMethod: "POST",
mimeType: file.mimetype,
resource: "IMAGE",
}
];
const {body} = await client.query({
data: {
query: `
mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
stagedUploadsCreate(input: $input) {
stagedTargets {
resourceUrl
url
parameters {
name
value
}
}
userErrors {
field
message
}
}
}
`,
variables: {
input
}
}
});
Example Code (upload):
import fetch, {FormData} from 'node-fetch'
const formData = new FormData();
parameters.forEach(({name: paramName, value}) => {
formData.append(paramName, value)
});
formData.append('file', file.buffer, {
contentType: file.mimetype,
filename: file.originalname
});
const response = await fetch(uploadUrl, {
method: 'POST',
body: formData
});
Example Code (productCreateMedia):
const variables = {
id: productId,
media: [
{
originalSource: resourceUrl,
mediaContentType: "IMAGE"
}
]
};
const {body} = await client.query({
data: {
query: `
mutation createProductMedia(
$id: ID!
$media: [CreateMediaInput!]!
) {
productCreateMedia(productId: $id, media: $media) {
media {
mediaContentType
preview {
image {
id
}
}
mediaErrors {
code
details
message
}
mediaWarnings {
code
message
}
}
product {
id
}
mediaUserErrors {
code
field
message
}
}
}
`,
variables
}
});
I ultimately found the solution by reading this post: https://community.shopify.com/c/shopify-apis-and-sdks/full-process-for-uploading-files-to-the-files-...
My issue was that I was not passing the required headers for the request to upload the file to the AWS staging URL. Once I add the headers from `formData.getHeaders()`, the Shopify backend was then able to retrieve the image data and upload it to my product.