Solved

Upload Video using Graph QL

AndreFonseca
Shopify Partner
7 0 0

Hi!

 

I'm trying to upload a video using the Graph QL API. I successfully receive the answer with the mutation 

stagedUploadsCreate. Then, I try to use that info to upload the file but I'm getting the following response:
 
<?xml version='1.0' encoding='UTF-8'?><Error><Code>AccessDenied</Code><Message>Access denied.</Message><Details>Anonymous caller does not have storage.objects.create access to the Google Cloud Storage object. Permission 'storage.objects.create' denied on resource (or it may not exist).</Details></Error>
 
I'm doing a POST for the provided URL resource . I already tryed to to use the mutation with FILE and VIDEO as resource. Depending on that parameter, I get a different number os parameters from Shopify. However, none of them work. Can anyone help me?
Accepted Solution (1)
ShopifyDevSup
Shopify Staff
1322 216 456

This is an accepted solution.

Hey @AndreFonseca , thanks for sharing those additional details. 

 

I went through to test on my own, and it was working properly. Let me what what I did and maybe we can narrow down where it's failing for you. 

Step 1. Staged Uploads create 

This was my mutation 

 

mutation generateStagedUploads {
   stagedUploadsCreate(
       input: [
           {
               filename: "testForMedia.mp4"
               mimeType: "video/mp4"
               resource: VIDEO
               fileSize: "17404311"
           }
       ]
   ) {
       stagedTargets {
           url
           resourceUrl
           parameters {
               name
               value
           }
       }
       userErrors {
           field
           message
       }
   }
}

That returned the staged targets the same as in the example here https://shopify.dev/docs/apps/online-store/media/products#generate-the-upload-url-and-parameters 

 

Noting in particular the resourceURL returned. Looking at the example above, this may be where it's going wrong.

"resourceUrl": "https://shopify-video-production-core-originals.storage.googleapis.com?external_video_id=8490719",

 

Step 2, I created a CURL POST request with the details from above response. If successful, this will return a 204 status with no content

 

curl -v \
 -F "GoogleAccessId=REDACTED" \
 -F "key=REDACTED" \
 -F "policy=REDACTED" \
 -F "signature=REDACTED" \
 -F "file=@/path/to/your/file.mp4" \
 "https://shopify-video-production-core-originals.storage.googleapis.com"

Step 3, is productCreateMedia mutation using the product GID that I want to apply to the video and the resourceURL from step 1 as the original source.  

 

mutation createProductMedia {
 productCreateMedia(productId: "gid://shopify/Product/[redacted]", media: [
   {
     originalSource: "https://shopify-video-production-core-originals.storage.googleapis.com?external_video_id=8490719",
     alt: "Video showing nothing really",
     mediaContentType: VIDEO
   }
 ]) {
   media {
     ... fieldsForMediaTypes
     mediaErrors {
       code
       details
       message
     }
     mediaWarnings {
       code
       message
     }
   }
   product {
     id
   }
   mediaUserErrors {
     code
     field
     message
   }
 }
}

fragment fieldsForMediaTypes on Media {
 alt
 mediaContentType
 preview {
   image {
     id
   }
 }
 status
 ... on Video {
   id
   sources {
     format
     height
     mimeType
     url
     width
   }
 }
}

The response here returns the video, with the status field likely to be uploaded meaning it's uploaded, but not yet processed or ready. 

 

Step 4. is retrieve media object with a product query. For this step I'm mainly interested in the status of the video. 

 

Here's a simplified query that will return the product title and the status of the media. 

 

{
 product(id:"gid://shopify/Product/[redacted]") {
   title
   media(first:5) {
     edges {
       node {
         status
       }
     }
   }
 }
}

This returned the following status of Ready, confirming the video has completed processing. If any other status is returned, the video is not yet processed. : 

"data": {
       "product": {
           "title": "Coffee Maker",
           "media": {
               "edges": [
                   {
                       "node": {
                           "status": "READY"
                       }
                   }
               ]
           }
       }
   },

Step 5, I visit my product page and the video is available. 

 

Let me know if that helps! 

 

- Kyle G.

Developer Support @ Shopify
- Was this reply helpful? Click Like to let us 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

View solution in original post

Replies 8 (8)

AndreFonseca
Shopify Partner
7 0 0

UPDATE: I managed to upload the file to Google Storage with CURL. Then I was able to create the video file using the resourceURL on the fileCreate mutation. However, I cannot add that video to the product. Accordingly to the documentation I must use the resourceUrl as the originalSource of the productCreateMedia mutation but I always get Invalid video url.

 

Does anyone know what is going on? Anyone faced the same situation and has able to figure it out?

ShopifyDevSup
Shopify Staff
1322 216 456

Hey @AndreFonseca

 

Thanks for sharing that update. Can you share an example of your productCreateMedia mutation? 

We have an example in our guide here, which may help to double check if there are any syntax errors with the URL. https://shopify.dev/docs/apps/online-store/media/products#step-2-add-media-to-a-product 

 

- Kyle G.

Developer Support @ Shopify
- Was this reply helpful? Click Like to let us 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

AndreFonseca
Shopify Partner
7 0 0

Hi @ShopifyDevSup 

 

Here is the mutation:

mutation productCreateMedia($media: [CreateMediaInput!]!, $productIdID!) {
  productCreateMedia(media$mediaproductId$productId) {
    media {
      alt,
      mediaContentType,
      status,
      id
    }
    product {
      id
      handle
    }
    mediaUserErrors {
      code
      field
      message
    }
  }
}
 
 
Variables
{
  "media": [
    {
        "alt""",
        "mediaContentType""VIDEO"
    }
  ],
  "productId""gid://shopify/Product/7545977077933"
}



 

I restarted the all process but now, I cant even play the video that I upload to my store. I'm feeling frustrated. I already spent so many time on this and I cannot understand what is going on 😞

 

EDIT: 

Let me recap just to be sure.

 

1st

Use the stagedUploadsCreate mutation witch return the parameters to POST the video to Google.

NOTE: The endpoint must be "https://shopify-staged-uploads.storage.googleapis.com" and not the full resourceUrl

 

2nd

Upload the video using the information os the first step

 

3rd

Create the file in Shopify using the fileCreate mutation. The originalSource link must be the resourceUrl of the first step

 

4th

Associate the video to the product using the productCreateMedia. The originalSouce is the resourceUrl of the first step and the mediaContentType is VIDEO

In the documentation (step 2) you specify that "The original source of the media object. Can be an external URL for images, YouTube videos, and Vimeo videos, or an upload URL for images, videos, and 3D models hosted by Shopify. For assets hosted by Shopify, use the resourceUrl value returned by the stagedUploadsCreate mutation." just like I said. However, looking for the example, the originalUrl used seems to be the one that is returned after uploading the file to Google. I tried both of them, but none work. 

 

Kyle, can you show me what am I doing wrong and why the video does not play? I tried the resourceUrl, Shopify Url (Content > Files) and the one returned after uploading the file to Google. Thanks in advance! 

 

EDIT2:

On the productCreateMedia mutation, I changed the mediaContentType value form VIDEO to IMAGE and I was able to associate. I went to the product page and the media was processing. After a while it failed (as expected). This proves that the url that I'm providing as the originalSource is correct. Something else is missing or may not be working on the API

AndreFonseca
Shopify Partner
7 0 0

I still have the problem when I try to associate the video to the product (step 4). I tryed the URL given by the mutation

stagedUploadsCreate, the url given as anwser after uploading the video to google storage and the link of the video on Shopify (Content > Files). None of them works. I even tried to put EXTERNAL_VIDEO as mediaContentType but no luck. Can someone please help me? 
 
EDIT: I used the mutation as is in the second step of the following tutorial (https://shopify.dev/docs/apps/online-store/media/products#requirements) but it doesn't work. I always says Invalid video URL
ShopifyDevSup
Shopify Staff
1322 216 456

Hey @AndreFonseca , thanks for sharing those additional details. 

 

I went through to test on my own, and it was working properly. Let me what what I did and maybe we can narrow down where it's failing for you. 

Step 1. Staged Uploads create 

This was my mutation 

 

mutation generateStagedUploads {
   stagedUploadsCreate(
       input: [
           {
               filename: "testForMedia.mp4"
               mimeType: "video/mp4"
               resource: VIDEO
               fileSize: "17404311"
           }
       ]
   ) {
       stagedTargets {
           url
           resourceUrl
           parameters {
               name
               value
           }
       }
       userErrors {
           field
           message
       }
   }
}

That returned the staged targets the same as in the example here https://shopify.dev/docs/apps/online-store/media/products#generate-the-upload-url-and-parameters 

 

Noting in particular the resourceURL returned. Looking at the example above, this may be where it's going wrong.

"resourceUrl": "https://shopify-video-production-core-originals.storage.googleapis.com?external_video_id=8490719",

 

Step 2, I created a CURL POST request with the details from above response. If successful, this will return a 204 status with no content

 

curl -v \
 -F "GoogleAccessId=REDACTED" \
 -F "key=REDACTED" \
 -F "policy=REDACTED" \
 -F "signature=REDACTED" \
 -F "file=@/path/to/your/file.mp4" \
 "https://shopify-video-production-core-originals.storage.googleapis.com"

Step 3, is productCreateMedia mutation using the product GID that I want to apply to the video and the resourceURL from step 1 as the original source.  

 

mutation createProductMedia {
 productCreateMedia(productId: "gid://shopify/Product/[redacted]", media: [
   {
     originalSource: "https://shopify-video-production-core-originals.storage.googleapis.com?external_video_id=8490719",
     alt: "Video showing nothing really",
     mediaContentType: VIDEO
   }
 ]) {
   media {
     ... fieldsForMediaTypes
     mediaErrors {
       code
       details
       message
     }
     mediaWarnings {
       code
       message
     }
   }
   product {
     id
   }
   mediaUserErrors {
     code
     field
     message
   }
 }
}

fragment fieldsForMediaTypes on Media {
 alt
 mediaContentType
 preview {
   image {
     id
   }
 }
 status
 ... on Video {
   id
   sources {
     format
     height
     mimeType
     url
     width
   }
 }
}

The response here returns the video, with the status field likely to be uploaded meaning it's uploaded, but not yet processed or ready. 

 

Step 4. is retrieve media object with a product query. For this step I'm mainly interested in the status of the video. 

 

Here's a simplified query that will return the product title and the status of the media. 

 

{
 product(id:"gid://shopify/Product/[redacted]") {
   title
   media(first:5) {
     edges {
       node {
         status
       }
     }
   }
 }
}

This returned the following status of Ready, confirming the video has completed processing. If any other status is returned, the video is not yet processed. : 

"data": {
       "product": {
           "title": "Coffee Maker",
           "media": {
               "edges": [
                   {
                       "node": {
                           "status": "READY"
                       }
                   }
               ]
           }
       }
   },

Step 5, I visit my product page and the video is available. 

 

Let me know if that helps! 

 

- Kyle G.

Developer Support @ Shopify
- Was this reply helpful? Click Like to let us 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

ShopifyDevSup
Shopify Staff
1322 216 456

Hey @AndreFonseca , thanks for sharing those additional details. 

 

I went through to test on my own, and it was working properly. Let me what what I did and maybe we can narrow down where it's failing for you. 

Step 1. Staged Uploads create 

This was my mutation 

 

mutation generateStagedUploads {
   stagedUploadsCreate(
       input: [
           {
               filename: "testForMedia.mp4"
               mimeType: "video/mp4"
               resource: VIDEO
               fileSize: "17404311"
           }
       ]
   ) {
       stagedTargets {
           url
           resourceUrl
           parameters {
               name
               value
           }
       }
       userErrors {
           field
           message
       }
   }
}

That returned the staged targets the same as in the example here https://shopify.dev/docs/apps/online-store/media/products#generate-the-upload-url-and-parameters 

 

Noting in particular the resourceURL returned. Looking at the example above, this may be where it's going wrong.

"resourceUrl": "https://shopify-video-production-core-originals.storage.googleapis.com?external_video_id=8490719",

 

Step 2, I created a CURL POST request with the details from above response. If successful, this will return a 204 status with no content

 

curl -v \
 -F "GoogleAccessId=REDACTED" \
 -F "key=REDACTED" \
 -F "policy=REDACTED" \
 -F "signature=REDACTED" \
 -F "file=@/path/to/your/file.mp4" \
 "https://shopify-video-production-core-originals.storage.googleapis.com"

Step 3, is productCreateMedia mutation using the product GID that I want to apply to the video and the resourceURL from step 1 as the original source.  

 

mutation createProductMedia {
 productCreateMedia(productId: "gid://shopify/Product/[redacted]", media: [
   {
     originalSource: "https://shopify-video-production-core-originals.storage.googleapis.com?external_video_id=8490719",
     alt: "Video showing nothing really",
     mediaContentType: VIDEO
   }
 ]) {
   media {
     ... fieldsForMediaTypes
     mediaErrors {
       code
       details
       message
     }
     mediaWarnings {
       code
       message
     }
   }
   product {
     id
   }
   mediaUserErrors {
     code
     field
     message
   }
 }
}

fragment fieldsForMediaTypes on Media {
 alt
 mediaContentType
 preview {
   image {
     id
   }
 }
 status
 ... on Video {
   id
   sources {
     format
     height
     mimeType
     url
     width
   }
 }
}

The response here returns the video, with the status field likely to be uploaded meaning it's uploaded, but not yet processed or ready. 

 

Step 4. is retrieve media object with a product query. For this step I'm mainly interested in the status of the video. 

 

Here's a simplified query that will return the product title and the status of the media. 

 

{
 product(id:"gid://shopify/Product/[redacted]") {
   title
   media(first:5) {
     edges {
       node {
         status
       }
     }
   }
 }
}

This returned the following status of Ready, confirming the video has completed processing. If any other status is returned, the video is not yet processed. : 

"data": {
       "product": {
           "title": "Coffee Maker",
           "media": {
               "edges": [
                   {
                       "node": {
                           "status": "READY"
                       }
                   }
               ]
           }
       }
   },

Step 5, I visit my product page and the video is available. 

 

Let me know if that helps! 

 

- Kyle G.

Developer Support @ Shopify
- Was this reply helpful? Click Like to let us 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

ShopifyDevSup
Shopify Staff
1322 216 456

This is an accepted solution.

Hey @AndreFonseca , thanks for sharing those additional details. 

 

I went through to test on my own, and it was working properly. Let me what what I did and maybe we can narrow down where it's failing for you. 

Step 1. Staged Uploads create 

This was my mutation 

 

mutation generateStagedUploads {
   stagedUploadsCreate(
       input: [
           {
               filename: "testForMedia.mp4"
               mimeType: "video/mp4"
               resource: VIDEO
               fileSize: "17404311"
           }
       ]
   ) {
       stagedTargets {
           url
           resourceUrl
           parameters {
               name
               value
           }
       }
       userErrors {
           field
           message
       }
   }
}

That returned the staged targets the same as in the example here https://shopify.dev/docs/apps/online-store/media/products#generate-the-upload-url-and-parameters 

 

Noting in particular the resourceURL returned. Looking at the example above, this may be where it's going wrong.

"resourceUrl": "https://shopify-video-production-core-originals.storage.googleapis.com?external_video_id=8490719",

 

Step 2, I created a CURL POST request with the details from above response. If successful, this will return a 204 status with no content

 

curl -v \
 -F "GoogleAccessId=REDACTED" \
 -F "key=REDACTED" \
 -F "policy=REDACTED" \
 -F "signature=REDACTED" \
 -F "file=@/path/to/your/file.mp4" \
 "https://shopify-video-production-core-originals.storage.googleapis.com"

Step 3, is productCreateMedia mutation using the product GID that I want to apply to the video and the resourceURL from step 1 as the original source.  

 

mutation createProductMedia {
 productCreateMedia(productId: "gid://shopify/Product/[redacted]", media: [
   {
     originalSource: "https://shopify-video-production-core-originals.storage.googleapis.com?external_video_id=8490719",
     alt: "Video showing nothing really",
     mediaContentType: VIDEO
   }
 ]) {
   media {
     ... fieldsForMediaTypes
     mediaErrors {
       code
       details
       message
     }
     mediaWarnings {
       code
       message
     }
   }
   product {
     id
   }
   mediaUserErrors {
     code
     field
     message
   }
 }
}

fragment fieldsForMediaTypes on Media {
 alt
 mediaContentType
 preview {
   image {
     id
   }
 }
 status
 ... on Video {
   id
   sources {
     format
     height
     mimeType
     url
     width
   }
 }
}

The response here returns the video, with the status field likely to be uploaded meaning it's uploaded, but not yet processed or ready. 

 

Step 4. is retrieve media object with a product query. For this step I'm mainly interested in the status of the video. 

 

Here's a simplified query that will return the product title and the status of the media. 

 

{
 product(id:"gid://shopify/Product/[redacted]") {
   title
   media(first:5) {
     edges {
       node {
         status
       }
     }
   }
 }
}

This returned the following status of Ready, confirming the video has completed processing. If any other status is returned, the video is not yet processed. : 

"data": {
       "product": {
           "title": "Coffee Maker",
           "media": {
               "edges": [
                   {
                       "node": {
                           "status": "READY"
                       }
                   }
               ]
           }
       }
   },

Step 5, I visit my product page and the video is available. 

 

Let me know if that helps! 

 

- Kyle G.

Developer Support @ Shopify
- Was this reply helpful? Click Like to let us 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

AndreFonseca
Shopify Partner
7 0 0

It works. Thanks!