Alberto Bonacina
Flutter and Other Experiments

Follow

Flutter and Other Experiments

Follow
How to properly organize your API EndPoints in Flutter

How to properly organize your API EndPoints in Flutter

Alberto Bonacina's photo
Alberto Bonacina
·Jan 20, 2023·

2 min read

Play this article

Hi everyone, in this post, I'll show you how I organize my API call in one class to manage my API endpoint better and pass parameters to them.

If you've got an app that syncs or gets information from a third-party service you must call some API from your code and it is often tempting to write endpoints directly within our HTTP calls, more or less like this:

//Worst case
Future<MyClass> callEndPoint(int id) async {
    var response = await http.get(Uri.parse("https://myendpointurl/myclass/$id"));
    ...
}

//not that much worse
Future<MyClass> callEndPoint(int id) async {
    var response = await     http.get(Uri.parse("${Env.BASE_URL}/myclass/$id"));
    ...
}

but it is not good practice to hardcode endpoints in all calls, and it is a tad better to manage an environment variable or constant that defines our BASE_URL for calls.

My solution

The solution I have adopted for some time in all my projects is to create an ApiEndPoint class where I define all my endpoints and the parameters I need to manage. So for example to implement calls to the Star Wars API I can do it this way:

class ApiEndPoint {

  late String FILM_ALL;
  late String FILM_SINGLE;

  ApiEndPoint({int? id}) {

    //Value added for simplicity but it is always better 
    //  to add it in a configuration file
    String baseUrlPath = 'https://swapi.dev/api';

    FILM_ALL = '$baseUrlPath/films/';
    FILM_SINGLE = '$baseUrlPath/films/$id';
  }
}

That way when I need to call the endpoint to get the list of movies I just type in:

Future<List<Film>> getAllFilms() async {
  var response = await http.get(
    Uri.parse(ApiEndPoint().FILM_ALL),
  );
  //...
}

And if this endpoint requires input parameters, such as the endpoint to get the information about a single movie, simply write:

Future<Film> getSingleFilm(int idFilm) async {
  var response = await http.get(
    Uri.parse(ApiEndPoint(id: idFilm).FILM_SINGLE),
  );
  //...
}

Easy isn't it?

I find this setup useful and with the following advantages:

  • I have a single class with the responsibility of managing my EndPoints and organizing the paths as required by the API;

  • I can easily pass input parameters without worrying about URL formatting;

  • In my repositories and in my HTTP calls I can tell right away what API it is without going to the URL to figure it out because I have made it explicit in the attributes of my ApiEndPoint class;

  • In the most extreme case, I can switch to another API without having to change my HTTP calls but only by changing the URLs within the ApiEndPoint class;

Code strong, Alberto

Cover Photo by Maria Orlova: Corner Of Aged House Near Direction Post In Town

Did you find this article valuable?

Support Alberto Bonacina by becoming a sponsor. Any amount is appreciated!

See recent sponsors Learn more about Hashnode Sponsors
 
Share this