How to Cache JSON from REST API in Flutter

In this example, we are going to show you how to enable Caching of JSON or any other resource from REST API. Cached JSON will be fetched whenever your app is offline or disconnected. We have used "Pull to refresh" to refresh the cache. See the example below:

First of all, you need to add dio and dio_http_cache flutter Packages in your project by adding the following lines in pubspec.yaml file.

dependencies:
  flutter:
    sdk: flutter
  dio: ^4.0.4
  dio_http_cache: ^0.3.0

Here, dio package is for fetching JSON or any other resource from REST API, and dio_http_cache package is to be used for caching resources fetched from REST API.

Read This Also: How to Fetch Data from REST API in Flutter

Import dio and dio_http_cache in your dart script:

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

Add this line before API Request, you can do this both on GET and POST Method:

dio.interceptors.add(DioCacheManager(CacheConfig(baseUrl: "http://www.google.com")).interceptor);

Enable Caching on REST API request:

Dio().get(
  "http://www.google.com",
   options: buildCacheOptions(Duration(days: 7)),
);

Read this also: How to Enable Cache and Lazy Loading Image in Flutter App

Set maxState if you want to return cache in case of 500, 400 error:

buildCacheOptions(Duration(days: 7), maxStale: Duration(days: 10))

You can force refresh too:

buildCacheOptions(Duration(days: 7), forceRefresh: true)

PHP Code at the server-side script that generates JSON:

<?php 
$return["error"] = false;
$return["msg"] = "";
$return["data"] = array();

if(isset($_REQUEST["auth"])){
    $authkey = $_REQUEST["auth"];
    if($authkey == "kjgdkhdfldfguttedfgr"){
          $countries = array(
               array(
                   "name"=>"Canada",
                   "capital"=>"Ottawa"
               ),

               array(
                   "name"=>"Brazil",
                   "capital"=>"Brasília"
               ),

               array(
                   "name"=>"Finland",
                   "capital"=>"Helsinki"
               ),
               array(
                   "name"=>"Nepal",
                   "capital"=>"Kathmandu"
               )
            );

            $return["data"] = $countries;
    }else{
       $return["error"] = true;
       $return["msg"] = "Authentication error.";
    }
}else{
    $return["error"]  = true;
    $return["msg"] = "Send auth key.";
}

header('Content-Type: application/json');
echo json_encode($return);
//converting array to JSON string

JSON Output:

{
   "error":false,
   "msg":"",
   "data":[
      {
         "name":"Canada",
         "capital":"Ottawa"
      },
      {
         "name":"Brazil",
         "capital":"Brasília"
      },
      {
         "name":"Finland",
         "capital":"Helsinki"
      },
      {
         "name":"Nepal",
         "capital":"Kathmandu"
      }
   ]
}

Flutter Code: In this code, "Pull to refresh" is also enabled using RefreshIndicator() widget

import 'package:dio/dio.dart';
import 'package:dio_http_cache/dio_http_cache.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
     return MaterialApp(
         home: Home()
      );
  }
}

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

class _HomeState extends State<Home> {
  late Response response;
  Dio dio = Dio();

  bool error = false; //for error status
  bool loading = false; //for data featching status
  String errmsg = ""; //to assing any error message from API/runtime
  var apidata; //for decoded JSON data
  bool refresh = false; //for forcing refreshing cache
  
  @override
  void initState() {
    dio.interceptors.add(DioCacheManager(CacheConfig(baseUrl: "http://192.168.0.235")).interceptor);
    getData(); //fetching data
    super.initState();
  }

  getData() async { 
      setState(() {
         loading = true;  //make loading true to show progressindicator
      });

      String url = "http://192.168.0.235/test/data.php?auth=kjgdkhdfldfguttedfgr";
      //don't use "http://localhost/" use local IP or actual live URL

      Response response = await dio.get(url, options: buildCacheOptions(
                          Duration(days: 7), //duration of cache
                          forceRefresh: refresh, //to force refresh
                          maxStale: Duration(days: 10), //before this time, if error like
                                    //500, 500 happens, it will return cache 
                )); 
      apidata = response.data; //get JSON decoded data from response
      
      print(apidata); //printing the JSON recieved

      if(response.statusCode == 200){
          //fetch successful
          if(apidata["error"]){ //Check if there is error given on JSON
              error = true; 
              errmsg  = apidata["msg"]; //error message from JSON
          }
      }else{ 
          error = true;
          errmsg = "Error while fetching data.";
      }

      loading = false;
      refresh = false;
      setState(() {}); //refresh UI 
  }

  
  @override
  Widget build(BuildContext context) {
    
    return Scaffold(
         appBar: AppBar(
            title: Text("Cache JSON from REST API"),
            backgroundColor: Colors.redAccent,
         ),

         body: RefreshIndicator(
             onRefresh: () async { 
                 refresh = true;
                 getData();
             },
             child:SingleChildScrollView(
             child:Container(
                constraints: BoxConstraints( 
                   minHeight: 1500
                ),
                alignment: Alignment.topCenter,
                padding: EdgeInsets.all(20),
                  child: loading?
                  CircularProgressIndicator(): //if loading == true, show progress indicator
                  Container( //if there is any error, show error message
                    child:error?Text("Error: $errmsg"):
                    Column(  //if everything fine, show the JSON as widget
                        children:apidata["data"].map<Widget>((country){
                            return Card(
                              child: ListTile( 
                                    title: Text(country["name"]),
                                    subtitle: Text(country["capital"]),
                              ),
                            );
                        }).toList(),
                    )
                  ) 
                )   
           )   
         )
    );
  } 
}

In this code, we have cached JSON for 7 days which is fetched from REST API. In the scroll view, we have enabled the Pull to refresh indicator so that whenever the User tries to refresh to data, we have forced refresh the cache.

You can run the above code. It will get the data from REST API, and cache it. Turn off your wifi or internet connection, and again restart the app. It will show the list from cache JSON. 

In this way, you can cache JSON or any other resource from REST API in Flutter App.

No any Comments on this Article


Please Wait...