Uploading files

Composer provides flow functions to upload files from an app to an AppGyver-hosted S3 bucket, as well as retrieve those files for later viewing.

This process has three steps:

  1. Preparing files for upload

  2. Uploading the files

  3. Retrieving previously uploaded files

In the context of this tutorial, we'll be making it possible to create simple image galleries that have a subject field and multiple images.

To get started, let's create an AppGyver Cloud Storage resource to store our galleries.

Preparing the ImageGallery data resource

Create a new AppGyver Cloud Storage resource via the Data section of the global toolbar at the top. Let's call it ImageGallery and define the schema as follows:

Correctly defined schema for the ImageGallery resource

Don't worry, the different properties will make sense soon.

Create a basic CRUD structure for the ImageGallery data resource:

  • Image gallery list – has All type data variable for ImageGallery, repeats a list component with that data, tapping on a list component opens the details page with current.id passed as id parameter

  • Image gallery details – has a One type data variable for ImageGallery, shows ImageGallery.subject in a Title element.

  • New image gallery – covered in the next section

Preparing files for upload

On the New image gallery page, add a New type ImageGallery data variable, calling it e.g. NewImageGallery.

Add an input field for the subject of our image gallery and bind it to NewImageGallery.subject.

Next, we need to get an array of files ready to be uploaded. The most straightforward way (that also works on web) is the Pick files flow function, but we could also e.g. take individual photos with the Take photo flow function and append them to our dNewImageGallery.images array.

If you examine the outputs of e.g. the Pick files flow function, you'll notice the properties of the outputted file object match our data schema quite closely. The only exception is that the downloadUrl and storageKey properties are missing – which is understandable, as they don't yet exist for our local-device-only files.

File object type

In Composer, files are represented by an object with specific properties. These include both local information, such as path to the file in the device's local filesystem and its size in bytes. As accessing the filesystem is asynchronous, the object available in Composer logic is always just a snapshot of what the file's status was when it was last accessed.

For example, you might take a photo and save its path to a variable. Now, if you use the Move/rename file/directory flow function elsewhere in your app to move the file, the saved path will no longer be valid.

Add a Pick images button, attach the Pick files flow function there and use Set data variable to set the resultant Files array to NewImageGallery.images (you might need to use a formula function due to a bug that results in Composer incorrectly identifying the data variable and the output as incompatible types).

Add an image component and make it repeat based on the NewImageGallery.images array, and bind the Source property to current.path.

Uploading files

Next, add a button to upload the files, and add the Get bucket upload URLs flow function to it. Bind its files output to the Upload files flow function, then bind that output to a Create new data record function, passing the uploaded files to images and getting subject from NewImageGallery.subject .

The first flow function queries AppGyver's backend service for upload URLs for each file, and the second one performs the actual uploading. Then, we create a record that has the storage keys that we can then use later on to fetch the record.

Retrieving previously uploaded files

The images are saved in the backend with an S3 storage key. To get the actual URLs so we can display our images, we need to use the Get bucket download URLs flow function.

Ensure you have a One type ImageGallery data variable defined in the details page, open the logic canvas for it.

Between the Get record and Set data variable flow functions, add the Get bucket download URLs flow function.

Bind the inputs:

  • Get bucket download URLs

    • Files to Output of another node > Get record / Record: images

  • Set data variable

    • Data variable name to ImageGallery

    • data.subject to Output of another node > Get record / Record: subject

    • data.images to Get bucket download URLs / Images

Now, we can add an image component, repeat it based on ImageGallery.images, and bind its Source to current.downloadUrl.

Test it out

You can now use the New image gallery page to create new image galleries, and opening the Image gallery details page will show the created gallery's images. What gets stored in the cloud database is just the storage key.