Files

You can use Kinvey to store and retrieve binary files of size up to 5TB. Files can be of any format.

The files are automatically enabled for download using a Content Delivery Network (CDN) for massive scale and performance.

Kinvey does not directly serve or accept files. Instead, the Kinvey Files API works by providing a short-lived URL to a third-party cloud storage service from which file(s) can be uploaded or downloaded. Currently, the third-party service used is Google Cloud Storage.

You would typically use the Files API to upload and download:

  • images
  • video files
  • other application-specific files.

When using the library, a file can be represented by:

  • A Blob, File, or ArrayBuffer object. This is the recommended way of representing a file.
  • A simple value like a string.

The library always communicates with Google Cloud Storage using the https protocol. If you want to use http instead, the options argument in the methods described below allow for a tls: false flag.

Recommended tutorials to learn more about uploading files are:

Download

To download a file given its _id, use $kinvey.Files.download. The response will contain the file metadata, with the file itself available on the _data property.

var promise = $kinvey.Files.download('file-id')
  .then(function(file) {
    var fileContent = file._data;
    // ...
  })
  .catch(function(error) {
    // ...
  });

Stream

For web applications, downloading the actual file is not a common use case. Often, just obtaining a download URL is sufficient. This holds for a variety of use cases, including:

  • Prompt a file for download
  • Embed an application-resource, such as a stylesheet
  • Display an image

To stream a file, use $kinvey.Files.stream. The response will contain the file metadata, with the download URL available as _downloadURL property.

var promise = $kinvey.Files.stream('file-id')
  .then(function(file) {
    var url = file._downloadURL;
    // ...
  })
  .catch(function(error) {
    // ...
  });

Query

To retrieve a list of files, the Querying interface is available for files.

The snippet below retrieves a list of all PNG images. The response is a list of file metadata.

var query = new $kinvey.Query();
query.equalTo('mimeType', 'image/png');
var promise = $kinvey.Files.find(query)
  .then(function(files) {
    // ...
  })
  .catch(function(error) {
    // ...
  });

Optionally, you can add the download: true flag to download every file found. The file itself will then become available under the _data property of each file in the list.

Be careful when using the download flag. Every file matching the query will be downloaded regardless of its size, which can lead to significant overhead and performance degradation of your application.

The file metadata returned by any of the methods explained above contains a _downloadURL. Depending on your use case, you might want to re-download a file. The $kinvey.Files.downloadByUrl() method allows you to do just that. The method accepts either a _downloadURL, or a JSON object literal containing a _downloadURL property.

var promise = $kinvey.Files.download('file-id')
  .then(function(file) {
    // After some time passed, redownload the file.
    return $kinvey.Files.downloadByUrl(file);
  })
  .then(function(file) {
    // ...
  })
  .catch(function(errpr) {
    // ...
  });

Specifying a custom expiration time

If you require the temporary download URL to last longer (or shorter) than the default of one hour, you may optionally specify a custom expiration time (in seconds) using the ttl option. If the file is public, the returned download URL never expires.

var promise = $kinvey.Files.download('file-id', {
  ttl: 7200 // Two hours in ms
})
  .then(function(file) {
    // ...
  })
  .catch(function(error) {
    // ...
  });

Upload

Use $kinvey.Files.upload() to upload the file and, optionally, save any associated metadata along with it. The example below uploads a file represented as a string. The _id and _filename properties will be auto-generated by Kinvey if left out.

var fileContent = '<file-content>';
var metadata ={
  _id: '<file-id>',
  filename: '<filename>',
  mimeType: '<mime-type>',
  size: fileContent.length
};
var promise = $kinvey.Files.upload(fileContent, metadata)
  .then(function(file) {
    // ...
  })
  .catch(function(error) {
    // ...
  });

The snippet below demonstrates how to upload a file through a form. The library attempts to save the file name, size, and type along with the file upload itself. Hence there is no need to manually add any metadata, the library will do that for you.

<form enctype="multipart/form-data" method="post" name="fileUpload">
  <input id="file" multiple type="file" />
  <input type="submit" value="Upload" />
</form>
<script>
  var form = document.getElementsByName('fileUpload')[0];
  form.addEventListener('submit', function(e) {
    e.preventDefault();
    var file = form.getElementById('input')[0].files[0];

    if (file) {
      var promise = $kinvey.Files.upload(file, metadata)
        .then(function(file) {
          // ...
        })
        .catch(function(error) {
          // ...
        });
    }
  });
</script>

Resume an Upload

The library supports resumable file uploads with Google Cloud Storage and will attempt to resume a file upload that may have been interrupted by only uploading the remaining portion of a file that has not been received by Google Cloud Storage. The example below shows how to resume a file upload that was started but did not complete.

var fileContent = '<file-content>';
var promise = $kinvey.Files.findById('file-id')
  .catch(function(error) {
    return {
      _id: '<file-id>',
      filename: '<filename>',
      mimeType: '<mime-type>',
      size: fileContent.length
    }
  })
  .then(function(metadata) {
    return $kinvey.Files.upload(fileContent, metadata);
  })
  .then(function(file) {
    // ...
  })
  .catch(function(error) {
    // ...
  });

Permissions

Files fully support entity level permissions. To upload a file and add read permissions to another user, you can do the following.

var acl = new $kinvey.Acl().addReader('<user-id>');
var fileContent = '<file-content>';
var metadata ={
  _id: '<file-id>',
  _acl: acl.toJSON(),
  filename: '<filename>',
  mimeType: '<mime-type>',
  size: fileContent.length
};
var promise = $kinvey.Files.upload(fileContent, metadata)
  .then(function(file) {
    // ...
  })
  .catch(function(error) {
    // ...
  });

Create publicly-readable files

By default, files uploaded to Google Cloud Storage through the Kinvey File API are private. This means that every time you wish to download a file, you must first request it via a GET request to Kinvey, which will generate a signed URL that allows download access only for a limited time.

However, using the File API, you may optionally create a publicly-readable file. The download link to this file will be a regular non-signed URL, which will not expire until you delete the file through Kinvey or change the file's status to be private again. To create a publicly-readable file, set the public option to true.

var fileContent = '<file-content>';
var metadata ={
  _id: '<file-id>',
  filename: '<filename>',
  mimeType: '<mime-type>',
  size: fileContent.length,
  public: true
};
var promise = $kinvey.Files.upload(fileContent, metadata)
  .then(function(file) {
    // ...
  })
  .catch(function(error) {
    // ...
  });

Upload Errors

The library uses an exponential backoff strategy if a 5xx error is returned when uploading a file. The default max backoff time is 32 seconds and can be changed by setting options.maxBackoff to a number of seconds.

var fileContent = '<file-content>';
var metadata ={
  _id: '<file-id>',
  filename: '<filename>',
  mimeType: '<mime-type>',
  size: fileContent.length
};
var promise = $kinvey.Files.upload(fileContent, metadata, {
  maxBackoff: 10 // 10 seconds
})
  .then(function(file) {
    // ...
  })
  .catch(function(error) {
    // ...
  });

When uploading a large file, the upload request might timeout before the upload is complete. The default timeout is 60000 ms (60 seconds) and can be changed by setting options.timeout to a number of ms.

var fileContent = '<file-content>';
var metadata ={
  _id: '<file-id>',
  filename: '<filename>',
  mimeType: '<mime-type>',
  size: fileContent.length
};
var promise = $kinvey.Files.upload(fileContent, metadata, {
  timeout: 5 * 60 * 1000 // 5 minutes
})
  .then(function(file) {
    // ...
  })
  .catch(function(error) {
    // ...
  });

Delete

To delete a file, use $kinvey.Files.removeById.

var promise = $kinvey.Files.removeById('file-id')
  .then(function() {
    // ...
  })
  .catch(function(error) {
    // ...
  });

Related Samples

Related Samples

Got a question?