Solved

Issues when obtaining and maintaining urls for product media of type video

nicu_taban
Shopify Partner
12 0 14

Hi!

I am developing a third-party application that uses the Shopify GraphQL API (version 2020.10) to add .mp4 videos to products. I have successfully completed the steps described in https://shopify.dev/api/examples/product-media (created an upload URL, uploaded the video and linked the video to a product).  However, the following two issues appeared:

1. The last mutation, which links the video to the product does not return any sources (empty array) or originalSource (it is null) on Media nodes of type Video. However, the video is present on the actual product in the Shopify store. The mutation is presented below:

const LINK_MEDIA_TO_PRODUCT = gql`
mutation productCreateMedia($productId: ID!, $media: [CreateMediaInput!]!) {
  productCreateMedia(productId: $productId, media: $media) {
    media {
      ...fieldsForMediaTypes
    }
    mediaUserErrors {
      code
      field
      message
    }
    product {
      id
    }
  }
}

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

 

2. The second problem is that one of the functionalities of the application is to manage the videos on the products, so the application must play the videos and display them in a list. However, all the links that are present in the sources list on the Video node are CDN links. (as tested with the Shopify GraphQL application installed on the store) The documentation states that the links for Video and 3D objects stored on the CDN expire, but it does not state how long it takes for the videos to expire. In this context, how can I ensure that the users of the application can always play the videos and see a thumbnail for them? How long does it take for a video to expire?

Thank you!

Accepted Solution (1)
Luke_K
Shopify Staff
402 66 98

This is an accepted solution.

Hey @nicu_taban 

I've managed to perform some further tests here.

So the reason why originalSource is null and the sources array is empty, is due to the status of the Video media(docs) when you callproductCreateMedia. 

At point you call productCreateMedia, in a Video's case, the Video has not been fully transcoded. originalSource and sources will be returned when the Video Media status = READY (you'll note this when polling for the product's GID).

When Video media status is READY, it has completed the Transcoding and is ready to be displayed and those requested fields will be returned which is expected behaviour. 

Hope that helps explain a little more, and please let me know if you have any questions!

 

| Shopify |
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution!

View solution in original post

Replies 22 (22)

Luke_K
Shopify Staff
402 66 98

Hey @nicu_taban 

Thanks for raising this! With first question, Did you happen to have a request ID for that productCreateMedia mutation that I could take a look at to find out why you were getting null?

With the second question, generally our CDN cache will keep links cached for up to one year. Hope that helps!

 

| Shopify |
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution!
nicu_taban
Shopify Partner
12 0 14

Hello @Luke_K ,

I can reproduce the behaviour, but how do I get hold of a request ID for a particular request to Shopify? Sorry for the late response.

Luke_K
Shopify Staff
402 66 98

No worries @nicu_taban!

So if you're consistently able to replicate this, we'd return an "x-request-id" in the response header when you make a call client side against Shopify API. If you send that x-request-id through to me I'll be able to see what's happening here in the logs. Thanks!

| Shopify |
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution!
nicu_taban
Shopify Partner
12 0 14

Ok, so I replicated the issue in the request having the following request id: 0995e80e-b111-4e41-aad4-6149d29c98b8. If you could take a look, I would be grateful @Luke_K . Thank you!

Luke_K
Shopify Staff
402 66 98

Hey @nicu_taban 

Thanks! That helped out alot. So, I checked out the logs for that request and the job to upload the Videos runs ok,  we see the video attached to your product, all the Videos are all in the 'Ready' state (denoting that file is attached and attached to the Product).

I'm able to replicate too when directly passing in Original Source and Sources on productCreateMedia mutation, I'm returned null for originalSource and nothing in the sources array. 

As an aside, I note that when I query the Product's Graphql ID (gid) directly, much like as shown here, i'm returned data for your product's originalSource and sources array. That maybe a workaround for you in the meantime whilst we look into this further.

I'll peform some further tests here regarding expected behaviour and will endeavour to be back here as soon as I have a further update.

| Shopify |
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution!
Luke_K
Shopify Staff
402 66 98

This is an accepted solution.

Hey @nicu_taban 

I've managed to perform some further tests here.

So the reason why originalSource is null and the sources array is empty, is due to the status of the Video media(docs) when you callproductCreateMedia. 

At point you call productCreateMedia, in a Video's case, the Video has not been fully transcoded. originalSource and sources will be returned when the Video Media status = READY (you'll note this when polling for the product's GID).

When Video media status is READY, it has completed the Transcoding and is ready to be displayed and those requested fields will be returned which is expected behaviour. 

Hope that helps explain a little more, and please let me know if you have any questions!

 

| Shopify |
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution!
nicu_taban
Shopify Partner
12 0 14

Hi @Luke_K 

Following your advice, I was able to obtain the links to the productMedia!

I have some final questions regarding the CDN, The productMedia object contains a sources array and an originalSrc field. Can I rely on the fact that the link in the originalSrc will not expire?

Also, the productMedia object has a preview field which is an object containing a thumbnail image, which in turn contains an originalSrc field. Can I also rely on the fact that the originalSrc for the thumbnail will not expire?

Thank you very much!

Luke_K
Shopify Staff
402 66 98

Hey @nicu_taban 

Yes you can rely on those to not expire. The documentation actually needs a refresh -  I believe those docs were written at a point where our Video Source URL's would expire. Hope that helps!

 

 

| Shopify |
- Was my reply helpful? Click Like to let me know!
- Was your question answered? Mark it as an Accepted Solution!
nicu_taban
Shopify Partner
12 0 14

Thank you very much for your clarifications @Luke_K !

Xen-dev
Shopify Partner
16 0 1

how can we replicate the status can you please give a little input regarding that please and I am getting the errors as yours please.

ShopifyDevSup
Shopify Staff
1315 215 454

Hey @Xen-dev

 

If you're not able to retrieve the response headers in your current application, I'd recommend retrying the query in an API client like postman or insomnia. Using a tool like that can also help with debugging if the issue is specific to your app code, or the API, as well as it makes it easy to view responses. 

Kind Regards,

- 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

Xen-dev
Shopify Partner
16 0 1

where do you check the status? I'm not able to log any status in my terminal and my message says invalid model 3d

ShopifyDevSup
Shopify Staff
1315 215 454

Hi @Xen-dev 

You can check the status of Product Media files by querying the Product object and the Media connector contained within like so:

{

    product(id: "gid://shopify/Product/12345"){

        id

        handle

        media(first: 50){

            edges{

                node{

                    id

                    mediaContentType

                    status

                }

            }

        }

    }

}

As for the Invalid 3D Model error you are seeing, please double check that you are using valid 3d files, either in GLB or USDZ format with a correct mimetype of either model/gltf-binary or model/vnd.usd+zip respectively.

If you are using the correct format and mimetypes, please do reach out to our Support Team directly through our Shopify Help Center with examples as requested in our previous thread.

I hope this helps, and I hope you have a great day 🙂

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

Xen-dev
Shopify Partner
16 0 1

How are you using this along with the mutation of productCreateMedia?

 

Xen-dev
Shopify Partner
16 0 1

As given in the documentation,

the status is inside the media [] for me that is empty as I am trying to load the 3d model and it gives me an mediaUserError[] code: "INVALID" and message: Invalid model 3d

below is my code :

    const fileCreateResponse = await admin!.graphql(
      `#graphql
      mutation createProductMedia {
        productCreateMedia(productId: "gid://shopify/Product/723115xxxxx", media: [
          {
            originalSource: "https://d18bonzuewcc.cloudfront.net/test/77543.glb",
            alt: "Comparison video showing the different models of watches.",
            mediaContentType: MODEL_3D
          }
        ]) {
          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
          }
        }
        ... on ExternalVideo {
          id
          host
          originUrl
        }
        ... on Model3d {
          sources {
            format
            mimeType
            url
            
          }
            boundingBox {
            size {
              x
              y
              z
            }
          }
      
        }
      }`,
    );

    console.log(fileCreateResponse, "fileCreateResponse");

    const productData = await fileCreateResponse.json();
    return json({
      data: productData.data,
    });
  } catch (error: any) {
    console.error("Error:", error);
    return json({ error: error.message }, { status: 500 });
  }
};

  

ShopifyDevSup
Shopify Staff
1315 215 454

Hi @Xen-dev ,

It looks like you are using an external URL for the 3d model upload, which may explain the errors you're seeing. Our developer documentation does mention that the originalSource argument can only accept external URLs for Images, and Youtube/Vimeo videos. For 3D models, you will need to create a Staged Upload URL first with the stagedUploadsCreate mutation, then upload the 3D file to the staged URL following the instructions in our documentation.

 

If you are still experiencing errors uploading the file with a staged upload URL, please double check the file and mimetype as mentioned in our response above, and do reach out to Shopify Support via our Shopify Help Center, with specific examples and our support team can help look into actual examples further. 

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

Xen-dev
Shopify Partner
16 0 1

Hi, Thank you for the response, I am using the stagedUploadsCreate mutation along with the productCreateMedia mutation, but still getting the same error:  the status is inside the media [] for me that is empty as I am trying to load the 3d model and it gives me an mediaUserError[] code: "INVALID" and message: Invalid model 3d. It would be a great help if you could help debug. The code is given below.

 

export const action: ActionFunction = async ({ request }) => {

    const filePath = "/Users/apple/Documents/xyz.usdz";
    const fileData = fs.readFileSync(filePath);
    const filename = filePath.split("/").pop();
    const fileSize = fs.statSync(filePath).size.toString();
    const input = [];

    input.push({
      filename,
      mimeType: "model/vnd.usd+zip" || "model/gltf-binary",
      resource: "FILE",
      fileSize,
      httpMethod: "POST",
    });

    const fileInput = {};

    const stagedUploadsResponse = await admin!.graphql(
      `#graphql
      mutation StagedUploadsCreate($input: [StagedUploadInput!]!) {
        stagedUploadsCreate(input: $input) {
          stagedTargets {
            url
            resourceUrl
            parameters {
              name
              value
            }
          }
        }
      }`,
      {
        variables: {
          input: input,
        },
      },
    );

    const stagedUploadsData = await stagedUploadsResponse.json();
    console.log(stagedUploadsData);

    const target = stagedUploadsData.data.stagedUploadsCreate.stagedTargets[0];
    const { resourceUrl, parameters, url } = target;
    const formData = new FormData();

    for (var param of target.parameters) {
      formData.append(param.name, param.value);
    }

    const blob = new Blob([fileData]);
    formData.append("file", blob, filename);
    await axios.post(target.url, formData, {
      headers: {
        "Content-Type": "application/octet-stream",
      },
    });

    console.log(resourceUrl, "resourceUrl", parameters, "parameters", url, 'url');

    const fileCreateResponse = await admin!.graphql(
      `#graphql
      mutation productCreateMedia($media: [CreateMediaInput!]!, $productId: ID!) {
        productCreateMedia(media: $media, productId: $productId) {
          media {
            alt
            mediaContentType
            status
            preview {
                    image {
                      id
                    }
            } 
            ... on Model3d {
              sources {
                format
                mimeType
                url
              }
            
            }
         }
          mediaUserErrors {
            code
            field
            message
          }
          product {
            id
            title
          }
        }
    
      }`,
      {
        variables: {
          media: [
            {
              alt: "3d models",
              mediaContentType: "MODEL_3D",
              originalSource: target.resourceUrl,
            },
          ],
          productId: "gid://shopify/Product/7231157665873",
        },
      },
    );

    console.log(fileCreateResponse, "fileCreateResponse");

    const productData = await fileCreateResponse.json();
    return json({
      data: productData.data,
    });
  } catch (error: any) {
    console.error("Error:", error);
    return json({ error: error.message }, { status: 500 });
  }
};

ShopifyDevSup
Shopify Staff
1315 215 454

Hi @Xen-dev,

Thanks for confirming that you are using the Staged Upload URL now. While we're not able to help debug the code directly, the API queries you are using does look correct. 

Moving forward to help investigate this issue further, we will need you to reach out to our Support Team directly with specific examples as mentioned in our previous responses. This allows us to help look into specific api calls that are returning the errors in our internal logs to help better determine the cause of this error. To do this we will need you to do the following please:

1. First confirm that the 3d files you are uploading do have the correct mimetype. For .usdz files, they need to have the model/vnd.usd+zip mimetype, and for .glb files they need to have the model/gltf-binary mimetype. Sometimes when downloading files from the internet it's possible that the file extension doesn't always match the exact file mimetype, so it's important to double check that these files have the correct mimetype to prevent this error.
 

  • You can check a file's mimetype on Mac and Linux in the terminal with the command: file --mime-type -b <file_name>. 
  • It's a little harder to check on Windows, and will likely need some third party tools, please see this SuperUser Stack Exchange post for more info.

 

2. If you've confirmed that the file types match the correct mimetype you are trying to upload, you will need to gather the following context on a recent example where the error occurred (within the last 14 days).

 

  • The full Request Body and Headers
  • The full Response Body and Headers (most important from the headers is the x-request-id and timestamp)
  • The file you are trying to upload that is returning the error

 

3. Once you have that context we need to look up the error in our logs, please reach out to our Support Team via the Shopify Help Center, logged in on the store that the error is occurring on, and we can then help look into the specific call where the error is occurring further.
 

I hope this helps, and I hope you have a great day 🙂

 

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

Xen-dev
Shopify Partner
16 0 1

Hi @ShopifyDevSup , 

Thank you for the response.

 

As you could see from the above code that the mimetypes of the files are defined as you have mentioned i.e.   mimeType  "model/vnd.usd+zip" and  "model/gltf-binary"but still facing the error of Invalid model. 

 

The model that is used works completely on the local server and don't understand the reason for it to not work here after following the documentation as given.

 

Would be great if you could help through it.

ShopifyDevSup
Shopify Staff
1315 215 454

Hi @Xen-dev ,

 

To be able to help troubleshoot this further with you we will need to authenticate you on the store that the errors are occurring on, and look into specific examples of API calls where the error is being returned after uploading the file.

To do this you will need to reach out in our Shopify Help Center and chat with our support team directly, where we can then authenticate you as mentioned above, and help look into specific examples of the errors in our internal logs.

Please review Step 2 in the post we sent above, which outlines the what information we will need to be able to help you with this further. Once you have gathered the information in Step 2 above, please reach out in the Shopify Help Center and we can absolutely help you look into this further.

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

Xen-dev
Shopify Partner
16 0 1

Hi, 

Thank you for the response.

I am having trouble getting the x-request-id from the request headers. I am using a proxy app and a checkout extension along with it.

It would be great if you could guide me through it.

Xen-dev
Shopify Partner
16 0 1

how do you generate this request id ? as I cant find these on my logs