How to properly organize your API EndPoints in Flutter

How to properly organize your API EndPoints in Flutter

ยท

2 min read

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 Flutter and Other Experiments by becoming a sponsor. Any amount is appreciated!