DEV Community

Cover image for Going fullstack with Flutter and MongoDB Atlas Data API
Demola Malomo
Demola Malomo

Posted on • Edited on • Originally published at fullstackwriter.dev

Going fullstack with Flutter and MongoDB Atlas Data API

Application Programming Interface (API) has revolutionized how applications are built. It enables software modules to communicate with each other using sets of standards. APIs have allowed companies to integrate new applications with existing software systems, provide an avenue for rapid innovation, and act as a gateway for enhancing customer experience across multiple platforms (mobile, web, etc.).

With the possibilities that APIs offer, it has also come with its share of difficulties. Developers are burdened with selecting the right database, integrating security, logging and monitoring, etc.

In this post, we will learn how to build a mobile phonebook using MongoDB Data API and Flutter. The project’s GitHub repository can be found here.

What is MongoDB Data API

MongoDB Data API is a fully managed platform-agnostic service that provides a secure and fast standard HTTPS for managing data stored on MongoDB. Web browsers, web servers, CI/CD pipelines, serverless & edge computing environments, mobile applications, or any HTTPS-enabled platforms can connect to the Data API using standard HTTPS requests. The Data API also ships with the following:

  • Authorization and authentication mechanism
  • Data validation when writing and reading from the API
  • Support for JSON or EJON API response

Prerequisites

To fully grasp the concepts presented in this tutorial, the following are required:

Getting started

To get started, we need to clone the project by navigating to the desired directory and running the command below:

git clone https://github.com/Mr-Malomz/flutter_mongo && cd flutter_mongo
Enter fullscreen mode Exit fullscreen mode

Running the project

First, we need to install the project dependencies by running the command below:



    flutter pub get


Enter fullscreen mode Exit fullscreen mode

Then, run the project using the following command:



    flutter run


Enter fullscreen mode Exit fullscreen mode

The command above will run the application on the selected device.

Home screen
Create contact
Edit contact

Setting up MongoDB Data API

Create a Database

With our application up and running, we need to log in or sign up into our MongoDB account. Click the project dropdown menu and click on the New Project button.

New Project

Enter the flutter_realm as the project name, click Next, and click Create Project.

enter project name
Create Project

Click on Build a Database

Select Shared as the type of database and Create to set up a cluster.

Shared highlighted in red

Next, we need to navigate to the Database menu, click the Browse Collection tab, and click the Add My Own Data button to add sample data to our database.

Navigate to Database
Click Browse Collection
click Add My Own Data

To add sample data, first, we need to create a phonebook database and a phonebookCollection collection.

Create database and collection
Create database and collection

Lastly, we need to add sample data to our phonebookCollection as shown below:

Key Value Object Type
fullname John Travolta String
phonenumber 907865744546 Int64


Setup the Data API

With our database fully set up, first, we need to navigate to the Data API tab, select the Cluster our database was created in and click the Enable Data Access from the Data API button.

configure and create API
Created API

With that done, MongoDB automatically provides us with a fast and secure API service. By default, the provisioned API is inaccessible. We need to create an API key to connect to the API securely. To do this, click the Create API Key button, input flutter_mongo as the name and Generate API Key.

create API key
Generate

PS: We must copy the generated API key. It will come in handy when integrating the API with our Flutter application.

Integrating MongoDB Data API with Flutter

With all that done, we can start building our application using the API. First, we need to create a model to convert the response sent from the Data API to a Dart object. The model will also cater to JSON serialization. To do this, we need to create a utils.dart file in the lib folder and add the snippet below:



    class PhoneBook {
      String? id;
      String fullname;
      int phonenumber;

      PhoneBook({
        this.id,
        required this.fullname,
        required this.phonenumber,
      });
      Map<dynamic, dynamic> toJson() {
        return {
          "fullname": fullname,
          "phonenumber": phonenumber,
        };
      }

      factory PhoneBook.fromJson(Map<dynamic, dynamic> json) {
        return PhoneBook(
          id: json['_id'],
          fullname: json['fullname'],
          phonenumber: json['phonenumber'],
        );
      }
    }


Enter fullscreen mode Exit fullscreen mode

Next, we must create a service file to separate the application core logic from the UI. To do this, create a phone_service.dart file inside the lib directory. Then, add the snippet below:



    import 'dart:convert';
    import 'package:flutter_mongo/utils.dart';
    import 'package:dio/dio.dart';

    class PhoneService {
      final dio = Dio();
      final String _dataSource = "Cluster0";
      final String _database = "phonebook";
      final String _collection = "phonebookCollection";
      final String _endpoint = "<REPLACE WITH THE ENDPOINT URL>";
      static const _apiKey = "REPLACE WITH THE API KEY";
      var headers = {
        "content-type": "application/json",
        "apiKey": _apiKey,
      };

      Future<List<PhoneBook>> getPhoneContacts() async {
        var response = await dio.post(
          "$_endpoint/action/find",
          options: Options(headers: headers),
          data: jsonEncode(
            {
              "dataSource": _dataSource,
              "database": _database,
              "collection": _collection,
              "filter": {},
            },
          ),
        );
        if (response.statusCode == 200) {
          var respList = response.data['documents'] as List;
          var phoneList = respList.map((json) => PhoneBook.fromJson(json)).toList();
          return phoneList;
        } else {
          throw Exception('Error getting phone contacts');
        }
      }

      Future<PhoneBook> getSinglePhoneContact(String id) async {
        var response = await dio.post(
          "$_endpoint/action/find",
          options: Options(headers: headers),
          data: jsonEncode(
            {
              "dataSource": _dataSource,
              "database": _database,
              "collection": _collection,
              "filter": {
                "_id": {"\$oid": id}
              },
            },
          ),
        );
        if (response.statusCode == 200) {
          var resp = response.data\['documents'\][0];
          var contact = PhoneBook.fromJson(resp);
          return contact;
        } else {
          throw Exception('Error getting phone contact');
        }
      }

      Future updatePhoneContact(String id, String fullname, int phonenumber) async {
        var response = await dio.post(
          "$_endpoint/action/updateOne",
          options: Options(headers: headers),
          data: jsonEncode(
            {
              "dataSource": _dataSource,
              "database": _database,
              "collection": _collection,
              "filter": {
                "_id": {"\$oid": id}
              },
              "update": {
                "\$set": {"fullname": fullname, "phonenumber": phonenumber}
              }
            },
          ),
        );
        if (response.statusCode == 200) {
          return response.data;
        } else {
          throw Exception('Error getting phone contact');
        }
      }

      Future createPhoneContact(String fullname, int phonenumber) async {
        var response = await dio.post(
          "$_endpoint/action/insertOne",
          options: Options(headers: headers),
          data: jsonEncode(
            {
              "dataSource": _dataSource,
              "database": _database,
              "collection": _collection,
              "document": {"fullname": fullname, "phonenumber": phonenumber}
            },
          ),
        );
        if (response.statusCode == 201) {
          return response.data;
        } else {
          throw Exception('Error creating phone contact');
        }
      }

      Future deletePhoneContact(String id) async {
        var response = await dio.post(
          "$_endpoint/action/deleteOne",
          options: Options(headers: headers),
          data: jsonEncode(
            {
              "dataSource": _dataSource,
              "database": _database,
              "collection": _collection,
              "filter": {
                "_id": {"\$oid": id}
              },
            },
          ),
        );
        if (response.statusCode == 200) {
          return response.data;
        } else {
          throw Exception('Error deleting phone contact');
        }
      }
    }


Enter fullscreen mode Exit fullscreen mode

The snippet above does the following:

  • Imports the required dependencies
  • Creates a PhoneService class with _dataSource, _database, _collection, _endpoint, _apikey, and headers properties.
  • Creates the getPhoneContacts, getSinglePhoneContact, updatePhoneContact, createPhoneContact, and deletePhoneContact methods that uses the Dio package to configure permissions and make secure HTTPS request to the Data API configured earlier and returns the appropriate responses

Consuming the service

With that done, we can use the service to perform the required operation.

Get all contacts

To get started, we need to modify the home.dart file in the screens directory and update it by doing the following:

First, we need to import the required dependencies and create a method to get the list of contacts saved in the database:



    import 'package:flutter/material.dart';
    import 'package:flutter_mongo/phone_service.dart';
    import 'package:flutter_mongo/screens/create.dart';
    import 'package:flutter_mongo/screens/detail.dart';
    import 'package:flutter_mongo/utils.dart';

    class Home extends StatefulWidget {
      const Home({super.key});
      @override
      State<Home> createState() => _HomeState();
    }

    class _HomeState extends State<Home> {
      late List<PhoneBook> contacts;
      bool _isLoading = false;
      bool _isError = false;

      @override
      void initState() {
        getContacts();
        super.initState();
      }

      getContacts() {
        setState(() {
          _isLoading = true;
        });
        PhoneService().getPhoneContacts().then((value) {
          setState(() {
            contacts = value;
            _isLoading = false;
          });
        }).catchError((onError) {
          setState(() {
            _isLoading = false;
            _isError = true;
          });
        });
      }

      @override
      Widget build(BuildContext context) {
       // UI CODE GOES HERE
      }
    }


Enter fullscreen mode Exit fullscreen mode

The snippet above does the following:

  • Imports the required dependencies
  • Lines 14-16: Create the contacts, _isLoading, and _isError properties to manage the application state
  • Lines 19-41: Create a getContacts method to get the list of available contacts on the database using the PhoneService().getPhoneContacts and set states accordingly

Lastly, we need to modify the UI to use the states and method created to get the contacts list.



    //imports goes here

    class Home extends StatefulWidget {
      //code goes here
    }

    class _HomeState extends State<Home> {
      //state goes here

      @override
      void initState() {
       /code goes here
      }

      getContacts() {
        //code goes here
      }

      @override
      Widget build(BuildContext context) {
        return _isLoading
            ? const Center(
                child: CircularProgressIndicator(
                color: Colors.blue,
              ))
            : _isError
                ? const Center(
                    child: Text(
                      'Error getting phone contacts',
                      style: TextStyle(
                        color: Colors.red,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  )
                : Scaffold(
                    appBar: AppBar(
                      title: const Text('Phonebook'),
                      backgroundColor: Colors.black,
                    ),
                    body: ListView.builder(
                      itemCount: contacts.length,
                      itemBuilder: (context, index) {
                        return InkWell(
                          onTap: () {
                            Navigator.push(
                              context,
                              MaterialPageRoute(
                                builder: (context) =>
                                    Detail(id: contacts[index].id!),
                              ),
                            );
                          },
                          child: Container(
                            decoration: const BoxDecoration(
                              border: Border(
                                bottom: BorderSide(width: .5, color: Colors.grey),
                              ),
                            ),
                            padding: EdgeInsets.fromLTRB(10, 20, 10, 20),
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                              children: [
                                Expanded(
                                  flex: 7,
                                  child: Column(
                                    crossAxisAlignment: CrossAxisAlignment.start,
                                    children: [
                                      Text(
                                        contacts[index].fullname,
                                        style: TextStyle(
                                            color: Colors.black,
                                            fontWeight: FontWeight.w800),
                                      ),
                                      SizedBox(height: 10.0),
                                      Text(contacts[index].phonenumber.toString())
                                    ],
                                  ),
                                ),
                                Column(
                                  crossAxisAlignment: CrossAxisAlignment.end,
                                  children: [
                                    SizedBox(height: 10.0),
                                    Icon(Icons.arrow_forward_ios_rounded)
                                  ],
                                ),
                              ],
                            ),
                          ),
                        );
                      },
                    ),
                    floatingActionButton: FloatingActionButton(
                      onPressed: () {
                        Navigator.push(
                          context,
                          MaterialPageRoute(
                            builder: (context) => const Create(),
                          ),
                        );
                      },
                      backgroundColor: Colors.black,
                      tooltip: 'Create contact',
                      child: const Icon(Icons.add),
                    ),
                  );
      }
    }


Enter fullscreen mode Exit fullscreen mode

Create contacts

To create a contact, we need to modify the create.dart file in the screen directory and update it by doing the following:

First, we need to import the required dependency and create a method to save the contact to the database:



    import 'package:flutter/material.dart';
    import 'package:flutter_mongo/phone_service.dart'; //ADD THIS
    import 'package:flutter_mongo/screens/home.dart';

    class Create extends StatefulWidget {
      const Create({
        Key? key,
      }) : super(key: key);
      @override
      State<Create> createState() => _CreateState();
    }

    class _CreateState extends State<Create> {
      final _formKey = GlobalKey<FormState>();
      final TextEditingController _fullname = TextEditingController();
      final TextEditingController _phonenumber = TextEditingController();
      bool _isLoading = false;

      createContact() {
        setState(() {
          _isLoading = true;
        });
        PhoneService()
            .createPhoneContact(_fullname.text, int.parse(_phonenumber.text))
            .then((value) {
          setState(() {
            _isLoading = false;
          });
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Contact created successfully!')),
          );
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => const Home()),
          );
        }).catchError((onError) {
          setState(() {
            _isLoading = false;
          });
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Error creating contact!')),
          );
        });
      }

      @override
      Widget build(BuildContext context) {
        //UI CODE GOES HERE
      }
    }


Enter fullscreen mode Exit fullscreen mode

The snippet above does the following:

  • Import the required dependency
  • Lines 15-17: Create the _fullname, _phonenumber, and _isLoading properties to manage the application state
  • Lines 17-38: Create a createContact method to save the contact using the PhoneService().createPhoneContact service, set states accordingly

Lastly, we need to modify the UI to use the method and states created to process the form.



    //import goes here

    class Create extends StatefulWidget {
      //code goes here
    }

    class _CreateState extends State<Create> {
      //state goes here

      createContact() {
        //code goes here
      }

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("Create contact"),
            backgroundColor: Colors.black,
          ),
          body: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 30.0),
            child: Form(
              key: _formKey,
              child: Column(
                children: [
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          const Text(
                            'Fullname',
                            style: TextStyle(
                              color: Colors.grey,
                              fontSize: 14.0,
                            ),
                          ),
                          const SizedBox(height: 5.0),
                          TextFormField(
                            controller: _fullname,
                            validator: (value) {
                              if (value == null || value.isEmpty) {
                                return 'Please input your fullname';
                              }
                              return null;
                            },
                            decoration: InputDecoration(
                              contentPadding: const EdgeInsets.symmetric(
                                  vertical: 10, horizontal: 20),
                              hintText: "input name",
                              fillColor: Colors.white,
                              focusedBorder: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(10),
                                borderSide: const BorderSide(color: Colors.grey),
                              ),
                              enabledBorder: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(10),
                                borderSide: const BorderSide(color: Colors.grey),
                              ),
                              errorBorder: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(10),
                                borderSide: const BorderSide(color: Colors.red),
                              ),
                            ),
                            keyboardType: TextInputType.text,
                            maxLines: null,
                          ),
                          const SizedBox(height: 30.0),
                          const Text(
                            'Phone number',
                            style: TextStyle(
                              color: Colors.grey,
                              fontSize: 14.0,
                            ),
                          ),
                          const SizedBox(height: 5.0),
                          TextFormField(
                            controller: _phonenumber,
                            validator: (value) {
                              if (value == null || value.isEmpty) {
                                return 'Please input your phone number';
                              }
                              return null;
                            },
                            decoration: InputDecoration(
                              contentPadding: const EdgeInsets.symmetric(
                                  vertical: 10, horizontal: 20),
                              hintText: "input phone number",
                              fillColor: Colors.white,
                              focusedBorder: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(10),
                                borderSide: const BorderSide(color: Colors.grey),
                              ),
                              enabledBorder: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(10),
                                borderSide: const BorderSide(color: Colors.grey),
                              ),
                              errorBorder: OutlineInputBorder(
                                borderRadius: BorderRadius.circular(10),
                                borderSide: const BorderSide(color: Colors.red),
                              ),
                            ),
                            keyboardType: TextInputType.number,
                          ),
                        ],
                      ),
                    ],
                  ),
                  const SizedBox(height: 30.0),
                  SizedBox(
                    height: 45,
                    width: double.infinity,
                    child: TextButton(
                      onPressed: _isLoading
                          ? null
                          : () {
                              if (_formKey.currentState!.validate()) {
                                createContact();
                              }
                            },
                      style: ButtonStyle(
                        backgroundColor:
                            MaterialStateProperty.all<Color>(Colors.black),
                      ),
                      child: const Text(
                        'Create contact',
                        style: TextStyle(
                          color: Colors.white,
                          fontWeight: FontWeight.bold,
                          fontSize: 14.0,
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }


Enter fullscreen mode Exit fullscreen mode

Get a contact, edit a contact and delete contacts

To perform the stated operations in our application, we need to modify the detail.dart file in the screens directory and update it by doing the following:

First, we need to import the required dependencies and create methods to get, edit, and delete contacts.



    import 'package:flutter/material.dart';
    import 'package:flutter_mongo/phone_service.dart';
    import 'package:flutter_mongo/screens/home.dart';
    import 'package:flutter_mongo/utils.dart';

    class Detail extends StatefulWidget {
      const Detail({Key? key, required this.id}) : super(key: key);
      final String id;
      @override
      State<Detail> createState() => _DetailState();
    }

    class _DetailState extends State<Detail> {
      final _formKey = GlobalKey<FormState>();
      final TextEditingController _fullname = TextEditingController();
      final TextEditingController _phonenumber = TextEditingController();
      late PhoneBook contact;
      bool _isLoading = false;
      bool _isSubmitting = false;
      bool _isError = false;

      @override
      void initState() {
        getContacts();
        super.initState();
      }

      getContacts() {
        setState(() {
          _isLoading = true;
        });
        PhoneService().getSinglePhoneContact(widget.id).then((value) {
          setState(() {
            contact = value;
            _isLoading = false;
          });
          _fullname.text = value.fullname;
          _phonenumber.text = value.phonenumber.toString();
        }).catchError((onError) {
          setState(() {
            _isLoading = false;
            _isError = true;
          });
        });
      }

      updateContact(String fullname, int phonenumber) {
        setState(() {
          _isSubmitting = true;
        });
        PhoneService()
            .updatePhoneContact(widget.id, fullname, phonenumber)
            .then((value) {
          setState(() {
            _isSubmitting = false;
          });
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Contact updated successfully!')),
          );
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => const Home()),
          );
        }).catchError((onError) {
          setState(() {
            _isSubmitting = false;
            _isError = true;
          });
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Error updating contact!')),
          );
        });
      }

      deleteContact() {
        setState(() {
          _isSubmitting = true;
        });
        PhoneService().deletePhoneContact(widget.id).then((value) {
          setState(() {
            _isSubmitting = false;
          });
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Contact deleted successfully!')),
          );
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => const Home()),
          );
        }).catchError((onError) {
          setState(() {
            _isSubmitting = false;
            _isError = true;
          });
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Error deleting contact!')),
          );
        });
      }

      @override
      Widget build(BuildContext context) {
        //UI GOES HERE
      }
    }


Enter fullscreen mode Exit fullscreen mode

The snippet above does the following:

  • Import the required dependencies
  • Lines 15-20: Create the _fullname, _phonenumber, contact, _isLoading, _isSubmitting, and _isError properties to manage the application state
  • Lines 17-38: Create the getSingleContact, updateContact, and deleteContact methods to get details of the selected contact, update it and delete it using the PhoneService().getSinglePhoneContact, PhoneService().updatePhoneContact, and PhoneService().deletePhoneContact service respectively, set states accordingly

Lastly, we need to modify the UI to use the methods and states created to process the operations.



    //import goes here

    class Detail extends StatefulWidget {
     //code goes here
    }

    class _DetailState extends State<Detail> {
      //states goes here

      @override
      void initState() {
        //code goes here
      }

      getSingleContact() {
        //code goes here
      }

      updateContact(String fullname, int phonenumber) {
        //code goes here
      }

      deleteContact() {
        //code goes here
      }

      @override
      Widget build(BuildContext context) {
        return _isLoading
            ? const Center(
                child: CircularProgressIndicator(
                color: Colors.blue,
              ))
            : _isError
                ? const Center(
                    child: Text(
                      'Error getting phone contacts',
                      style: TextStyle(
                        color: Colors.red,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  )
                : Scaffold(
                    appBar: AppBar(
                      title: const Text("Details"),
                      backgroundColor: Colors.black,
                    ),
                    body: Padding(
                      padding: const EdgeInsets.symmetric(
                          horizontal: 16.0, vertical: 30.0),
                      child: Form(
                        key: _formKey,
                        child: Column(
                          children: [
                            Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    const Text(
                                      'Fullname',
                                      style: TextStyle(
                                        color: Colors.grey,
                                        fontSize: 14.0,
                                      ),
                                    ),
                                    const SizedBox(height: 5.0),
                                    TextFormField(
                                      controller: _fullname,
                                      validator: (value) {
                                        if (value == null || value.isEmpty) {
                                          return 'Please input your fullname';
                                        }
                                        return null;
                                      },
                                      decoration: InputDecoration(
                                        contentPadding: const EdgeInsets.symmetric(
                                            vertical: 10, horizontal: 20),
                                        hintText: "input name",
                                        fillColor: Colors.white,
                                        focusedBorder: OutlineInputBorder(
                                          borderRadius: BorderRadius.circular(10),
                                          borderSide:
                                              const BorderSide(color: Colors.grey),
                                        ),
                                        enabledBorder: OutlineInputBorder(
                                          borderRadius: BorderRadius.circular(10),
                                          borderSide:
                                              const BorderSide(color: Colors.grey),
                                        ),
                                        errorBorder: OutlineInputBorder(
                                          borderRadius: BorderRadius.circular(10),
                                          borderSide:
                                              const BorderSide(color: Colors.red),
                                        ),
                                      ),
                                      keyboardType: TextInputType.text,
                                      maxLines: null,
                                    ),
                                    const SizedBox(height: 30.0),
                                    const Text(
                                      'Phone number',
                                      style: TextStyle(
                                        color: Colors.grey,
                                        fontSize: 14.0,
                                      ),
                                    ),
                                    const SizedBox(height: 5.0),
                                    TextFormField(
                                      controller: _phonenumber,
                                      validator: (value) {
                                        if (value == null || value.isEmpty) {
                                          return 'Please input your phone number';
                                        }
                                        return null;
                                      },
                                      decoration: InputDecoration(
                                        contentPadding: const EdgeInsets.symmetric(
                                            vertical: 10, horizontal: 20),
                                        hintText: "input phone number",
                                        fillColor: Colors.white,
                                        focusedBorder: OutlineInputBorder(
                                          borderRadius: BorderRadius.circular(10),
                                          borderSide:
                                              const BorderSide(color: Colors.grey),
                                        ),
                                        enabledBorder: OutlineInputBorder(
                                          borderRadius: BorderRadius.circular(10),
                                          borderSide:
                                              const BorderSide(color: Colors.grey),
                                        ),
                                        errorBorder: OutlineInputBorder(
                                          borderRadius: BorderRadius.circular(10),
                                          borderSide:
                                              const BorderSide(color: Colors.red),
                                        ),
                                      ),
                                      keyboardType: TextInputType.number,
                                    ),
                                  ],
                                ),
                              ],
                            ),
                            const SizedBox(height: 30.0),
                            SizedBox(
                              height: 45,
                              width: double.infinity,
                              child: TextButton(
                                onPressed: _isSubmitting
                                    ? null
                                    : () {
                                        if (_formKey.currentState!.validate()) {
                                          updateContact(
                                            _fullname.text,
                                            int.parse(_phonenumber.text),
                                          );
                                        }
                                      },
                                style: ButtonStyle(
                                  backgroundColor: MaterialStateProperty.all<Color>(
                                      Colors.black),
                                ),
                                child: const Text(
                                  'Update contact',
                                  style: TextStyle(
                                    color: Colors.white,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 14.0,
                                  ),
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                    floatingActionButton: FloatingActionButton(
                      onPressed: _isSubmitting
                          ? null
                          : () {
                              deleteContact();
                            },
                      backgroundColor: Colors.red,
                      tooltip: 'Delete',
                      child: const Icon(Icons.delete),
                    ),
                  );
      }
    }


Enter fullscreen mode Exit fullscreen mode

With that done, we restart the application using the code editor or run the command below:



    flutter run


Enter fullscreen mode Exit fullscreen mode

Conclusion

This post discussed how to build a fullstack mobile application using MongoDB Data API and Flutter. With the Data API, organizations can quickly create secure and scalable services that can be used across platforms.

These resources may also be helpful:

Top comments (1)

Collapse
 
kannan_raja_7a83bc82acc98 profile image
Kannan Raja

DioException (DioException [bad response]: This exception was thrown because the response has a status code of 401 and RequestOptions.validateStatus was configured to throw for this status code.