Uploading a file (in an embedded Shopify app) using Dropzone component

Hi, I’m building an app which requires users to upload files in the user interface.

I’m having some difficulty finding documentation detailing how to go about this.

I am aware of the GraphQL api, and the Files API. However, I am still having issues.

My main concern and inquiry - if anyone can answer - is if the API (Graphql or Rest) support uploading arbitrary file types (not just images/media)?

It seems like it is - but I want to confirm that before I continue spending my time developing the application.

This community post seems to indicate it’s possible, but I’m still not sure. (it seems like it was a workaround for uploading an image)

Also, is it possible to upload the file without specifying a URL? (without having to upload it anywhere else but Shopify?)

My second concern would be where to find supporting documentation/tutorials to accomplish this.

Please let me know if you need further clarification.

Thank you for your time.

1 Like

So, I’ve actually been able to figure out how to get this working by following this tutorial (made by Shopify): https://www.shopify.com/partners/blog/upload-files-graphql-react

I’m getting a successful response for uploading PDFs, but when I go into the admin section for Files, it doesn’t show up (the only one that went through was a SVG file)

Please see following code:

// import { React, Component, useState, useCallback, useEffect } from “react”;
import React, { Component } from ‘react’;
import {NoteMinor} from ‘@shopify/polaris-icons’;

import { gql, useMutation } from ‘@apollo/client’;

import {
Card,
Layout,
EmptyState,
ChoiceList,
Button,
SkeletonPage,
SkeletonBodyText,
Select,
TextField,
DropZone,
Thumbnail,
Stack,
Caption
} from “@shopify/polaris”;
import { ResourcePicker } from ‘@shopify/app-bridge/actions’;

import {useQuery} from “@apollo/client”;
// import useMutation from ‘react’;
import {useState} from ‘react’;

export function FileDropperFunctional (props) {

const STAGED_UPLOADS_CREATE = gqlmutation stagedUploadsCreate($input: [StagedUploadInput!]!) { stagedUploadsCreate(input: $input) { stagedTargets { resourceUrl url parameters { name value } } userErrors { field message } } };

const [stagedUploadsCreate] = useMutation(STAGED_UPLOADS_CREATE);

const [disabled, setDisabled] = useState(false);
const [dropzone_files, setDropZoneFiles] = useState();
const [loading, setLoading] = useState(false);

// function to run after submission: props.afterSubmit

async function processButton() {

setLoading(true);

if(props.afterSubmit != undefined)
props.afterSubmit(dropzone_files);

var file = dropzone_files[0];

let { data } = await stagedUploadsCreate({ variables: {
“input”: [
{
“resource”: “FILE”,
“filename”: file.name,
“mimeType”: file.type,
“fileSize”: file.size.toString(),
“httpMethod”: “POST”
}
]
}})

const [{ url, parameters }] = data.stagedUploadsCreate.stagedTargets

const formData = new FormData()

parameters.forEach(({name, value}) => {
formData.append(name, value)
})

formData.append(‘file’, file)

const response = await fetch(url, {
method: ‘POST’,
body: formData
})

console.log(response)

setLoading(false);
setDisabled(true);
}

function handleDropzoneDrop(files, acceptedFiles, rejectedFiles) {
// console.log(files)

setDropZoneFiles(files)

}

var fileUpload = !dropzone_files.length && <DropZone.FileUpload />;
var uploadedFiles = dropzone_files.length > 0 && (

{dropzone_files.map((file, index) => (
{file.name} {file.size} bytes
))}
);

var proceedButton = <>

<Button onClick={processButton} disabled={!dropzone_files.length || disabled} loading={loading}>Continue</>;

return (

<>

{uploadedFiles}
{fileUpload}

{proceedButton}
</>

);

}

2 Likes

Hey.. Thanks for sharing this.

Just checking it you were able to upload the file without specifying a URL? (i.e. without having to upload it anywhere else but Shopify?) – or do you have to uploading it somewhere else first, and then use that URL for staging uploads.

Thanks