skip to Main Content

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

2

Answers


  1. 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.

    EDIT: Updated the url retrieval query to use id rather than created_at, fixes weird glitch where Shopify selects an older random image.

    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']
    id = files[0]['id'].split('gid://shopify/MediaImage/')[1] # We only need the number
    
    ############  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:"id:'%(id)s'") {
            edges {
            node {
                ... on MediaImage {
                image {
                    id
                    url
                    altText
                    height
                    width
                }
                }
            }
            }
        }
    }''' % {'id': id}
    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)
    
    Login or Signup to reply.
  2. What works for me is to put everything into form data, passed as the files param in requests.

    form_data = {
        param['name']: param['value'] for param in params 
    }
    form_data['file'] = image_data
    headers["Content-Length"] = str(len(image_data) + 500)
    response = requests.post(url, files=form_data, headers=headers)
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search