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:

  • File, Blob, or ArrayBuffer object. This is the recommended way of representing a file.
  • Simple value such as 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 contains a string representation of the file content. If you only need to get the file metadata, use Files.find() or consider streaming the file.

import { Component } from '@angular/core';
import { FilesService } from 'kinvey-angular-sdk';

@Component()
export class FilesComponent {
  constructor(private filesService: FileService) { }

  async download(id: string) {
    try {
      const file = await this.filesService.download(id);
      console.log(file);
    } catch (error) {
      console.log(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 stream(). The response will contain the file metadata, with the download URL available as _downloadURL property.

import { Component } from '@angular/core';
import { FilesService } from 'kinvey-angular-sdk';

@Component()
export class FilesComponent {
  constructor(private filesService: FileService) { }

  async stream(id: string) {
    try {
      const file = await this.filesService.stream(id);
      console.log(file);
    } catch (error) {
      console.log(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.

import { Component } from '@angular/core';
import { FilesService, Query } from 'kinvey-angular-sdk';

@Component()
export class FilesComponent {
  constructor(private filesService: FileService) { }

  async find() {
    try {
      const query = new Query();
      query.equalTo('mimeType', 'image/png');
      const files = await this.filesService.find(query);
      console.log(files);
    } catch (error) {
      console.log(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 a _downloadURL.

import { Component } from '@angular/core';
import { FilesService } from 'kinvey-angular-sdk';

@Component()
export class FilesComponent {
  constructor(private filesService: FileService) { }

  async download(id: string) {
    try {
      const file = await this.filesService.download(id);
      console.log(file);
    } catch (error) {
      console.log(error);
    }
  }
}

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.

import { Component } from '@angular/core';
import { FilesService } from 'kinvey-angular-sdk';

@Component()
export class FilesComponent {
  constructor(private filesService: FileService) { }

  async download(id: string) {
    try {
      const file = await this.filesService.download(id, { ttl: 7200 });
      console.log(file);
    } catch (error) {
      console.log(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.

When using custom values for _id, you should avoid values that are exactly 12 or 24 symbols in length. Such values are automatically converted to BSON ObjectID and are not stored as strings in the database, which can interfere with querying and other operations.

To ensure that no items with 12 or 24 symbols long _id are stored in the collection, you can create a pre-save hook that either prevents saving such items, or appends an additional symbol (for example, underscore) to the _id:

if (_id.length === 12 || _id.length === 24) {
  _id += "_";
}

import { Component } from '@angular/core';
import { FilesService } from 'kinvey-angular-sdk';

@Component()
export class FilesComponent {
  constructor(private filesService: FileService) { }

  async upload() {
    try {
      const fileContent = '<file-content>';
      const metadata ={
        _id: '<file-id>',
        filename: '<filename>',
        mimeType: '<mime-type>',
        size: fileContent.length
      };
      const file = await this.filesService.upload(fileContent, metadata);
      console.log(file);
    } catch (error) {
      console.log(error);
    }
  }
}

Delete

To delete a file, use removeById().

import { Component } from '@angular/core';
import { FilesService } from 'kinvey-angular-sdk';

@Component()
export class FilesComponent {
  constructor(private filesService: FileService) { }

  async removeById(id: string) {
    try {
      const result = await this.filesService.removeById(id);
      console.log(result);
    } catch (error) {
      console.log(error);
    }
  }
}

Linking files to entities in collections

Many common uses for files involve associating them with entities that reside in collections. In order to make this experience as easy as possible, entities in collections may contain KinveyFile references. These references will be automatically resolved when the entity that contains them is retrieved through the Data Store API.

Creating a KinveyFile reference

A reference to a file stored using Kinvey, or a KinveyFile reference, is simply a JSON object with a _type of KinveyFile and an _id containing the ID of a file in Kinvey (as created through the File API).

To store a KinveyFile reference, create or update an entity in any collection with such a property. For example:

var dataStore = Kinvey.DataStore.collection('pets');
dataStore.save({
  dogName: 'Bob',
  furColor: 'brown with black spots',
  pawPrintPicture: {
    _type: 'KinveyFile',
    _id: '325620e4-93dd-4a26-9f84-8a5e62c0db11'
  }
})
  .then(function(pet) {
    // ...
  })
  .catch(function(error) {
    // ...
  });

Please note that only two properties are allowed in a KinveyFile reference: _type and _id. If you attempt to save any additional properties as part of the KinveyFile JSON object, these properties will be ignored by Kinvey and not saved. Any additional properties that you wish to assiciate with the file should be a part of the file itself, and set through the File API.

A KinveyFile is only a reference to a file stored on Kinvey. You are responsible for uploading the file itself using the File API. It is good practice to first upload the file, and only then create the KinveyFile reference.

Downloading using a KinveyFile reference

When querying any collection through the Data Store API, Kinvey will resolve any KinveyFile reference and provide you with a _downloadURL.

var dataStore = Kinvey.DataStore.collection('pets');
dataStore.findById('3f583e9f-d064-4a25-a953-6cf0a3dc2ff1')
  .subscribe(function(pet) {
    /*
      {
        "_id": "3f583e9f-d064-4a25-a953-6cf0a3dc2ff1",
        "_acl": {...},
        "dogName": "Bob",
        "furColor": "brown with black spots",
        "pawPrintPicture": {
          "_type": "KinveyFile",
          "_id": "325620e4-93dd-4a26-9f84-8a5e62c0db11",
          "_filename": "bobsPawPrint.png",
          "_acl": { ... },
          "_downloadURL": <Google Cloud Storage download URL>,
          "_expiresAt": "2018-06-18T23:07:23.394Z"
        }
      }
    */
  }, function(error) {
    // ...
  });

You will then need to download the file directly from Google Cloud Storage by calling Kinvey.Files.downloadByUrl(); with the _downloadURL property of the KinveyFiles reference.

_downloadURL is a temporary URL that will expire one hour after your find() or findById() call is made to Kinvey. While you must begin your file download within that time limit, the download itself may take longer.

Specifying a custom expiration time using KinveyFiles

If you require the temporary download URL to last longer (or shorter) than one hour, you may optionally specify a custom expiration time (in seconds) using the kinveyFileTTL query parameter.

var dataStore = Kinvey.DataStore.collection('pets');
dataStore.findById('3f583e9f-d064-4a25-a953-6cf0a3dc2ff1', { kinveyFileTTL: 3600 })
  .subscribe(function(pet) {
    /*
      {
        "_id": "3f583e9f-d064-4a25-a953-6cf0a3dc2ff1",
        "_acl": {...},
        "dogName": "Bob",
        "furColor": "brown with black spots",
        "pawPrintPicture": {
          "_type": "KinveyFile",
          "_id": "325620e4-93dd-4a26-9f84-8a5e62c0db11",
          "_filename": "bobsPawPrint.png",
          "_acl": { ... },
          "_downloadURL": <Google Cloud Storage download URL>,
          "_expiresAt": "2018-06-18T23:07:23.394Z"
        }
      }
    */
  }, function(error) {
    // ...
  });

If you would like to upload a publicly-readable file that never expires, please refer to the upload publicly-readable files section.

Securely communicating with GCS using KinveyFiles

Secure communication is available as a query parameter when retrieving KinveyFile references through the Data Store API, as well. To use https instead of http, set the kinveyFileTLS parameter to true.

var dataStore = Kinvey.DataStore.collection('pets');
dataStore.findById('3f583e9f-d064-4a25-a953-6cf0a3dc2ff1', { kinveyFileTLS: true })
  .subscribe(function(pet) {
    /*
      {
        "_id": "3f583e9f-d064-4a25-a953-6cf0a3dc2ff1",
        "_acl": {...},
        "dogName": "Bob",
        "furColor": "brown with black spots",
        "pawPrintPicture": {
          "_type": "KinveyFile",
          "_id": "325620e4-93dd-4a26-9f84-8a5e62c0db11",
          "_filename": "bobsPawPrint.png",
          "_acl": { ... },
          "_downloadURL": <Google Cloud Storage download URL>,
          "_expiresAt": "2018-06-18T23:07:23.394Z"
        }
      }
    */
  }, function(error) {
    // ...
  });

Business Logic

You may create Business Logic code which will execute before or after each File API v3 route. To do so, simply add hooks to the _blob collection just like any other data collection. For more information on Business Logic, refer to the Business Logic guide.

Please note that Business Logic is only supported for File API version 3 routes. If you attempt to access a File API version 2 route that includes Business Logic, your request will fail.

Comprehensive reference

Properties

While you may include any number of custom metadata properties when saving your file, Kinvey uses certain properties to maintain its own metadata. This section contains a comprehensive list of all special Kinvey attributes that may be part of a file.

PropertyShort description
_idA unique identifier
_filenameA filename
_aclThe file's Access Control List
_kmdKinvey metadata, including lmt and ect
_publicIf set to true, the file is publicly accessible through an unsigned URL. Defaults to false
_downloadURLA link to GET the file
_expiresAtThe time at which the link will expire. Will not be included if the file's _public attribute is set to true

Special supported properties

The following properties, while optional, will allow the Kinvey Console to display more information about the file if you specify them as part of the file metadata.

PropertyShort description
mimeTypeThe mime type of the file (e.g. text/plain, image/png, etc)

Optional query parameters

ParameterApplies toDefaultShort description
ttlDownloading3600If set, Google Cloud Storage URLs will expire after the specified amount of time
tlsDownloading and UploadingfalseIf true, Google Cloud Storage URLs will use the https protocol instead of http
kinveyFileTTLKinveyFiles3600If set, Google Cloud Storage URLs will expire after the specified amount of time
kinveyFileTLSKinveyFilesfalseIf true, Google Cloud Storage URLs will use the https protocol instead of http