Category: Blog, Flutter, Development

Networking and Connecting to API | How to Develop an App with Flutter – Part 5

Learn how to build your first app with Flutter. This time we will focus on networking setup.

How to build your first app with Flutter – Networking and Connecting to API

Want to build an app with Flutter? Follow our series “Flutter app development tutorial for beginners”. We’ve published the following posts so far:

  1. Introduction to your first Flutter app development 
  2. Flutter Project Setup
  3. Creating a Home Screen
  4. Styling the Home Screen
  5. Networking and connecting to API – you are reading this
  6. Refining Widgets’ Layer with Provider
  7. Internationalizing and Localizing your Flutter App

What’s more, we’ve also prepared a Roadmap that can be useful in your Flutter development journey:

Whether you want to be a freelancer or work at Flutter development company, our series will help you to become a Flutter developer.

Setting up networking in the project

Thanks to following the steps described in the last post, we have the screen of our application ready. In this part, we are going to make it worse (a little). Currently, the pollution data on the screen is mocked, we have to replace it with the real data fetched from the server. In order to do this, it is necessary to set networking in our application up.

Where do we start?

If we want to display the data we need to take it from somewhere. We will use public API for air quality in Poland. The air quality portal API grants access to detailed air quality data collected from the whole country. This API is public and we do not need to authenticate.

What kind of data can we obtain?

  1. List of all air quality stations,
  2. List of air quality sensors for each station,
  3. List of historical air quality data for each sensor,
  4. Current air quality summary for each station.

Here is how a single air quality station looks like:


Our goal is to display the name of the station in the UI of our application.

Setting up networking packages

There are two main choices when it comes to the networking library in Flutter

  1. http package – as per documentation “set of high-level functions and classes that make it easy to consume HTTP resources.” This package is also mentioned in the flutter documentation.
  2. dio package – more powerful than the previous one, offers more configuration such as adding interceptors and request cancellation. Also, it can be extended with plugins for cookie management, cache, etc.

In this article, we will use the HTTP package because our use case is simple. We will only fetch data from the network and we don’t have to authenticate. There will be no complicated logic behind our networking adventures, so we wouldn’t need to use all the features of the dio package, but it is definitely worth knowing of its existence.

What’s more, the data that we will get has to be serialized. We can do this manually but it is much convenient to use code generation for that. For this purpose we will need serialization packages:

  1.  json_serializable – generating classes.
  2.  json_annotation – marking model classes with annotations so that it is clear what we want to achieve in generated code.
  3.  build_runner – provides a command-line interface for generating the code.

This will convert JSON data into objects defined in our application. All this will prevent us from writing boilerplate serialization code for each model class. Add all those packages into pubspec.yaml:

To the code

Now, that we have all our dependencies ready it’s time to make use of them!

First, we will create an HTTP client class that will be responsible for making actual network requests and for error handling. The class looks like this:

  • The class is defined as a singleton so that we can reuse the same instance in many places,
  • data from the network is received as a String so we need to parse it using jsonDecode method which is defined in dart SDK – dart:convert,
  • we check for failures and map them to our own errors defined to suit our needs.

Here are the error types defined for our networking:

The next step is creating a repository when we will create methods to obtain data from different endpoints using HttpClient class created earlier.

The private _Urls class defines all the endpoints that were described at the beginning of the article. We will use each of the endpoints as a parameter to the getRequest method of our HTTP client object.

PollutionRestRepository class extends PollutionRepository. This is an interface that defines all our network requests. This way the responsibility of the repository class is clearly defined. What is more, because of the abstraction it will be easy to switch implementations if we needed to.

As you can see in our repository implementation there are two types of data returned from the getRequest  method:

  1. final List<dynamic> stationListJson
  2. final Map<String, dynamic> sensorDataJson

The reason for this is that we can have two (and only two) types of structures when it comes to json files

  1. List – when json data is wrapped with square brackets []
  2. Map – when json data is wrapped with curly brackets {}

The type of structure depends on the endpoint that we are requesting data from. dynamic type specifies that there can be different types of objects stored as list elements or map key values.

We are left with the last piece of data to analyze in our PollutionRestRepository class

PollutionStation.fromJson(stationListJson.first)

This line converts JSON structure into PollutionStation object that we have defined in our application. Let’s describe this situation in more detail.

Deserialization

“Serialization is the process of translating data structures or object state into a format that can be stored (for example, in a file or memory buffer) or transmitted (for example, across a network connection link) and reconstructed later” – from Wikipedia. Deserialization is the opposite.

Since we are only fetching data from the internet we will focus on the deserialization process. We can do this by manually mapping each property of the class to the corresponding JSON key which is very repetitive and error-prone or we can use code generation to do this task for us.

In order to generate the code we have to mark our class with annotations:

Here is what needs to be done in steps:

  1. Specify the name of the auto-generated class part pollution_station.g.dart
  2. Mark class as serializable  @JsonSerializable()
  3. Specify json key for each property of the class @JsonKey(name: 'id'). Hint: if the name of the property is the same as the key then the annotation can be omitted.
  4. If the property is an object itself we have to provide the serialization class for that object as well! Here City property is the case.

More information about possible annotations can be found in json_serializable documentation. Now we are ready to generate the code, we do this by typing into the terminal:

flutter packages pub run build_runner build

This command is available by adding build_runner to pubspec.yaml file. Running it will generate classes containing code that we would otherwise have to write ourselves.

The last thing is to provide convenient methods in our classes that can use the auto-generated code.

Displaying the data on the UI

The time has come to display pollution data on the UI of our application. First thing is to create a repository object in the HomePage class so that we can use its methods:

For the purpose of displaying the data, we will use FutureBuilder widget which will allow us to create widgets using the future object. We will combine it with GestureDetector widget so that we will invoke a request every time we click on the created widget, the code looks like this:

Inside the builder method, we have access to snapshot object which we can use to check if the data are still loading and if the request resulted in success or error. In case of an error, we have to map received error into an appropriate message. We will do it in ApiExceptionMapper class:

The error types have already been defined in our HttpClient (at the beginning of the article) so now it is easy to provide a message for a specific type of error received. This way this class is translatable if we wanted to introduce internationalization in our application.

Now, when the request fails we should see a relevant message. We have just placed, the name of the station in the middle of the screen. This name is only for the purpose of this article and will be removed afterward.

smoge final

Summary

Today we’ve learned how to create a simple network request and pass the data into our UI. The complete plugin source code is available in Smoge GitHub repository.

In the next article, we will focus on improving the architecture of our Flutter app. In the meantime, check out in10 – RSVP & ETA Tracking App which we made with Flutter.

About the author

Tomasz Olichwer

Tomasz Olichwer

Android & Flutter Developer

Android & Flutter Developer