Working with Rest API’s in Flutter with a Progress bar (Part -1).

Jaspal
7 min readJul 16, 2019

--

Working with rest API’s in flutter.
Rest API’s in a flutter

Do you have knowledge about working with Rest APIs in Flutter?

If not, take some time and have a look below about how the code takes place. Let’s go ahead and learn something new about Flutter and how to get a response from Rest API. By just following the below-mentioned steps respectively.

Step 1: Add the below mentioned packages in your pubspec.yaml project file.

http package for flutter.

I have added two packages in the pubspec.yaml file. First is http: ^0.12.0+2 to consume rest API’s in flutter and the second one is connectivity: ^0.4.3+2 to check internet connection.

Step 2: Create a model class for your JSON structure.

Here I would like to suggest a little converter tool. Believe me, it is very simple. I just discovered it recently, and I’m in love 😍. Just copy & paste your complex JSON structure and get your model classes magically.

Hey, Dude !!! can you prove your given statement?

Ok ok…Here we are having a live example.

Endpoint URL=”https://api.punkapi.com/v2/beers

First, get your JSON response from URL then go for a converter tool. I have shown you in the below-mentioned image.

BeerListModel class to handle the list of beer model, which we will get in the network call response.

import 'BeerModel.dart';

class BeerListModel{
List<BeerModel> beerList;

BeerListModel({this.beerList});

BeerListModel.fromJson(List<dynamic> parsedJson){
beerList=new List<BeerModel>();
parsedJson.forEach((v){
beerList.add(BeerModel.fromJson(v));
});
}
}

BeerModel class to store the detail of the beer object.

class BeerModel {
var id;
var name;
var tagline;
var firstBrewed;
var description;
var imageUrl;
var abv;
var ibu;
var targetFg;
var targetOg;
var ebc;
var srm;
var ph;

BeerModel(
{this.id,
this.name,
this.tagline,
this.firstBrewed,
this.description,
this.imageUrl,
this.abv,
this.ibu,
this.targetFg,
this.targetOg,
this.ebc,
this.srm,
this.ph});

BeerModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
tagline = json['tagline'];
firstBrewed = json['first_brewed'];
description = json['description'];
imageUrl = json['image_url'];
abv = json['abv'];
ibu = json['ibu'];
targetFg = json['target_fg'];
targetOg = json['target_og'];
ebc = json['ebc'];
srm = json['srm'];
ph = json['ph'];
}

Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
data['tagline'] = this.tagline;
data['first_brewed'] = this.firstBrewed;
data['description'] = this.description;
data['image_url'] = this.imageUrl;
data['abv'] = this.abv;
data['ibu'] = this.ibu;
data['target_fg'] = this.targetFg;
data['target_og'] = this.targetOg;
data['ebc'] = this.ebc;
data['srm'] = this.srm;
data['ph'] = this.ph;
return data;
}
}

You can save your precious time by using this.

Step 3: Now time to call our API.

I have added all API call methods in a different file, suppose a EndPoints.dart.

import 'dart:convert';
import 'package:flutter_rest_api/model/BeerListModel.dart';
// get reponse from API
import 'package:http/http.dart' as http;
// to check internet connection
import 'package:connectivity/connectivity.dart';

// API url
String url = "https://api.punkapi.com/v2/beers";

// Here we are using http package to fetch data from API
// We defined retrun type BeerListModel
Future<BeerListModel> getBeerListData() async {
final response = await http.get(url,);
//json.decode used to decode response.body(string to map)
return BeerListModel.fromJson(json.decode(response.body));
}

Note: Don’t forget to import required packages. I have shown in above code.

Now hold your seat tight, here I am going to explain the code. Http.get() method will call the endpoint, which we have defined in the url string. We will receive a JSON string in response.body, which we have to send to .fromJson method of our model class and don’t forget to add json.decode to decode JSON string. So that it can do its conversion magically.

wow wow, dude !!! you forgot to explain about return type FUTURE !!

We are working with a network call. So it is dam sure it will take some time to deliver a response. So to get our response in future we use Future return type. When we have that Future object, you may not have the data, but you definitely have a promise to get that data in the Future. If you want to know more about the future then give a look at this page.

Definition of future:-

A Future is used to represent a potential value, or error, that will be available at some time in the future.

Besides the Future, we have mentioned two more keywords async and await. Async keyword used for asynchronous. In simple words, it will make your method asynchronous. The await keyword works only in async functions. Awaiting pauses the running code to well wait for the Future to resolve until we get our result.

We are almost done with a network call. Guys here… I have some complimentary code for you.

How to check internet connectivity during network call?

// method defined to check internet connectivity
Future<bool> isConnected() async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.mobile) {
return true;
} else if (connectivityResult == ConnectivityResult.wifi) {
return true;
}
return false;
}

Note: Don’t forget to import required package.import ‘package:connectivity/connectivity.dart’;

Step 4: Building UI for the response, we got from API.

In this step, we are going to build UI from the API response. So here we need to be careful because we have our response in the future but our UI will be built soon as the app runs. If our UI depends on the response value then it will create trouble for you maybe it will throw a lot of null errors.

To solve this problem, we have FutureBuilder.

The FutureBuilder is also a widget, so you can either have it attached to your Scaffold directly, or attach it as a child to any widget you like.

Simply put, use a FutureBuilder to build a widget when there are Futures involved. Let’s add the following lines of code.

import 'package:flutter/material.dart';
import 'package:flutter_rest_api/model/BeerModel.dart';
import 'package:flutter_rest_api/network/EndPoints.dart';

import 'model/BeerListModel.dart';

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;

@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

// Future object to fetch response from API (Response in future)
Future<BeerListModel> beerListFuture;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
padding: const EdgeInsets.all(16.0),
child: FutureBuilder<BeerListModel>(
future: beerListFuture,
builder: (context, snapshot) {
// to show progress loading view add switch statment to handle connnection states.
switch (snapshot.connectionState) {
case ConnectionState.waiting:
{
// here we are showing loading view in waiting state.
return loadingView();
}
case ConnectionState.active:
{
break;
}
case ConnectionState.done:
{
// in done state we will handle the snapshot data.
// if snapshot has data show list else set you message.
if (snapshot.hasData) {
// hasdata same as data!=null
if (snapshot.data.beerList != null) {
if (snapshot.data.beerList.length > 0) {
// here inflate data list
return ListView.builder(
itemCount: snapshot.data.beerList.length,
itemBuilder: (context, index) {
return generateColum(
snapshot.data.beerList[index]);
});
} else {
// display message for empty data message.
return noDataView("No data found");
}
} else {
// display error message if your list or data is null.
return noDataView("No data found");
}
} else if (snapshot.hasError) {
// display your message if snapshot has error.
return noDataView("Something went wrong");
} else {
return noDataView("Something went wrong");
}
break;
}
case ConnectionState.none:
{
break;
}
}
}),
));
}

// Here we created row for the bear list.
Widget generateColum(BeerModel item) => Card(
child: ListTile(
leading: Image.network(item.imageUrl),
title: Text(
item.name,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
),
subtitle:
Text(item.tagline, style: TextStyle(fontWeight: FontWeight.w600)),
),
);

// Progress indicator widget to show loading.
Widget loadingView() => Center(
child: CircularProgressIndicator(
backgroundColor: Colors.red,
),
);

// View to empty data message
Widget noDataView(String msg) => Center(
child: Text(
msg,
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w800),
),
);

@override
void initState() {
// here first we are checking network connection
isConnected().then((internet) {
if (internet) {
// set state while we fetch data from API
setState(() {
// calling API to show the data
// you can also do it with any button click.
beerListFuture = getBeerListData();
});
} else {
/*Display dialog with no internet connection message*/
}
});
super.initState();
}
}

The explanation for the above-mentioned code in simple breakpoints.

  • We used two main properties of the FutureBuilder. The first is the future and the second is the builder. Future needs future so we added beerListFuture simply to get a response in the future. Builder will build your UI. So when we have a network call then the future will return the result to a snapshot of a builder.
  • We did our network call in the initState() method of the lifecycle. We called the getRequest network call method in beerListFuture, which is already defined in the FutureBuilder widget. For more understanding keep your eyes on the code.
  • To show progress indicator we have handled all connection states of the snapshot. In waiting state we put progress indicator and in done state, we have inflated our result.
  • To handle images from the network. We used the below-mentioned code.
Image.network(item.imageUrl),
  • The rest of the checks are added according to connection states of snapshot likewise UI on no data, UI on error or UI on no connection.

Here the Output…..

Thanks for reading this article ❤

If something went wrong? Let me know in the comments section, raise your voice. I would love to improve. A clap from your side will be appreciated.

If you want to check the complete code get it from Github.

--

--