Getting started with Appwrite Cloud and Flutter
Tags: cloud, appwrite, webdev, flutter
Published: 2023-06-05 10:52:49

Isn’t it nice to have all the traditional backend features on the web? Appwrite cloud alleviates the need to manage a server. [Appwrite cloud](https://appwrite.io/cloud?utm_source=hackmamba&utm_medium=hackmamba-blog) is a backend as a service (BaaS) with all the necessary APIs to build your modern application. These APIs assist in building client and server-side applications. A use case of Appwrite is the Database API, which assists in implementing CRUD (create, read, update, delete) features in your application.

This article will show you how to use an input element to create, store, view and delete text in Flutter using [Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog).


## Prerequisites

To follow along with this tutorial, the following are required:

- [Xcode](https://developer.apple.com/xcode/) (with developer account for Mac users)
- iOS Simulator, Android Studio, or Chrome web browser to run the application
- Appwrite [cloud](https://appwrite.io/cloud?utm_source=hackmamba&utm_medium=hackmamba-blog) access. It is currently in beta testing.


## Creating an Appwrite project

You can apply to the [Appwrite cloud](https://cloud.appwrite.io/login?utm_source=hackmamba&utm_medium=hackmamba-blog) to access the private beta. Once you access Appwrite’s cloud private beta, create a project and fill in the **project's name and id;** otherwise, [use Appwrite locally with Docke](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9)r or [DigitalOcean droplet.](https://marketplace.digitalocean.com/apps/appwrite)


![Create Project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cynje5138vjtj1zy4w84.png)


Also, you will need a database collection to perform CRUD operations. Head to Databases, select `Create Database`, and fill in the database `name and ID`. After, create a new collection by selecting `Create collection` and filling in the subsequent `name and ID`. 



![Databases](https://paper-attachments.dropboxusercontent.com/s_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685788990392_2023-06-03+11_39_14-.png)
![Create databases](https://paper-attachments.dropboxusercontent.com/s_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685788990491_2023-06-03+11_37_24-.png)
![Create collections](https://paper-attachments.dropboxusercontent.com/s_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685788990580_2023-06-03+11_37_55-.png)


It is necessary to have parameters to hold data within your collection. Thus, head to the attributes section within the collection created earlier and add the attributes in the following table to the collection:

| Attribute key | Attribute type |
| ------------- | -------------- |
| title         | String         |
| subtitle      | String         |


Finally, head to the collection settings section and set the collection and document level permission to `role:any` and check all the CRUD permissions. These permissions allow anyone to create, read, update, and delete documents from the collection.

![Update permission 1](https://paper-attachments.dropboxusercontent.com/s_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685789183553_2023-06-03+11_45_34-Window.png)
![Update permission 2](https://paper-attachments.dropboxusercontent.com/s_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685789183614_2023-06-03+11_44_55-Window.png)

## Cloning the UI template

This section uses a UI template containing user registration and login code. Let’s clone the [repository](https://github.com/muyiwexy/getting_started_with_cloud) specified in the prerequisites. Check out the official GitHub [docs](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) to learn more about cloning a repository.

![GitHub clone 1](https://paper-attachments.dropboxusercontent.com/s_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1682462067276_Screenshot+295.png)
![GitHub clone 2](https://paper-attachments.dropboxusercontent.com/s_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1682462067360_Screenshot+296.png)


After cloning the UI to your local storage, open it in your preferred code editor and run the command below:

```javascript
flutter pub get
```

This command obtains all the dependencies listed in the `pubspec.yaml` file in the current working directory and their transitive dependencies. Next, run the command `flutter run`, and your application should look like the image below:


![clone result](https://paper-attachments.dropboxusercontent.com/s_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1685719912564_2023-06-02+16_30_41-Window.png)


The `lib` directory tree should look like this:

```javascript
    lib/
    ├─ auth/
    │  ├─ app_provider.dart
    ├─ model/
    │  ├─ documentmodel.dart
    ├─ pages/
    │  ├─ components/
    │  │  ├─ add_item_modal.dart
    │  │  ├─ edit_item_modal.dart
    │  ├─ home.dart
    ├─ main.dart
```


## Explaining the UI and functionalities

**Functionalities**
Before beginning, create a file `app_constants.dart` to store important constants from Appwrite. Update the `app_constants.dart` with the code below:

``` javascript
class Appconstants {
  static const String projectid = "<projectID>";
  static const String endpoint = "<cloud endpoint>";
  static const String dbID = "<database ID>";
  static const String collectionID = "<collection ID>";
}
```

The project utilizes the Provider package for its state management purposes. Thus, the `app_provider.dart` file defines a class named `AppProvider` that is implementing `ChangeNotifier`. The `AppProvider` class contains various methods for creating, listing, updating, and removing documents in a database using the `Appwrite` package.

{% embed https://gist.github.com/muyiwexy/a7376fbf8130b9ce3f81e21aeacb64ae %}

In the code above, the `AppProvider` class implements the `ChangeNotifier` class to handle changes in your application’s state. The `Client` class instance, named `client`, is tasked with communicating with the Appwrite API.

The `Account` and `Databases` instances communicate with the account and database API. This allows you to create a user account on the client side and perform the CRUD operations.

The code above uses the `initialize` method to set up the `client` instance by setting the endpoint and project and creating an anonymous session for the user.

To utilize the CRUD operations in Appwrite, here is a summary of the document-based methods in the code:


- `createDocument` method takes in `newTitle`, `newSubtitle`, and `context` parameters to create a new document in the specified database and collection. It then adds the new document to the list of documents and closes the add document screen.
- `listDocument` method lists all the documents in the specified database and collection. It maps the returned list of documents to a list of `ListItem` objects and sets the `_listItem` variable to this list. 
    

You can use a model class to map the JSON when getting a list of documents from Appwrite. Thus, add the code below in `documentmodel.dart` file

``` javascript
class UserFields {
  static const String id = "\$id";
  static const String title = "title";
  static const String subtitle = "subtitle";
}
class ListItem {
  String? id;
  String? title;
  String? subtitle;
  ListItem({
    required this.id,
    required this.title,
    required this.subtitle,
  });
  ListItem.fromJson(Map<String, dynamic> json) {
    id = json[UserFields.id];
    title = json[UserFields.title];
    subtitle = json[UserFields.subtitle];
  }
  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    data[UserFields.id] = id;
    data[UserFields.title] = title;
    data[UserFields.subtitle] = subtitle;
    return data;
  }
}
```

- the `updateDocument` method takes in `documentId`, `updateTitle`, and `updateSubtitle` parameters to update the specified document in the database with the new title and subtitle.
- the `removeDocument` method takes in `documentId` and `index` parameters to delete the specified document from the database and remove it from the list of documents. 

Overall, the `AppProvider` class provides a way to manage documents in an Appwrite database in a Flutter application.

**UI (User interface)**
The pages folder consists of the entirety of the user interface. The user interface consists of a centered container whose primary action is to display a list of created items. The Container has an `ElevatedButton` widget with an `onPressed` action displaying a modal. This displayed modal consists of a formfield (input and button) that takes values to create an item.

To perform an update action, wrap the list in an `Inkwell` widget and attach an `onTap` property that shows an editable modal that updates the list and the document on Appwrite.


``` javascript
//Home.dart 

Widget appContainer(BuildContext context, state) {
  return Container(
      height: MediaQuery.of(context).size.height,
      width: MediaQuery.of(context).size.width,
      margin: const EdgeInsets.only(left: 50, right: 50, top: 50),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(25.0),
        color: const Color.fromARGB(238, 238, 232, 198),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Padding(
            padding: const EdgeInsets.all(20.0),
            child: ElevatedButton.icon(
              onPressed: () {
                // Handle the tap event by displaying a dialog box where the user can edit the data
                showDialog(
                  context: context,
                  builder: (BuildContext context) {
                    // Return the dialog widget
                    return const AddItemDialog();
                  },
                );
              },
              icon: const Icon(
                Icons.add,
                size: 24.0,
              ),
              label: const Text("Add Item"),
            ),
          ),
          items(state)
        ],
      ));
}
Widget items(state) {
  return Expanded(
      child: Container(
          child: state.listItem.isEmpty
              ? const Center(
                  child: Text(
                    "No items found",
                    style: TextStyle(fontWeight: FontWeight.w800),
                  ),
                )
              : listContainer(state)));
}
Widget listContainer(state) {
  return ListView.builder(
    itemCount: state.listItem.length,
    itemBuilder: (BuildContext context, int index) {
      return InkWell(
        onTap: () {
          // Handle the tap event by displaying a dialog box where the user can edit the data
          showDialog(
            context: context,
            builder: (BuildContext context) {
              // Return the dialog widget
              return EditListItemDialog(
                item: state.listItem[index],
                onSave: (ListItem editedItem) {
                  // Update the item in the list with the edited data
                  state.listItem[index] = editedItem;
                  // Rebuild the UI to reflect the updated data
                  setState(() {});
                },
              );
            },
          );
        },
        child: ListTile(
          title: Text(state.listItem[index].title),
          subtitle: Text(state.listItem[index].subtitle),
          trailing: IconButton(
            icon: const Icon(Icons.delete),
            onPressed: () =>
                state.removeReminder(state.listItem[index].id, index),
          ),
        ),
      );
    },
  );
}
```

`Add item AlertDialog`

{% embed https://gist.github.com/muyiwexy/a551020eb205af6cf15adcf380dc93d1 %}



`Edit/Update item AlertDialog`

{% embed https://gist.github.com/muyiwexy/9ff742e1c7e43fdac8b740cfc3cd3c4d %}


When you run the application, your result should look like the GIF below:

![result](https://paper-attachments.dropboxusercontent.com/s_67C901E4B6FF75C9D09ACF7B3E65BDFA6B104A823AEA5D335459C86502EADB98_1682461851671_ezgif.com-video-to-gif+5.gif)



## Conclusion

Though still in beta testing, [Appwrite Cloud](https://appwrite.io/cloud?utm_source=hackmamba&utm_medium=hackmamba-blog) is a game-changer, enabling the creation of backend functionalities swiftly and easily while providing the same benefits as using Appwrite locally. This tutorial has shown how to create CRUD features using the Appwrite cloud and Flutter. 


## Resources
- [Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Appwrite Cloud](https://cloud.appwrite.io/login?utm_source=hackmamba&utm_medium=hackmamba-blog)
- [Appwrite Databases API](https://appwrite.io/docs/client/databases?utm_source=hackmamba&utm_medium=hackmamba-blog)