Flutter: How to do CRUD with PostgreSQL? Part 2

I am going to share today some exciting topics such as :

From the previous post, I have shared how to setup your web server to implement RESTful api using Aqueduct with Postgresql. In this post, we are going to start building our flutter app to interact with our web application.

How to set up Flutter project

Create a new Flutter project call flutter_crud_demo. If you are using Visual Studio Code, you can create new project by View > Command Pallete > Flutter New Project > Enter project name > Select directory to save your project. When the workspace is done initialising, delete the widget_test.dart and empty the content of the main.dart.

Read function

Future Builder

Future builder allows us to render a list view as soon as we get our list of data asynchronously. Future builder has 2 parameters, one is the future which is the future method we use to retrieve the list of data and the other is builder which is what do we want to build with the data. Using future builder allows us to show to user a CircularProgressIndicator before data is ready and shows ListView when fetching is done. In our scaffold body, replace with the following code.

body: new Container(
  child: new FutureBuilder<List<Hero>>(
    future: getAll(),
    builder: (context, snapshot) {

if (snapshot.hasData) {
return new ListView.builder(
          itemCount: snapshot.data.length,
          itemBuilder: (context, index) {
return new Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
new Text(snapshot.data[index].name,
                  style: new TextStyle(fontWeight: FontWeight.bold)),
new Divider()
              ]
            );
          }
        );
      } else if (snapshot.hasError) {
return new Text("${snapshot.error}");
      }

      // By default, show a loading spinner
return new CircularProgressIndicator();
    },
  ),
),

Next we need to implement getAll()method to retrieve list of heroes from our web server. Our method returns a Futureof type list of hero. Inside the function, we call and awaithttp.get(_heroesUrl) . Await allows us to wait for a response before proceeding to the next line. The function getAll() needs to be marked with async to be able to use await inside the method. From the response, we retrieve the body message and convert into our

Future<List<Hero>> getAll() async {
final response = await http.get(_heroesUrl);
  print(response.body);
  List responseJson = json.decode(response.body.toString());
  List<Hero> userList = createHeroesList(responseJson);
return userList;
}

We need to import some libraries for some helper functions.

import 'dart:convert';
import 'dart:async';
import 'package:http/http.dart' as http;

Let’s create a class call Hero. This class takes in an integer for id and string as name.

class Hero {
  Hero({this.id, this.name});
final int id;
  String name;
}

Inside class _MyHomePageState, add static const _heroesUrl to contain our localhost url.

static const _heroesUrl = 'http://localhost:8888/heroes';

Let’s run the Flutter app. Also do remember to start your web server application with aqueduct serve command.

We can get list of heroes in our Flutter app

Delete function

From here onwards, we are going to introduce an enum to store the status of any http request. Any http request should return type HttpRequestStatus.

enum HttpRequestStatus {
  NOT_DONE,
  DONE,
  ERROR
}

Dismissible

We are going to implement swipe to delete which is a very common pattern found in mobile apps. To do this, we going to swap Column with Dismissible as shown below. We then request to delete a hero by its id at the onDismissed parameter. The method deleteHero returns a future which is the httpRequestStatus . If the status is done, we will ask to redraw the screen using setState().

return new ListView.builder(
    itemCount: snapshot.data.length,
    itemBuilder: (context, index) {
var item = snapshot.data[index];

return Dismissible(
        key: Key(item.id.toString()),
        onDismissed: (direction) async {
          httpRequestStatus = await deleteHero(item.id);
if (httpRequestStatus == HttpRequestStatus.DONE) {
            setState(() {
              snapshot.data.removeAt(index);
            });
          }
        },
        background: Container(color: Colors.red),
        child: ListTile(title: Text('${item.name}')),
      );
    });

The method deleteHero is as follows

Future deleteHero(int id) async {
  httpRequestStatus = HttpRequestStatus.NOT_DONE;
final url = '$_heroesUrl/$id';
final response = await http.delete(url, headers: _headers);
if (response.statusCode == 200) {
    print(response.body.toString());
    httpRequestStatus = HttpRequestStatus.DONE;
  } else {
    httpRequestStatus = HttpRequestStatus.ERROR;
  }

return httpRequestStatus;
}
Swipe to delete hero

Add function

Let’s add a widget icon under the AppBar to allow user to add hero.

appBar: new AppBar(
  title: new Text('Flutter CRUD Demo'),
  actions: <Widget>[
    IconButton(
      icon: Icon(Icons.add),
      onPressed: _addHeroService,
      tooltip: 'Add New Hero',
    )
  ],
),

In the _addHeroService , we call _openDialogAddHero to push a new screen for user input on hero name. This method returns a new hero name which we will then call createHero with it and if hero name is successfully updated, we will call setState() to redraw the screen.

void _addHeroService() async {
  String name = await _openDialogAddHero();
  HttpRequestStatus httpRequestStatus = await createHero(name);
if (httpRequestStatus == HttpRequestStatus.DONE) {
    setState(() {

    });
  }
}

Let’s add a static const _headers to store content-type of http header.

static final _headers = {'Content-Type': 'application/json'};

The following is the code to send a create new hero request to web server application.

Future createHero(String name) async {
  httpRequestStatus = HttpRequestStatus.NOT_DONE;
final response = await http.post(_heroesUrl,
      headers: _headers, body: json.encode({'name': name}));
if (response.statusCode == 200) {
    print(response.body.toString());
    httpRequestStatus = HttpRequestStatus.DONE;
  } else {
    httpRequestStatus = HttpRequestStatus.ERROR;
  }

return httpRequestStatus;
}
We can add new hero now

Update function

Finally we are left with one last function which is the ability to update hero name. We want user to tap on existing hero to update the name. For this, we add an onTap inside ListTile which calls method _updateHeroService , passing in id and name of the hero at that index of the list. Similar to the _addHeroService which retrieves name from the pop up dialog and pass into updateHero . The screen is then redrawn if the updateHero is successful.

Future _updateHeroService(int id, String name) async {
  String updatedName = await _openDialogUpdateHero(id, name);
  HttpRequestStatus httpRequestStatus = await updateHero(id, updatedName);
if (httpRequestStatus == HttpRequestStatus.DONE) {
    print(httpRequestStatus.toString());
    setState(() {

    });
  }
}

The following is the code for updateHero

Future updateHero(int id, String name) async {
  httpRequestStatus = HttpRequestStatus.NOT_DONE;
final url = '$_heroesUrl/$id';
final response = await http.put(url,
      headers: _headers, body: json.encode({'id': id, 'name': name}));
if (response.statusCode == 200) {
    print(response.body.toString());
    httpRequestStatus = HttpRequestStatus.DONE;
  } else {
    httpRequestStatus = HttpRequestStatus.ERROR;
  }
}
Let’s swap Hawkeye with Thor

As a recap, we have covered how to build our web server application implementing RESTful api and managed to build a Flutter app to perform basic CRUD functions with PostgreSQL.

Github

https://github.com/tattwei46/flutter_crud_postgresql

If you find this article helpful and educational, do give it some 👏👏👏to encourage me to write more of this in future 🙏


The Flutter Pub is a medium publication to bring you the latest and amazing resources such as articles, videos, codes, podcasts etc. about this great technology to teach you how to build beautiful apps with it. You can find us on Facebook, Twitter, and Medium or learn more about us here. We’d love to connect! And if you are a writer interested in writing for us, then you can do so through these guidelines.

About the author

Founder of tattweicheah.com. Loves music, sport and most importantly software development.

Leave a Reply

Your email address will not be published. Required fields are marked *