I am struggling to figure out why I’m not able to successfully upload images to the Files section of my Shopify store. I followed this code here, except mine is a Python version of this: https://gist.github.com/celsowhite/2e890966620bc781829b5be442bea159
import requests
import os
# Set up Shopify API credentials
shopify_store = 'url-goes-here.myshopify.com' // the actual URL is here
access_token = 'token-goes-here' // the actual token is here
# Read the image file
image_path = r'C:the-actual-filepath-is-hereAPI-TEST-1.jpg' # Replace with the actual path to your image file
with open(image_path, 'rb') as file:
image_data = file.read()
# Create staged upload
staged_upload_url = f"https://{shopify_store}/admin/api/2023-04/graphql.json"
staged_upload_query = '''
mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
stagedUploadsCreate(input: $input) {
stagedTargets {
resourceUrl
url
parameters {
name
value
}
}
userErrors {
field
message
}
}
}
'''
staged_upload_variables = {
"input": [
{
"filename": "API-TEST-1.jpg",
"httpMethod": "POST",
"mimeType": "image/jpeg",
"resource": "FILE"
}
]
}
response = requests.post(
staged_upload_url,
json={"query": staged_upload_query, "variables": staged_upload_variables},
headers={"X-Shopify-Access-Token": access_token}
)
data = response.json()
staged_targets = data['data']['stagedUploadsCreate']['stagedTargets']
target = staged_targets[0]
params = target['parameters']
url = target['url']
resource_url = target['resourceUrl']
# Post image data to the staged target
form_data = {
"file": image_data
}
headers = {
param['name']: param['value'] for param in params # Fix the headers assignment
}
headers["Content-Length"] = str(len(image_data))
response = requests.post(url, files=form_data, headers=headers) # Use 'files' parameter instead of 'data'
# Create the file in Shopify using the resource URL
create_file_url = f"https://{shopify_store}/admin/api/2023-04/graphql.json"
create_file_query = '''
mutation fileCreate($files: [FileCreateInput!]!) {
fileCreate(files: $files) {
files {
alt
}
userErrors {
field
message
}
}
}
'''
create_file_variables = {
"files": [
{
"alt": "alt-tag",
"contentType": "IMAGE",
"originalSource": resource_url
}
]
}
response = requests.post(
create_file_url,
json={"query": create_file_query, "variables": create_file_variables},
headers={"X-Shopify-Access-Token": access_token}
)
data = response.json()
files = data['data']['fileCreate']['files']
alt = files[0]['alt']
It runs the code, it doesn’t output any errors. However when I navigate to the Files section of the Shopify store, it says "1 upload failed — processing error."
Any clues in the code as to what might be causing that?
Also when I print(data) at the very end, this is what it says:
{‘data’: {‘fileCreate’: {‘files’: [{‘alt’: ‘alt-tag’}], ‘userErrors’: []}}, ‘extensions’: {‘cost’: {‘requestedQueryCost’: 20, ‘actualQueryCost’: 20, ‘throttleStatus’: {‘maximumAvailable’: 1000.0, ‘currentlyAvailable’: 980, ‘restoreRate’: 50.0}}}}
Seeming to indicate it created it successfully. But there’s some misc processing error.
Thanks
1
1 Answer
Shopify does make it hard work to do simple things sometimes, I’m sure it’s on purpose at times. I’ve spent two days trying to find a working method for uploading images. OP’s code was super close to working, however, it was corrupting the image while uploading by adding:
--460f1914a62abdf36f0115337cf3577d Content-Disposition: form-data; name="file"; filename="file"
To the head of the image file, very confusing, I’ve read why but I’m still not to clear on the how… 😕
After much reading/thinking/coffee/screaming I offer the following code which works for me and should fix OP’s issue. The answer was in the way the file got sent, modifying the answer given here: Prepared Requests we can now send unmolested file data 😁🎉
Bonus feature: I’ve added a final query to pull to URL out of Shopify, why it can’t give you the URL on upload I’ll never know.
import requests
import os
from time import sleep
# Set up Shopify API credentials
shopify_store = 'url-goes-here.myshopify.com' // the actual URL is here
access_token = 'token-goes-here' // the actual token is here
# Read the image file
image_path = r'C:the-actual-filepath-is-hereAPI-TEST-1.jpg' # Replace with the actual path to your image file
with open(image_path, 'rb') as file:
image_data = file.read()
# Create staged upload
staged_upload_url = f"https://{shopify_store}/admin/api/2023-04/graphql.json"
staged_upload_query = '''
mutation stagedUploadsCreate($input: [StagedUploadInput!]!) {
stagedUploadsCreate(input: $input) {
stagedTargets {
resourceUrl
url
parameters {
name
value
}
}
userErrors {
field
message
}
}
}
'''
staged_upload_variables = {
"input": [
{
"filename": filename,
"httpMethod": "PUT",
"mimeType": mimetype,
"resource": "IMAGE"
}
]
}
response = requests.post(
staged_upload_url,
json={"query": staged_upload_query, "variables": staged_upload_variables},
headers={"X-Shopify-Access-Token": access_token}
)
data = response.json()
staged_targets = data['data']['stagedUploadsCreate']['stagedTargets']
target = staged_targets[0]
params = target['parameters']
url = target['url']
resource_url = target['resourceUrl']
############ START NEW CODE ############
# Post image data to the staged target
headers = {
param['name']: param['value'] for param in params # Fix the headers assignment
}
image_length = len(image_data) # We need this in a couple of places
headers["Content-Length"] = str(image_length)
req = requests.Request('PUT', url, headers)
prepped = req.prepare()
try:
with open(image_path, 'rb') as f:
prepped.body = f.read(image_length)
s = requests.Session()
r = s.send(prepped, stream=True)
print ('File sent OK')
except Exception as error:
print (f'File send error: {error}')
############ END NEW CODE ############
# Create the file in Shopify using the resource URL
create_file_url = f"https://{shopify_store}/admin/api/2023-04/graphql.json"
create_file_query = '''
mutation fileCreate($files: [FileCreateInput!]!) {
fileCreate(files: $files) {
files {
alt
createdAt
fileStatus
... on MediaImage {
id
image {
url
height
width
}
}
}
userErrors {
field
message
}
}
}
'''
create_file_variables = {
"files": [
{
"alt": "alt-tag",
"contentType": "IMAGE",
"originalSource": resource_url
}
]
}
response = requests.post(
create_file_url,
json={"query": create_file_query, "variables": create_file_variables},
headers={"X-Shopify-Access-Token": access_token}
)
data = response.json()
files = data['data']['fileCreate']['files']
alt = files[0]['alt']
created = files[0]['createdAt']
############ GET IMAGE URL ############
# Adapted from https://community.shopify.com/c/graphql-basics-and/file-api-get-the-file-url-after-it-s-being-uploaded-successfully/m-p/1445697/highlight/true#M903
sleep(10) # Give GraphQL a chance to show results
find_img = '''query {
files (first: 1, query:"created_at:'%(created)s'") {
edges {
node {
... on MediaImage {
image {
id
url
altText
height
width
}
}
}
}
}
}''' % {'created': created}
find_img = requests.post(staged_upload_url,json={"query": find_img},headers={"X-Shopify-Access-Token": access_token})
find_img_data = find_img.json()
############ END GET IMAGE URL ############
print(data)
print(find_img_data)
Follow-up: I get a Response 503 at this specific step. The other steps appear to be successful. # Post image data to the staged target form_data = { "file": image_data } headers = { param['name']: param['value'] for param in params # Fix the headers assignment } headers["Content-Length"] = str(len(image_data)) response = requests.post(url, files=form_data, headers=headers) # Use 'files' parameter instead of 'data' print(response)
Jun 2 at 19:44