How to Build a Simple CRUD Application Using Flutter & Strapi
Tags: flutter, strapi, app
Published: 2021-12-08 13:54:27

In this tutorial, we will learn how to build a Create, Retrieve, Update and Delete (CRUD) application using Flutter and Strapi. We will call End-points provided to us by Strapi using the HTTP package in our app. We will build screens where different operations will take place like adding/creating a new user, Retrieve User data, Update user data and Delete data.

## Prerequisite 

To follow this tutorial, you need:
- NPM
- Node.js
- Flutter SDK

## What is Headless CMS

Headless CMS is the only content repository that serves as a back-end for your front-end applications. It is built to allow content to be accessed via RESTFUL API or GraphQL API i.e it provides your content as data over an API.

The term **Head** refers to where you deliver your content either through a mobile application or a web application. The term “headless” refers to the concept of removing the head from the body, which is usually the front end of a website. This does not mean that having ahead is not important, it just means that you get the flexibility to choose what platform or head you send your content to.

## Why Strapi

Strapi is a JavaScript framework that simplifies the creation of REST APIs. It allows developers to create content types and their relationships between them. It also has a media library that will allow you to host audio and video assets.

## Overview

Building a full-stack application usually requires the use of both the front-end and back-end components. These components are often interrelated and are required to complete the project.
You can manage and create your API without the help of any backend developer.
Strapi is a headless CMS that's built on top of Node.js. This is a great alternative to traditional CMSes that are already in use. 


## Setup Flutter Project

In our terminal, we will create our flutter project
```
    flutter create strapi_backend
    cd strapi_backend
```
In our flutter app, we will create two folders and six files inside our lib folder just like our files structure  below.

**File Structure**   


    ├─ android                                                                            
    │  ├─ app                                                                             
    │  │  ├─ src                                                                           ├─ build                                                                             
    │  ├─ app                                                                             ├─ ios                                                                                 ├─ lib                                                                                
    │  ├─ customisation                                                                   
    │  │  └─ textfield.dart                                                               
    │  ├─ view                                                                            
    │  │  ├─ add_user.dart                                                                 │  │  ├─ editUser.dart                                                                
    │  │  ├─ show_users.dart                                                              
    │  │  ├─ user.dart                                                                    
    │  │  └─ userDetail.dart                                                              
    │  └─ main.dart                                                                       
    ├─ README.md                                                                          
    ├─ pubspec.lock                                                                       
    ├─ pubspec.yaml                                                                       
    └─ strapi_backend.iml                                                                       


**Add Http library to fetch APIs**

We will be needing the HTTP package from [pub. dev](https://pub.dev/) to make requests to strapi
you can run the command below to add the package to your `pubspec.yaml` and download all dependencies we will need in our app.

```
    flutter pub add http
    flutter pub get
```

![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635875032067_http-package.png)

## Setting Up Strapi

We will change the directory in our terminal to create a folder for Strapi using the following command
```
    cd ../
    npx create-strapi-app backend
```
At some point, we will be prompted to choose the installation type.
```
    ? Choose your installation type (Use arrow keys)
    ❯ Quickstart (recommended) 
      Custom (manual settings) 
```

Please choose Quickstart as it is recommended.

After hitting enter, we will be prompted to choose a template, in my case, I did not.

After the prompts, your strapi project gets built and a server starts automatically.

Once the server starts, we will be redirected to a web page where we will access our admin panel at `http://localhost:1337/admin`.
Fill out the fields to create credentials for a root admin user or a super admin and which accept the terms and click on `LET' S START` to take us to our dashboard.

![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635896381976_dashboard.png)

## Create Strapi Collection Types

Let’s create data collection for our mobile application via our dashboard.
Just to the left of our dashboard are options to help us create content for our mobile application and we will be using the `Content-Type Builder` under **Plugin.** We will be creating a simple CRUD app to create, retrieve, update and delete data, let’s dive right in! 

First, under our Collection type, click on **Create new collection type** to create a new collection. 

![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635898021734_createNewcollection.png)



When we click on the `Create new collection type` a modal opens up requesting for a display name for the new collection type. We can simply name it `App`. Click on continue so we can create the fields needed for our application.


![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635898510699_addFields.png)

## Add Fields

The fields we will be needing will just be three text fields

- name
- email
- password

The name text field will just hold the name of the user, while the email text field will hold the user's email address and the password will hold the possible password of the user.

![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635898825395_addNametextfield.png)


Give the name “name” to the Text field. To add more fields, click `Add another field` to add fields for email and password.
All we want is to create a user who will store the data so we can easily retrieve and make updates to the data

![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635899274916_appFileds.png)


After creating the fields, click on finish and hit the `Save` button at the top of the fields.

**NOTE:** After hitting the Save button and toast appears to show that an error has occurred, you can simply reload the page and your data will be saved.


## Adding Roles and Permissions

Next up, we will return to the sidebar of our dashboard, under the group title “general”, click on `Settings`. Here, we will be adding permissions for the users on what operations they can perform and these permissions will also allow us to easily access our API.

Right after the sidebar, there is another sidebar, click on `Roles` under `Users & Permission` Plugin 

![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635900084491_addRoles.png)


Under **Roles,** click on the icon at the extreme of **Public** to add permissions for the users.


![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635900441410_selectAll.png)


We will give permissions to the user to perform CRUD operations, so you can go ahead and check the Select all checkbox and hit the save button at the top right of the page.



## Build Screens

Recall that we have created our flutter project, so all we need to do is open the flutter project folder in our code Editor. I am using VS code.
Let’s build our first screen

For our `main. dart` file. The `main. dart` file in flutter is where the app is being bootstrapped from. Main. dart is the entry point of our flutter app.
 copy the code below 

```
    import 'package:flutter/material.dart';
    import 'package:strapi_backend/view/add_user.dart';
    void main() {
      runApp(Strapi());
    }
    class Strapi extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home:CreateUser()
        );
      }
    }
```

**Create User screen**

The screen will have a text field where users will enter their details to save to the entry point on our local strapi server.
All users will have a specific ID once saved. The screen will be performing a `POST` request to store user details on our backend. The screen will take in the Name, Email, and Password using TextFields and its controllers to post the user details to strapi.


![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635912173571_createUser.png)


 Copy-paste the code below into your `add_user.dart` file
 
```
    import 'package:flutter/material.dart';
    import 'package:strapi_backend/customisation/textfield.dart';
    import 'package:strapi_backend/view/show_users.dart';
    import 'package:http/http.dart' as http;
    import 'package:strapi_backend/view/user.dart';
    class CreateUser extends StatefulWidget {
      final int id;
      const CreateUser({ Key key,this.id });
      @override
      _CreateUserState createState() => _CreateUserState();
    }
     TextEditingController emailController = TextEditingController(text: users.email);
      TextEditingController passwordController = TextEditingController(text: users.password);
      TextEditingController nameController = TextEditingController(text: users.name);
      Users users = Users(0, '', '', '');
    class _CreateUserState extends State<CreateUser> {
      Future save() async {
         await http.post(Uri.parse("http://10.0.2.2:1337/apis/",),headers:<String, String> {
          'Context-Type': 'application/json; charset=UTF-8',
        },body: <String,String> {  'name':users.name,
          'email': users.email,
          'password': users.password,}
        );
        Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (BuildContext context) => DisplayUsers()), (Route<dynamic> route) => false);
          }
      
       
      @override
      Widget build(BuildContext context) {
        //  print(widget.id);
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.indigo[700],
            elevation: 0.0,
            title: Text('Create User'),
          ),
          body: SingleChildScrollView(
            child: Padding(
              padding:  EdgeInsets.only(top: 100,bottom: 100,left: 18,right: 18),
              child: Container(
    .            height: 550,
                width: 400,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(4),
                   color: Colors.indigo[700],
                ),
               
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                   Container(
                     width: 300,
                     decoration: BoxDecoration(boxShadow: [
                            ]),
                     child: Textfield(
                       controller:nameController ,
                       onChanged: (val){
                         users.name = val;
                       },
                       hintText: 'Name',
                     )
                     ),
                     SizedBox(height: 10,),
                     Container(
                         width: 300,
                     decoration: BoxDecoration(boxShadow: [
                            ]),
                     child: Textfield(
                       controller: emailController,
                       onChanged: (val){
                         users.email = val;
                       },
                       hintText: 'Email',
                     )
                     ),
                       Container(
                         width: 300,
                     decoration: BoxDecoration(boxShadow: [
                            ]),
                     child: Textfield(
                       hintText: 'Password',
                       onChanged: (val){
                         users.password = val;
                       },
                       controller: passwordController,
                     )
                     ),
                     SizedBox(
                       width: 100,
                       child: TextButton(
                         style: TextButton.styleFrom(backgroundColor: Colors.white),
                         onPressed:save, child: Text('Save')),
                     )
                  ],
                ),
              ),
            ),
          ),
        );
        
      }
      
    }
```

The code above has an asynchronous save function that returns a future response. Note that we have a link where we are posting our details to `"http://10.0.2.2:1337/apis/``"` this link is what we will be using to make every possible request around our app but our localhost runs on `"http://localhost:1337/apis/"`, so why do we use `"http://10.0.2.2:1337/apis/"` is because we are running our flutter app on an emulator. 

The HTTP requests made to this page are sent to the `local host` address. The reason why we don't use the local host is that the HTTP request will be forwarded to the destination port of the requested website.

Since our local host runs on `localhost:1337` the emulator will make  an HTTP request to `10.0.2.2:1337`.

```
     Users users = Users(0, '', '', '');
    class _CreateUserState extends State<CreateUser> {
      Future save() async {
        // var jsonResponse = null;
         await http.post(Uri.parse("http://10.0.2.2:1337/apis/",),headers:<String, String> {
          'Context-Type': 'application/json; charset=UTF-8',
        },body: <String,String> {  'name':users.name,
          'email': users.email,
          'password': users.password,}
        );
        Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (BuildContext context) => DisplayUsers()), (Route<dynamic> route) => false);
          }
```

We will create a separate Users class file where we will list all possible data that will be posted to our backend. The Users class will help us have good control over how our data will be passed around in our application. The Users class will have the following variables: id, name, email, password and we will pass them on as constructors so we can access it when we use an instance of the Users class.

The function in the code above shows a simple `POST` request that has all the necessary data in the body and after the function is called and executed, we navigate to another screen where added users will display.

**Display User screen**
This screen will only retrieve the data posted from the Create users screen.
This screen will be performing a `GET` request to display as a list tile. Below is the code for the display screen

![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635915197571_displayUsers.png)

```
    import 'dart:convert';
    import 'package:flutter/material.dart';
    import 'package:http/http.dart' as http;
    import 'package:strapi_backend/view/user.dart';
    import 'package:strapi_backend/view/userDetail.dart';
    class DisplayUsers extends StatefulWidget {
      const DisplayUsers({Key key}) : super(key: key);
      @override
      _DisplayUsersState createState() => _DisplayUsersState();
    }
    class _DisplayUsersState extends State<DisplayUsers> {
      List<Users> user = [];
      Future<List<Users>> getAll() async {
        var response = await http.get(Uri.parse("http://10.0.2.2:1337/apis/"));
      
        if(response.statusCode==200){
          user.clear();
        }
        var decodedData = jsonDecode(response.body);
        for (var u in decodedData) {
          user.add(Users(u['id'], u['name'], u['email'], u['password']));
        }
        return user;
      }
      @override
      Widget build(BuildContext context) {
        getAll();
        return Scaffold(
            appBar: AppBar(
              title: Text('Display Users'),
              elevation: 0.0,
              backgroundColor: Colors.indigo[700],
            ),
            body: FutureBuilder(
                future: getAll(),
                builder: (context, AsyncSnapshot<List<Users>> snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return Center(
                      child: CircularProgressIndicator(),
                    );
                  }
                    return ListView.builder(
                      itemCount: snapshot.data.length,
                      itemBuilder: (BuildContext context, index) => 
                      InkWell(
                        child: ListTile(
                          title: Text(snapshot.data[index].name),
                          subtitle: Text(snapshot.data[index].email),
                          onTap: (){
                            Navigator.push(context, MaterialPageRoute(builder: (_)=>MyDetails(users: snapshot.data[index],)));
                          },
                        ),
                      )
                    );
                  }
                ));
      }
    }
```  

Let’s break the code above into segments to understand what is happening

```
    List<Users> user = [];
      Future<List<Users>> getAll() async {
        var response = await http.get(Uri.parse("http://10.0.2.2:1337/apis/"));
      
        if(response.statusCode==200){
          user.clear();
        }
        var decodedData = jsonDecode(response.body);
        for (var u in decodedData) {
          user.add(Users(u['id'], u['name'], u['email'], u['password']));
        }
        return user;
      }
```

In the code above, we created a list with the name `user`, with the type of Users. The function after the list performs a GET request that fetches data from our backend to display on our frontend and inside the function has a simple check statement that clears the list before adding a user, so we do not have multiple users displaying twice after decoding the response and looping through it.


    FutureBuilder(
                future: getAll(),
                builder: (context, AsyncSnapshot<List<Users>> snapshot) {
                  if (snapshot.connectionState == ConnectionState.waiting) {
                    return Center(
                      child: CircularProgressIndicator(),
                    );
                  }
                    return ListView.builder(
                      itemCount: snapshot.data.length,
                      itemBuilder: (BuildContext context, index) => 
                      InkWell(
                        child: ListTile(
                          title: Text(snapshot.data[index].name),
                          subtitle: Text(snapshot.data[index].email),
                          onTap: (){
                            Navigator.push(context, MaterialPageRoute(builder: (_)=>MyDetails(users: snapshot.data[index],)));
                          },
                        ),
                      )
                    );
                  }
                ));

Future builder is a widget that displays and builds widgets based on the latest snapshot of interaction with a future like the function above. We made a check to return the progress indicator if there is no data available or if it is fetching the data. We built a `ListView.builder` widget  based on snapshots of data from Future Builder.
We also made the ListTile widget clickable so it takes us to a new screen where all the details of a particular user are displayed and we also passed the snapshot to the next screen so we can use the data there instead of making new requests all over again.

```
      onTap: (){
    Navigator.push(context, MaterialPageRoute(builder: (_)=>MyDetails(users: snapshot.data[index],)));
    }
```

**Create My Details Screen**
 
 This screen displays all the data of a particular user, his/her ID, password, email, and and name.
 This screen also has two TextButton widgets positioned below the container that displays the user details. These buttons are the `EDIT` and `DELETE` buttons.
  
```
    import 'package:flutter/material.dart';
    import 'package:strapi_backend/view/editUser.dart';
    import 'package:strapi_backend/view/show_users.dart';
    import 'package:strapi_backend/view/user.dart';
    import 'package:http/http.dart' as http;
    class MyDetails extends StatefulWidget {
     final  Users users;
      const MyDetails({this.users }) ;
      @override
      _MyDetailsState createState() => _MyDetailsState();
    }
     
    class _MyDetailsState extends State<MyDetails> {
      @override
      Widget build(BuildContext context) {
        void deleteUser()async{
          await http.delete(Uri.parse("http://10.0.2.2:1337/apis/${widget.users.id}"));
           Navigator.of(context).pushAndRemoveUntil(
              MaterialPageRoute(builder: (BuildContext context) => DisplayUsers()),
              (Route<dynamic> route) => false);
        }
        return Scaffold(
          appBar: AppBar(
            title: Text('My Details'),
            elevation: 0.0,
            backgroundColor: Colors.indigo[700],
          ),
          body: Center(
            child: Padding(
              padding:  EdgeInsets.symmetric(horizontal: 18,vertical:32),
              child: Column(
                children: [
                  Container(
                    height:50,
                    width: MediaQuery.of(context).size.width,
                    color: Colors.indigo[700],
                    child: Center(child: Text('Details',style: TextStyle(color: Color(0xffFFFFFF)),)),
                  ),
                  Container(
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 18,vertical: 32),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text('${widget.users.id}'),
                          SizedBox(height: 10,),
                          Text(widget.users.name),
                          SizedBox(height: 10,),
                          Text(widget.users.email),
                          SizedBox(height: 10,),
                          Text(widget.users.password),
                          
                        ],
                      ),
                    ),
                    // height: 455 ,
                    width:  MediaQuery.of(context).size.width,
                    decoration: BoxDecoration(
                       color: Color(0xffFFFFFF),
                      boxShadow: [
                        BoxShadow(
                          color: Colors.grey,
                          offset: Offset(0,1),
                        ),
                      ]
                    ),
                    
                  ),
                  Row(
                    children:[
                      TextButton(
                        onPressed: (){
                             Navigator.push(context, MaterialPageRoute(builder: (_)=>EditUser(users: widget.users,)));
                         
                        }, child:Text('Edit'),
                      ),
                      TextButton(
                        onPressed:(){
                          deleteUser();
                        }, child:Text('Delete'),
                      ),
                    ]
                  )
                ],
              ),
            ),
          ),
        );
      }
    }
```


At the top of our class, we created a variable with the type of Users that takes a snapshot data from the previous screen. We displayed this data in a container, see the image below.
Data above the state class of the statefulwidget cannot be accessed and if we have to access it, we have to do a lot of dependency injections passing one particular data over and over again till we get it to a point of access but flutter made it easier by using the keyword `widget`.

![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635917270408_mydetails.png)


Let’s dive into the buttons below the container and their functionalities.
The Edit button when clicked, takes us to a new screen where we can edit the details of a user based on his or her ID. We will create a new dart file called `editUser.dart` 
Copy-paste the code below into that file.

```
    import 'package:flutter/material.dart';
    import 'package:strapi_backend/customisation/textfield.dart';
    import 'package:strapi_backend/view/show_users.dart';
    import 'package:strapi_backend/view/user.dart';
    import 'package:http/http.dart' as http;
    class EditUser extends StatefulWidget {
      final Users users;
      const EditUser({Key key, this.users});
      @override
      _EditUserState createState() => _EditUserState();
    }
    class _EditUserState extends State<EditUser> {
      void editUser(
          {Users users, String email, String password, String name}) async {
        final response = await http.put(
            Uri.parse(
              "http://10.0.2.2:1337/apis/${users.id}",
            ),
            headers: <String, String>{
              'Context-Type': 'application/json;charset=UTF-8',
            },
            body: <String, String>{
              'name': name,
              'email': email,
              'password': password,
            });
        if (response.statusCode == 200) {
          print(response.reasonPhrase);
          Navigator.of(context).pushAndRemoveUntil(
              MaterialPageRoute(builder: (BuildContext context) => DisplayUsers()),
              (Route<dynamic> route) => false);
        } else {
          print(response.statusCode);
          print(response.reasonPhrase);
        }
      }
      @override
      Widget build(BuildContext context) {
        TextEditingController emailController =
            TextEditingController(text: widget.users.email);
        TextEditingController passwordController =
            TextEditingController(text: widget.users.password);
        TextEditingController nameController =
            TextEditingController(text: widget.users.name);
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.indigo[700],
            elevation: 0.0,
            title: Text('Edit User'),
          ),
          body: SingleChildScrollView(
            child: Padding(
              padding: EdgeInsets.only(top: 100, bottom: 100, left: 18, right: 18),
              child: Container(
                height: 550,
                width: 400,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(4),
                  color: Colors.indigo[700],
                ),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Container(
                        width: 300,
                        decoration: BoxDecoration(boxShadow: [
                          
                        ]),
                        child: Textfield(
                          controller: nameController,
                          onChanged: (val) {
                            nameController.text = val;
                          },
                          hintText: 'Name',
                        )),
                    SizedBox(
                      height: 10,
                    ),
                    Container(
                        width: 300,
                        decoration: BoxDecoration(boxShadow: []),
                        child: Textfield(
                          controller: emailController,
                          onChanged: (val) {
                            emailController.text = val;
                          },
                          hintText: 'Email',
                        )),
                    Container(
                        width: 300,
                        decoration: BoxDecoration(boxShadow: []),
                        child: Textfield(
                          hintText: 'Password',
                          onChanged: (val) {
                            passwordController.text = val;
                          },
                          controller: passwordController,
                        )),
                    SizedBox(
                      width: 100,
                      child: TextButton(
                          style:
                              TextButton.styleFrom(backgroundColor: Colors.white),
                          onPressed: () {
                            editUser(
                                users: widget.users,
                                email: emailController.text,
                                password: passwordController.text,
                                name: nameController.text);
                          },
                          child: Text('Save')),
                    )
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
```

**Edit Function**

When the Edit Text Button is clicked, we get to navigate to a new screen where we can edit the details of a particular user, and once saved, the user's detail gets updated.

```
      TextButton(
                        onPressed: (){
                             Navigator.push(context, MaterialPageRoute(builder: (_)=>EditUser(users: widget.users,)));
                         
                        }, child:Text('Edit'),
                      ),
```

![](https://paper-attachments.dropbox.com/s_6D0176A88A37742E7044C32CD8D678646C9062CD1368C35FD8B2416DF5A7212F_1635920268768_editorUser.png)


Every time we click the Edit button, the user's details appear on the Text Field to be edited.
See code below

```
    import 'package:flutter/material.dart';
    import 'package:strapi_backend/customisation/textfield.dart';
    import 'package:strapi_backend/view/show_users.dart';
    import 'package:strapi_backend/view/user.dart';
    import 'package:http/http.dart' as http;
    class EditUser extends StatefulWidget {
      final Users users;
      const EditUser({Key key, this.users});
      @override
      _EditUserState createState() => _EditUserState();
    }
    class _EditUserState extends State<EditUser> {
      void editUser(
          {Users users, String email, String password, String name}) async {
        final response = await http.put(
            Uri.parse(
              "http://10.0.2.2:1337/apis/${users.id}",
            ),
            headers: <String, String>{
              'Context-Type': 'application/json;charset=UTF-8',
            },
            body: <String, String>{
              'name': name,
              'email': email,
              'password': password,
            });
          Navigator.of(context).pushAndRemoveUntil(
              MaterialPageRoute(builder: (BuildContext context) => DisplayUsers()),
              (Route<dynamic> route) => false);
        } 
      }
      @override
      Widget build(BuildContext context) {
        TextEditingController emailController =
            TextEditingController(text: widget.users.email);
        TextEditingController passwordController =
            TextEditingController(text: widget.users.password);
        TextEditingController nameController =
            TextEditingController(text: widget.users.name);
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.indigo[700],
            elevation: 0.0,
            title: Text('Edit User'),
          ),
          body: SingleChildScrollView(
            child: Padding(
              padding: EdgeInsets.only(top: 100, bottom: 100, left: 18, right: 18),
              child: Container(
                height: 550,
                width: 400,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(4),
                  color: Colors.indigo[700],
                ),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    Container(
                        width: 300,
                        decoration: BoxDecoration(boxShadow: [
                          
                        ]),
                        child: Textfield(
                          controller: nameController,
                          onChanged: (val) {
                            nameController.text = val;
                          },
                          hintText: 'Name',
                        )),
                    SizedBox(
                      height: 10,
                    ),
                    Container(
                        width: 300,
                        decoration: BoxDecoration(boxShadow: []),
                        child: Textfield(
                          controller: emailController,
                          onChanged: (val) {
                            emailController.text = val;
                          },
                          hintText: 'Email',
                        )),
                    Container(
                        width: 300,
                        decoration: BoxDecoration(boxShadow: []),
                        child: Textfield(
                          hintText: 'Password',
                          onChanged: (val) {
                            passwordController.text = val;
                          },
                          controller: passwordController,
                        )),
                    SizedBox(
                      width: 100,
                      child: TextButton(
                          style:
                              TextButton.styleFrom(backgroundColor: Colors.white),
                          onPressed: () {
                            editUser(
                                users: widget.users,
                                email: emailController.text,
                                password: passwordController.text,
                                name: nameController.text);
                          },
                          child: Text('Save')),
                    )
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
```

Let’s break the code into segments to understand all the events happening above

```
    void editUser(
          {Users users, String email, String password, String name}) async {
        final response = await http.put(
            Uri.parse(
              "http://10.0.2.2:1337/apis/${users.id}",
            ),
            headers: <String, String>{
              'Context-Type': 'application/json;charset=UTF-8',
            },
            body: <String, String>{
              'name': name,
              'email': email,
              'password': password,
            });
          Navigator.of(context).pushAndRemoveUntil(
              MaterialPageRoute(builder: (BuildContext context) => DisplayUsers()),
              (Route<dynamic> route) => false);
        } 
```

The above function performs a PUT request based on the ID of the user passed and this function has parameters when called in the onPressed function, takes the needed data from the Text field, and afterward Navigates to the Display Users screen.

**Delete Function**

The delete TextButton deletes a particular user based on the ID passed.

```
     void deleteUser()async{
          await http.delete(Uri.parse("http://10.0.2.2:1337/apis/${widget.users.id}"));
           Navigator.of(context).pushAndRemoveUntil(
              MaterialPageRoute(builder: (BuildContext context) => DisplayUsers()),
              (Route<dynamic> route) => false);
        }
```


<iframe width="560" height="315" src="https://www.youtube.com/embed/kWmqa9_oTFc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


## Test App

<iframe width="560" height="315" src="https://www.youtube.com/embed/xu55LvwDgxc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


## Conclusion

Finally, we came to the end of the tutorial. In the tutorial, we learned how to connect strapi with our flutter frontend using RESTFUL API and we used it to fetch data. In the process, we created three fields in strapi to accept data and we created four screens on our frontend using the flutter framework namely: Create user, Display User, My Details, and Edit User.
We also added permissions to allow us to perform CRUD operations.

We had a hands-on tutorial and this has proven how easy it is to use Strapi. Strapi is straight forward and you can choose any client web, mobile app, or Desktops


## Resources

[Github code](https://github.com/Maxiggle/strapi-and-flutter.git)