Loading

Flutter API call best practices with code example

svgFebruary 17, 2023APIDartFlutterCodeStackGuide

When making API calls in Flutter, there are a number of best practices to follow to ensure that your app is reliable, efficient, and easy to maintain. Here are some best practices to follow when making API calls using the http package in Flutter, with an example of calling the JSONPlaceholder API:

  1. Use a separate class for API calls: It’s a good practice to create a separate class to handle API calls. This makes it easier to manage your code and keep your business logic separate from your API code.

Here’s an example of a separate class for API calls to the JSONPlaceholder API:

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

class ApiService {
  static const String _baseUrl = 'https://jsonplaceholder.typicode.com';

  static Future<http.Response> getPosts() async {
    final url = Uri.parse('$_baseUrl/posts');
    return http.get(url);
  }
}

In this example, the ApiService class is responsible for making API calls to the JSONPlaceholder API. The getPosts method makes an HTTP GET request to the /posts endpoint of the API and returns a http.Response object.

  1. Use HTTP request methods: Use the appropriate HTTP request method for the API endpoint you’re calling. For example, if you’re retrieving data, use the HTTP GET method. If you’re updating data, use the HTTP PUT or PATCH method. If you’re creating data, use the HTTP POST method. If you’re deleting data, use the HTTP DELETE method.

Here’s an example of making a GET request to the JSONPlaceholder API to retrieve a list of posts:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

import 'api_service.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

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

class _HomePageState extends State<HomePage> {
  Future<http.Response>? _futureResponse;

  @override
  void initState() {
    super.initState();
    _futureResponse = ApiService.getPosts();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('JSONPlaceholder API Example'),
      ),
      body: Center(
        child: FutureBuilder<http.Response>(
          future: _futureResponse,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done) {
              if (snapshot.hasData) {
                final response = snapshot.data!;
                final data = response.body;
                return Text(data);
              } else {
                return const Text('Error');
              }
            } else {
              return const CircularProgressIndicator();
            }
          },
        ),
      ),
    );
  }
}

In this example, we’re using the http package to make a GET request to the JSONPlaceholder API to retrieve a list of posts. The response is then displayed in the UI using a FutureBuilder.

  1. Handle errors: Always handle errors that may occur when making API calls. This can include network errors, server errors, or invalid responses.

Here’s an example of handling errors when making a GET request to the JSONPlaceholder API:

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

class ApiService {
  static const String _baseUrl = 'https://jsonplaceholder.typicode.com';

  static Future<http.Response> getPosts() async {
    final url = Uri.parse('$_baseUrl/posts');
    final response = await http.get(url);
    if (response.statusCode == 200) {
      return response;
    } else {
      throw Exception('Failed to load posts');
    }
  }
}

In this example, we are using the http package to make a GET request to the JSONPlaceholder API to retrieve a list of posts. If the response code is not 200 OK, we throw an exception with an error message.

  1. Use a package for JSON parsing: When working with JSON data, it’s a good practice to use a package for parsing JSON data, rather than writing your own parsing logic. The dart:convert library provides a built-in jsonDecode function for parsing JSON data, but there are also several packages available for working with JSON data in Flutter, such as json_serializable or built_value.

Here’s an example of using the jsonDecode function to parse JSON data from the JSONPlaceholder API:

import 'dart:convert';

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

class ApiService {
  static const String _baseUrl = 'https://jsonplaceholder.typicode.com';

  static Future<List<dynamic>> getPosts() async {
    final url = Uri.parse('$_baseUrl/posts');
    final response = await http.get(url);
    if (response.statusCode == 200) {
      final data = jsonDecode(response.body) as List<dynamic>;
      return data;
    } else {
      throw Exception('Failed to load posts');
    }
  }
}

In this example, we’re using the jsonDecode function to parse the JSON response from the JSONPlaceholder API into a List<dynamic>.

  1. Use a library for HTTP requests: Instead of using the http package directly, you can use a library that provides a higher-level interface for making HTTP requests, such as dio, chopper, or retrofit. These libraries offer features like request cancellation, automatic retries, and request/response interception.

Here’s an example of making a GET request to the JSONPlaceholder API using the dio library:

import 'package:dio/dio.dart';

class ApiService {
  static const String _baseUrl = 'https://jsonplaceholder.typicode.com';

  static final _dio = Dio(BaseOptions(baseUrl: _baseUrl));

  static Future<Response> getPosts() {
    return _dio.get('/posts');
  }
}

In this example, we’re using the dio library to make a GET request to the JSONPlaceholder API to retrieve a list of posts. The Dio instance is created with a base URL, and the request is made using the get method.

In summary, when making API calls in Flutter, it’s important to use best practices to ensure that your app is reliable, efficient, and easy to maintain. These best practices include using a separate class for API calls, using the appropriate HTTP request methods, handling errors, using a package for JSON parsing, and using a library for HTTP requests.

What not to do when calling a rest API

There are several bad practices to avoid when calling an API in Flutter. Here are some of the most common ones:

  1. Making API calls directly in a widget: One of the biggest mistakes is making API calls directly in a widget. This is bad practice because it can make your widget code hard to read and maintain. Instead, you should create a separate class to handle API calls, and call its methods from your widget.
  2. Not handling errors: Failing to handle errors can result in an app that crashes or behaves unpredictably. When making API calls, it’s important to handle errors that might occur, such as network errors or server errors.
  3. Not using a package for HTTP requests: It’s not recommended to make HTTP requests directly using the dart:io library, as it lacks some features that can make the process of calling APIs easier, such as handling cookies, request cancellation, and request timeouts. Instead, it’s recommended to use a package such as http, dio, or chopper.
  4. Making too many API calls: Making too many API calls can slow down your app and use up a lot of data. It’s recommended to minimize the number of API calls by using pagination or by caching data that is frequently used.
  5. Not using a package for JSON parsing: It’s not recommended to write your own JSON parsing logic, as it can be time-consuming and error-prone. Instead, you should use a package such as json_serializable or built_value to parse JSON data.
  6. Not using a package for dependency injection: When making API calls, it’s common to have dependencies such as http or dio. Not using a package for dependency injection can lead to tightly coupled code and make testing and refactoring difficult.

In summary, to avoid bad practices when calling an API in Flutter, it’s important to create a separate class to handle API calls, handle errors, use a package for HTTP requests, minimize the number of API calls, use a package for JSON parsing, and use a package for dependency injection.

0 People voted this article. 0 Upvotes - 0 Downvotes.
svg

What do you think?

Show comments / Leave a comment

Leave a reply

svg
Quick Navigation
  • 01

    Flutter API call best practices with code example