Himanshu Sharma Computer science student pursuing his Bachelor's and working as an SWE Intern. For the past 2 years, has been developing mobile and web apps using Flutter SDK. Open-source enthusiast and co-organizer of Flutter India.

Learning how to use AWS Amplify in Flutter

8 min read 2303

Learning AWS Amplify with Flutter

In this tutorial, you’ll learn about what AWS Amplify is and how to use it while building a Flutter to-do app.

The majority of organizations today use Amazon Web Services (AWS) to transition to a cloud-based model that provides 90+ services and products for fast, efficient, serverless, and secure development of web and mobile applications.

One among such services is AWS Amplify, and it’s gaining attention with a simplified and abstracted platform to aid web and mobile developers. It comes with a set of tools and services that offers users options to configure backends, connect apps, deploy static web apps, and manage context outside the AWS Console.

In this tutorial, you’ll learn how to do the following:

  • Add Amplify to a Flutter app
  • Generate data models
  • Integrate and configure Amplify
  • Connect to the cloud

N.B., this tutorial assumes you have some prior knowledge of Flutter. If you are new to Flutter, please go through the official documentation to learn about it.

However, before proceeding, make sure that you have the following requirements:

  • Git v2.14.1 or later
  • npm v5.x or later
  • Node.js v12.x or later
  • Flutter v2.0.0 or later (stable)
  • AWS Account (Create AWS Account)

Getting started with Amplify

Download the starter app containing all the prebuilt UI from here, as you’ll focus on learning Amplify currently.

Open it in your editor, build and run the app:

Beginner to-do app AWS

Now, you need to install Amplify CLI, which is a toolchain to configure services required to fuel your backend as follows:

We made a custom demo for .
No really. Click here to check it out.

npm install -g @aws-amplify/cli

N.B., you are installing Amplify CLI globally using -g.

After installation, configure Amplify by using the below command:

amplify configure

N.B., the above configuration asks you to sign invto the AWS Console.

Next, Amplify CLI will ask you to create an IAM user, as follows:

Specify the AWS Region
? region:  # Your preferred region
Specify the username of the new IAM user:
? user name:  # User name for Amplify IAM user
Complete the user creation using the AWS console

Amazon IAM (Identity and Access Management) enables you to manage users and user permissions in AWS. You can learn more about Amazon IAM here.

Now, go to the console and create a user with administrator access to utilize various AWS resources.

Set Up AWS in Flutter

Grab the accessKeyId and secretAccessKey after user creation, as Amplify CLI will ask you to provide these to connect CLI with the created IAM user:

Enter the access key of the newly created user:
? accessKeyId:  # YOUR_ACCESS_KEY_ID
? secretAccessKey:  # YOUR_SECRET_ACCESS_KEY
This would update/create the AWS Profile in your local machine
? Profile Name:  # (default)

Successfully set up the new user.

In the next step, you’ll start setting up your project and initialize Amplify in it.

Setting up project

Add Amplify to your Flutter app

Add the Amplify plugins in the pubspec dependencies as follows:

amplify_flutter: ^0.2.0
amplify_datastore: ^0.2.0
amplify_datastore_plugin_interface: ^0.2.4

Either save it using your IDE to install the plugins or use the below command for that:

flutter pub get

Update target iOS platform and Android version

Update the target iOS platform to 13.0 or later by navigating to the /ios directory and updating the Podfile:

platform :ios, '13.0'

Update the Android SDK version to 21 or later by navigating to the android/app directory and updating build.gradle:

minSdkVersion 21

Now, you are all set to use Amplify.

Creating data model

Create data model

Now, you need to create a data model which will be utilized by your blog app. These models are created as GraphQL Schemas.

Navigate to Amplify Admin and select the Data feature:

Amplify Admin Data Feature

Next, select the To-do list schema and click on Create new schema:

To-Do List Schema AWS

Add fields and type

  • To add a new field, click on Add a field under the To-do model.
  • Set the Field name of this field to isTaskCompleted
  • For the Type of this field, select Boolean
  • In the inspector panel (right panel), select Is required to make this field required

isTaskCompleted AWS

Next, click on Test locally in your app.

Generate data model

Now complete the deployment steps:

  1. What type of app are you building? Proceed to provide the following information and click Next:
    • Platform: Cross-platform
    • Framework/Language: Flutter
  2. (Optional) Create a new app: Skip this step if the Flutter app has already been created
  3. Install Amplify CLI to pull the data model: Amplify CLI is already configured, so proceed with running the provided command in your project’s root and click Next:
    amplify pull --sandboxId <UUID>
    1. The rest of the steps for the integration of Amplify and deployment will be covered later in this tutorial, so now click on Deploy to AWS and grab the Login to Deploy AWS link

Till now, a few new directories and files have been added to the root of your app. To check the GraphQL schema generated, navigate to amplify\backend\api\amplifyDatasource\schema.graphql and you should see the following:

type Todo @model @auth(rules: [{allow: public}]) {
  id: ID!
  name: String!
  description: String
  isTaskCompleted: Boolean!
}

N.B., you can learn more GraphQl Schemas here.

Now, your models are successfully generated and can be found in todorocket\lib\models.

Folder Structure AWS

Integrating Amplify

Now, you’ll Integrate Amplify DataStore and use the generated model.

Update the todo_view.dart to initialize Amplify Libraries, as follows:

// Amplify Flutter Packages
import 'package:amplify_flutter/amplify.dart';
import 'package:amplify_datastore/amplify_datastore.dart';

// Generated in the previous step
import 'models/ModelProvider.dart';
import 'amplifyconfiguration.dart';

Update the _configureAmplify method in _TodosViewState class as below:

  final AmplifyDataStore _dataStorePlugin =
      AmplifyDataStore(modelProvider: ModelProvider.instance);

Future<void> _configureAmplify() async {
    try {
      await Amplify.addPlugins([_dataStorePlugin]);

      await Amplify.configure(amplifyconfig);
    } catch (err) {
      debugPrint('Erro occured while configuring Amplify $err');
    }
  }

Here, you did the following:

  1. Created AmplifyDataStore object, _dataStorePlugin.
  2. Updated the _configureAmplify method to use _dataStorePlugin to configure Amplify.

Next, create a list of types of Todo, and update the body property of the build method as below:

List<Todo> _todos = [];

@override
  Widget build(BuildContext context) {
    ...
      // body: const Center(child: CircularProgressIndicator()),
      body: _isLoading
          ? const Center(child: CircularProgressIndicator())
          : TodosList(todos: _todos),
    ...
  }
}

Here, you are checking whether Amplify is configured or not. Restart your app, now you’ll see a message instead of a progress indicator:

Checking Amplify Configuration

Now, you need to update the _fetchTodos method to use the CRUD API locally using DataStore:

Future<void> _fetchTodos() async {
    try {
      List<Todo> updatedTodos = await Amplify.DataStore.query(Todo.classType);

      // update the UI state to reflect fetched todos
      setState(() {
        _todos = updatedTodos;
      });
    } catch (e) {
      print('An error occurred while querying Todos: $e');
    }
  }

In the above code, you are using a DataStore.query() for all todo entries and assigning the result to _todos list. If you restart your project now, you won’t see any todo item as we haven’t used the Save query yet.

Creating a to-do

The Add button in the Home screen navigates you to the Add To-do Form view that doesn’t do anything when clicking on the Save button. You need to fix this so that you can see a Todo on the Home screen.

Update the _saveTodo method, as below:

Future<void> _saveTodo() async {
    String name = _nameController.text;
    String description = _descriptionController.text;

    Todo newTodo =
        Todo(name: name, description: description, isTaskCompleted: false);

    try {
      await Amplify.DataStore.save(newTodo);
      Navigator.pop(context);
    } catch (e) {
      debugPrint('Error occured while saving Todo $e');
    }
  }

Here, you created a newTodo object and saved it using DataStore. If you try to save a Todo now, you’ll be redirected to the Home screen. However, you cannot see any new Todo even after restarting the app. So to fix this, you need to create a query to list them all.

Querying Todos

Update the _initializeApp method in the _TodosViewState class, as following:

Future<void> _initializeApp() async {

  await _configureAmplify();

  await _fetchTodos();

  setState(() {
    _isLoading = false;
  });
}

N.B., you can also use .then after the _configureAmplify method.

In the above code, you called the _fetchTodos method to fetch all the Todos from the DataStore after the Amplify configuration.

Next, update the _fetchTodos method as below:

Future<void> _fetchTodos() async {
    try {
      List<Todo> updatedTodos = await Amplify.DataStore.query(Todo.classType);

      setState(() {
        _todos = updatedTodos;
      });
    } catch (e) {
      print('An error occurred while querying Todos: $e');
    }
  }

Here, you are querying all the Todo entries by passing the Todo classType to DataStore and updating the UI state to display the fetched data.

If you restart your app now, you can see your added Todos. However, if you create a new Todo, you won’t see them on the Home screen unless you restart your app. Now you’ll address this issue and make real-time Todo creation.

Listening to Todo Updates

Amplify DataStore provides a way to subscribe to data updates to your model.

Now, add a StreamSubscription under the _TodosViewState:

 late StreamSubscription _subscription;

Here you created a subscription to Todo model update events that’ll be later initialized at runtime.

Next, update the dispose method as below:

@override
void dispose() {
  _subscription.cancel();
  super.dispose();
}

In the above code, you cancel the subscription when the state is removed from the tree.

Next, update the _initializeApp method as below:

Future<void> _initializeApp() async {

  await _configureAmplify();

  _subscription = Amplify.DataStore.observe(Todo.classType).listen((event) {
    _fetchTodos();
  });

  await _fetchTodos();

  setState(() {
    _isLoading = false;
  });
}

In the above code, you are listening for the Todo updates by passing the Todo classType to Amplify.DataStore.observe(), and when an update event comes, you are fetching the to-do list.

If you restart your application and start adding new Todo, they’ll start popping up on your Home screen.

Now, what happens after you complete your Todo? You need to mark that Todo as done, and if you noticed, you can see a checkbox on a Todo item. So now you need to update your Todo when your task is done.

Updating Todo

In DataStore, you cannot directly manipulate a record as the models in DataStore are immutable. So to update one record, you’ll use the copyWith method.

Now, update the _toggleIsComplete method in the TodoItem class as below:

Future<void> _toggleIsComplete() async {
    Todo updatedTodo = todo.copyWith(isTaskCompleted: !todo.isTaskCompleted);
    try {
      await Amplify.DataStore.save(updatedTodo);
    } catch (e) {
      print('An error occurred while saving Todo: $e');
    }
  }

Here you are creating a new instance of the Todo you want to update, but with additional properties updated and then again passing the new instance to Amplify.DataStore.save() to update.

Now, restart your app and you are now able to toggle in between the complete and incomplete state of your Todo. Additionally, if you wish you can also delete a Todo.

Deleting a Todo

Deleting a Todo is much easier than updating it because you don’t need to copy the object to delete it. So to delete a Todo from the existing project, you can use the long-press gesture or change according to your liking.

Now, update the _deleteTodo method in TodoItem as follows:

void _deleteTodo(BuildContext context) async {
    try {
      await Amplify.DataStore.delete(todo);
    } catch (e) {
      print('An error occurred while deleting Todo: $e');
    }
  }

In the above code, you are passing the Todo object to DataStore.delete() to delete data from DataStore.

Reload your app once and you should be able to long-press an item to delete it. Now you have a fully-featured CRUD application in your hands.

Next, you’ll connect your app to AWS.

Connecting to cloud

For deployment of your Amplify sandbox backend, return to the sandbox link and log in to your AWS account.

Connecting to AWS Cloud

Create the app backend

To create your app backend, provide the data in creation form:

  1. Give your app name
  2. Select your deployment region
  3. Click on Confirm Deployment

Create AWS App Backend

Next, AWS will start deploying your backend, and when the status is displayed as Deployment completed, click on Edit backend to open your admin UI.

Edit AWS Backend

Add authentication

Since your To-do model specifies an @auth directive, we need to first add authentication. From the left panel, select Authentication. Click Deploy with default values.

Admin UI Authentication

Update local project with the deployed environment

After authentication deployment, click on the Local setup instructions on the top right.

Local Setup Instructions

Now, copy the command to pull the backend in your local and run it.

This will prompt you to log in to Amplify Admin UI using Amplify CLI; click Yes.

Later proceed according to your choices:

amplify pull --appId <appId> --envName staging

? Choose your default editor:
    `<your editor of choice>`
? Choose the type of app that you're building
    `flutter`
? Where do you want to store your configuration file?
    `./lib/`
? Do you plan on modifying this backend?
    `Yes`

Add more plugins

Now we need to add some additional plugins that will ensure that DataStore has access to the API access it requires for communicating with the cloud:

amplify_api: ^0.2.0
amplify_auth_cognito: ^0.2.0

Add the above dependencies in your pubspec.yaml and do flutter pub get.

Next, add these plugins before you configure Amplify in the _TodosViewState class and update the _configureAmplify method:

final AmplifyAPI _apiPlugin = AmplifyAPI();
final AmplifyAuthCognito _authPlugin = AmplifyAuthCognito();

Future<void> _configureAmplify() async {
    try {
      await Amplify.addPlugins([_dataStorePlugin, _apiPlugin, _authPlugin]);

      await Amplify.configure(amplifyconfig);
    } catch (err) {
      debugPrint('Erro occured while configuring Amplify $err');
    }
  }

Since Amplify can only be configured once, you will need to do a full restart (stop and restart the app) now instead of just a hot restart. And you’re done!

Todorocket Demo

Conclusion

You can find the starter and final project here. In this tutorial, you learned about AWS Amplify and how you can easily use DataStore to build a featured CRUD Application. However, this is only the beginning, you can learn more about authentication, storage, function, REST/GraphQl APIs, and more libraries from the AWS docs here.

We hope you enjoyed this tutorial. Feel free to reach out to us if you have any queries. Thank you!

Himanshu Sharma Computer science student pursuing his Bachelor's and working as an SWE Intern. For the past 2 years, has been developing mobile and web apps using Flutter SDK. Open-source enthusiast and co-organizer of Flutter India.

Leave a Reply