REST API integration in Flutter with Retrofit

Flutter framework contains Networking and JSON serialization modules.
For small JSON data, these modules will work and need to write a lot of code.

If you know about Android/iOS, you may know about a few libraries like Retrofit, AlamoFire. These libraries will handle all data parsing and we need to write less code.

In this post, we are going to learn how to use the Retrofit library in Flutter.

Will do below implementations in this post

  • Calling network APIs.
  • Parsing JSON data.
  • Showing JSON data in a ListView.

Note: If you’re a newbie to Flutter, please check out the Flutter tutorial for an overview of the basics of working with this SDK.

 

In this example we have a button, when we tap on button it will fetch data from API and shows the list of users with the Listview widget

 

Retrofit Rest API

 

 

Retrofit Implementation

 

Let's get started

Step 1: Create a Flutter Application

Step 2:
To work with Retrofit implementation in Flutter we need to add below dependencies in pubspec.yaml file

 

dev_dependencies:
    retrofit_generator: any
    build_runner: any
    analyzer: '0.39.14'
  
dependencies:
    retrofit: any
    logger: any
    dio:
    json_annotation: any
    json_serializable: any

 

Dio is our Http client, handling the connection for us.
Retrofit is a Dio client that makes consuming REST APIs easier for us. Those coming from Android will be pleased to see it in Flutter I guess ????
Build runner is used for code generation in Dart, apart from the pub
JSON Serializable: Creates Model class from JSON data

 

Step 3:

In this post for User data, we are using the API "https://gorest.co.in/public-api/users"

Let's create an abstract class ApiRequest

 

@RestApi(baseUrl: "https://gorest.co.in/public-api/")
abstract class ApiRequest{
  factory ApiRequest(Dio dio,{String baseUrl}) =_ApiRequest;

  @GET("/users")
  Future<ResponseData> getUsers();
}

 

This class is working as a repository which will handle all network call methods.

in the above code, it will show error on the _ApiRequest variable.

To remove this error we need to add part 'apirequest.g.dart'; in the import statement

and run flutter pub run build_runner build command.
 

This will generate apirequest.g.dart file and contains all data about creating Retrofit instance and fetching data from the network

 

Step 4: Create data classes

Our API will return a list of users 

{
      code: 200,
      meta: {
          pagination: {
              total: 1676,
              pages: 84,
              page: 1,
              limit: 20
            }
          },
      data: [
          {
              id: 1,
              name: "Mrs. Somnath Namboothiri",
              email: "somnath_namboothiri_mrs@baumbach-nitzsche.com",
              gender: "Female",
              status: "Active",
              created_at: "2020-08-31T03:50:04.198+05:30",
              updated_at: "2020-08-31T03:50:04.198+05:30"
          },
      ]
}

 

So let's create a data.dart file and add below code

import 'package:json_annotation/json_annotation.dart';
part 'data.g.dart';
@JsonSerializable()
class User{
  int id;
  String name;
  String email;
  String gender;
  String status;
  String created_at;
  String updated_at;

  User({this.id, this.name, this.email,this.gender, this.status, this.created_at, this.updated_at});

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

@JsonSerializable()
class ResponseData{
  int code;
  dynamic meta;
  List<dynamic>data;
  ResponseData({this.code, this.meta, this.data});
  factory ResponseData.fromJson(Map<String, dynamic> json) => _$ResponseDataFromJson(json);
  Map<String, dynamic> toJson() => _$ResponseDataToJson(this);

}

 

The above code will do auto serialization of the JSON data.
at this time it will show errors

so let's add part 'data.g.dart'; and run below command 
flutter pub run build_runner build command

 

Step 5: 
Call API with retrofilt object

FutureBuilder<ResponseData> _buildBody(BuildContext context) {
  final client = ApiRequest(Dio(BaseOptions(contentType: "application/json")));
  return FutureBuilder<ResponseData>(
    future: client.getUsers(),
    builder: (context, snapshot) {
      if (snapshot.connectionState == ConnectionState.done) {

        final ResponseData posts = snapshot.data;
        return _buildPosts(context, posts);
      } else {
        return Center(
          child: CircularProgressIndicator(),
        );
      }
    },
  );
}

 

 

Complete code

main. dart file

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_retrofit/data.dart';

import 'apirequest.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(

        primarySwatch: Colors.green,

        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {


  bool pressed = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        title: Text("Retrofit Implementation - Flutter"),
      ),
      body: pressed ? _buildBody(context):Center(
        child: RaisedButton(child: Text("Fetch Users",style: TextStyle(color: Colors.white,fontSize: 18),),color: Colors.green,
            onPressed: () => {setState(() {
              pressed = true;

            })}),
      ),
    );
  }
}

FutureBuilder<ResponseData> _buildBody(BuildContext context) {
  final client = ApiRequest(Dio(BaseOptions(contentType: "application/json")));
  return FutureBuilder<ResponseData>(
    future: client.getUsers(),
    builder: (context, snapshot) {
      if (snapshot.connectionState == ConnectionState.done) {

        final ResponseData posts = snapshot.data;
        return _buildPosts(context, posts);
      } else {
        return Center(
          child: CircularProgressIndicator(),
        );
      }
    },
  );
}

Widget _buildPosts(BuildContext context, ResponseData posts) {
  return
    ListView.builder(itemBuilder: (context,index){
      return Card(
        child: ListTile(

          leading: Icon(Icons.account_box,color: Colors.green,size: 50,),
          title: Text(posts.data[index]['name'],style: TextStyle(fontSize: 20),),
          subtitle: Text(posts.data[index]['email']),
        ),
      );
    },itemCount: posts.data.length,
   );

}

 

apirequest.dart

import 'package:dio/dio.dart';
import 'package:retrofit/retrofit.dart';

import 'data.dart';

part 'apirequest.g.dart';
@RestApi(baseUrl: "https://gorest.co.in/public-api/")
abstract class ApiRequest{
  factory ApiRequest(Dio dio,{String baseUrl}) =_ApiRequest;

  @GET("/users")
  Future<ResponseData> getUsers();

}

 

data.dart file

import 'package:json_annotation/json_annotation.dart';
part 'data.g.dart';
@JsonSerializable()
class User{
  int id;
  String name;
  String email;
  String gender;
  String status;
  String created_at;
  String updated_at;

  User({this.id, this.name, this.email,this.gender, this.status, this.created_at, this.updated_at});

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

@JsonSerializable()
class ResponseData{
  int code;
  dynamic meta;
  List<dynamic>data;
  ResponseData({this.code, this.meta, this.data});
  factory ResponseData.fromJson(Map<String, dynamic> json) => _$ResponseDataFromJson(json);
  Map<String, dynamic> toJson() => _$ResponseDataToJson(this);

}

 

 

Flutter Search - ListView Filter Search

 

Tags: Retrofit, Rest API, Network calls, JSON Serialization