DEV Community

Cover image for #30DaysofAppwrite : Appwrite Storage API
Damodar Lohani for Appwrite

Posted on • Updated on

#30DaysofAppwrite : Appwrite Storage API

Intro

Appwrite is an open-source, self-hosted Backend-as-a-Service that makes app development easier with a suite of SDKs and APIs to accelerate app development. #30DaysOfAppwrite is a month long event focused on giving developers a walkthrough of all of Appwrite's features, starting from the basics to more advanced features like cloud functions! Alongside we will also be building a fully featured Medium clone to demonstrate how these concepts can be applied when building a real world app. We also have some exciting prizes for developers who follow along with us!

Appwrite Storage API

Every application needs more than just a database, it needs Storage. Appwrite comes bundled with an extensive Storage API which allows you to manage your projects' files. Appwrite's Storage service provides us with a sleek API to upload, download, preview and manipulate images.

How Is Storage Implemented

As of now, Appwrite mounts a Docker volume using the host machine's storage to provide the Storage service. So, it's using the local filesystem to store all the files that you upload to Appwrite. We are working on adding support for external object storage like AWS S3, DigitalOcean Spaces or other similar services. You can check the progress regarding this in our utopia-php/storage library.

Managing Storage using Appwrite Console

Appwrite's console supports easy management of files in storage. From here you can create files, update metadata of files, view or download files, and also delete files.

Storage UI

You can create a new file easily by clicking on the circular + button at the bottom right corner.

Storage New UI

Each file in the service is granted with read and write permissions to manage who has access to view or edit it. These permissions work in the same way the database permissions work, which is already covered in Day 15 for you to review.

For existing files in storage, you can see a preview and update permissions right from the console. You can also view the original file in new window or download the file.

Storage Edit UI

Services

The Storage API provides us with few different endpoints to manipulate our files.

Create File

We can make a POST <ENDPOINT>/storage/files request to upload a file. In SDKs this endpoint is exposed as storage.createFile(). It requires three parameters: the binary file, an array of strings to define the read permissions, and the same for write permissions.

We can use the below code to create file from our Web SDK.

let sdk = new Appwrite();

sdk
    .setEndpoint('https://demo.appwrite.io/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
;

let promise = sdk.storage
    .createFile(document.getElementById('uploader').files[0], ['*'], ['role:member']);

promise.then(function (response) {
    console.log(response); // Success
}, function (error) {
    console.log(error); // Failure
});
Enter fullscreen mode Exit fullscreen mode

Or in Flutter we could use

import 'package:appwrite/appwrite.dart';

void main() { // Init SDK
  Client client = Client();
  Storage storage = Storage(client);

  client
    .setEndpoint('https://demo.appwrite.io/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
  ;
  Future result = storage.createFile(
    file: await MultipartFile.fromFile('./path-to-files/image.jpg', 'image.jpg'),
    read: ['*'],
    write: ['role:member'],
  );

  result
    .then((response) {
      print(response);
    }).catchError((error) {
      print(error.response);
  });
}
Enter fullscreen mode Exit fullscreen mode

List Files

We can make a GET <ENDPOINT>/storage/files request in order to list files. In SDKs this is exposed as storage.listFiles(). We can also use the search parameter to filter results. You can also include limit, offset and orderType parameters to further customize the returned results.

With the Web SDK:

let sdk = new Appwrite();

sdk
    .setEndpoint('https://demo.appwrite.io/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
;

let promise = sdk.storage.listFiles();

promise.then(function (response) {
    console.log(response); // Success
}, function (error) {
    console.log(error); // Failure
});
Enter fullscreen mode Exit fullscreen mode

And with Flutter:

import 'package:appwrite/appwrite.dart';

void main() { // Init SDK
  Client client = Client();
  Storage storage = Storage(client);

  client
    .setEndpoint('https://demo.appwrite.io/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
  ;
  Future result = storage.listFiles();

  result
    .then((response) {
      print(response);
    }).catchError((error) {
      print(error.response);
  });
}
Enter fullscreen mode Exit fullscreen mode

Get File

We can make a GET <ENDPOINT>/storage/files/{fileid} request to an individual file by its id. It returns a JSON object with the file metadata. In SDKs this endpoint is exposed as storage.getFiles() which requires the fileId parameter.

With the Web SDK:

let sdk = new Appwrite();

sdk
    .setEndpoint('https://<HOSTNAME_OR_IP>/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
;

let promise = sdk.storage.getFile('[FILE_ID]');

promise.then(function (response) {
    console.log(response); // Success
}, function (error) {
    console.log(error); // Failure
});
Enter fullscreen mode Exit fullscreen mode

With Flutter:

import 'package:appwrite/appwrite.dart';

void main() { // Init SDK
  Client client = Client();
  Storage storage = Storage(client);

  client
    .setEndpoint('https://<HOSTNAME_OR_IP>/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
  ;
  Future result = storage.getFile(
    fileId: '[FILE_ID]',
  );

  result
    .then((response) {
      print(response);
    }).catchError((error) {
      print(error.response);
  });
}
Enter fullscreen mode Exit fullscreen mode

File Preview

The preview endpoint allows you to generate preview images for your files. Using the preview endpoint, you can also manipulate the resulting image so that it will fit perfectly inside your app in terms of dimensions, file size, and style. Additionally, the preview endpoint allows you to change the resulting image file format for better compression or change the image quality for better delivery over the network.

We can make a GET <ENDPOINT>/storage/files/{fileId}/preview request to get a preview for image files. It supports parameters like width, height, quality, background and output format to manipulate the preview image. This method is exposed as storage.getFilePreview() and requires a fileId.

We have even more awesome features like border, border radius, and opacity support for the preview endpoint in the upcoming Appwrite 0.8 release.

With the Web SDK:

let sdk = new Appwrite();

sdk
    .setEndpoint('https://<HOSTNAME_OR_IP>/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
;

let result = sdk.storage.getFilePreview('[FILE_ID]', 100, 100); //crops the image into 100x100

console.log(result); // Resource URL
Enter fullscreen mode Exit fullscreen mode

And with Flutter:

import 'package:appwrite/appwrite.dart';

void main() { // Init SDK
  Client client = Client();
  Storage storage = Storage(client);

  client
    .setEndpoint('https://<HOSTNAME_OR_IP>/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
  ;
}

//displaying image
FutureBuilder(
  future: storage.getFilePreview(
    fileId: '[FILE_ID]',
    width: 100
    height: 100
  ),
  builder: (context, snapshot) {
    return snapshot.hasData && snapshot.data != null
      ? Image.memory(
          snapshot.data.data,
        )
      : CircularProgressIndicator();
  },
);
Enter fullscreen mode Exit fullscreen mode

File Download

We can make a GET <ENDPOINT>/storage/files/{fileId}/download request to get the contents of a file by its unique ID. The endpoint response includes a Content-Disposition: attachment header that tells the browser to start downloading the file to user downloads directory. This method is exposed as storage.getFileDownload(), and a fileId is required.

With the Web SDK:

let sdk = new Appwrite();

sdk
    .setEndpoint('https://<HOSTNAME_OR_IP>/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
;

let result = sdk.storage.getFileDownload('[FILE_ID]');

console.log(result); // Resource URL
Enter fullscreen mode Exit fullscreen mode

With Flutter:

import 'package:appwrite/appwrite.dart';

void main() { // Init SDK
  Client client = Client();
  Storage storage = Storage(client);

  client
    .setEndpoint('https://<HOSTNAME_OR_IP>/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
  ;
}

//displaying image
FutureBuilder(
  future: storage.getFileDownload(
    fileId: '[FILE_ID]',
  ),
  builder: (context, snapshot) {
    return snapshot.hasData && snapshot.data != null
      ? Image.memory(
          snapshot.data.data,
        )
      : CircularProgressIndicator();
  },
);
Enter fullscreen mode Exit fullscreen mode

File View

We can make a GET <ENDPOINT>/storage/files/{fileId}/view request to get the contents of a file by its unique ID. This endpoint is similar to the download method but returns with no Content-Disposition: attachment header.

With the Web SDK:

let sdk = new Appwrite();

sdk
    .setEndpoint('https://<HOSTNAME_OR_IP>/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
;

let result = sdk.storage.getFileView('[FILE_ID]');

console.log(result); // Resource URL
Enter fullscreen mode Exit fullscreen mode

With Flutter:

import 'package:appwrite/appwrite.dart';

void main() { // Init SDK
  Client client = Client();
  Storage storage = Storage(client);

  client
    .setEndpoint('https://<HOSTNAME_OR_IP>/v1') // Your API Endpoint
    .setProject('5df5acd0d48c2') // Your project ID
  ;
}

//displaying image
FutureBuilder(
  future: storage.getFileView(
    fileId: '[FILE_ID]',
  ),
  builder: (context, snapshot) {
    return snapshot.hasData && snapshot.data != null
      ? Image.memory(
          snapshot.data.data,
        )
      : CircularProgressIndicator();
  },
);
Enter fullscreen mode Exit fullscreen mode

More detailed information about the Storage service can be found in our docs.

Credits

We hope you liked this write-up. You can follow #30DaysOfAppwrite on Social Media to keep up with all of our posts. The complete event timeline can be found here

Feel free to reach out to us on Discord if you would like to learn more about Appwrite, Aliens or Unicorns 🦄. Stay tuned for tomorrow's article! Until then 👋

Top comments (0)