- Home
- Services
- IVY
- Portfolio
- Game Dev
- Blogs
- About Us
- Contact Us
- Sun-Tue (9:00 am-7.00 pm)
- infoaploxn@gmail.com
- +91 656 786 53
API Integration in Flutter Using Design Patterns Integrating APIs efficiently is crucial for building scalable Flutter apps. In this guide, I will show you how I structure API calls using three key design patterns:
Let’s build a simple example where I fetch posts from an API and display them in a list.
I start by creating an ApiService class that handles API calls. This class is responsible for making network requests using Dio, which simplifies HTTP communication in Flutter.
Create api_service.dart
import ’package:dio/dio.dart’;
class ApiService {
final Dio _dio = Dio();
final String baseUrl = "https://jsonplaceholder.typicode.com";
Future<List<dynamic>> fetchPosts() async {
try {
final response = await _dio.get(’$baseUrl/posts’);
return response.data;
} catch (e) {
throw Exception("Failed to fetch posts");
}
}
}
By keeping API logic separate in a service class, I ensure that any changes to API calls don’t directly impact other parts of the app.
The repository pattern abstracts the API service so that UI code does not directly depend on API calls. Instead of calling ApiService directly in my widgets, I delegate that responsibility to a repository.
Create post_repository.dart
import ’api_service.dart’;
class PostRepository {
final ApiService apiService;
PostRepository(this.apiService);
Future<List<dynamic>> getPosts() async {
return await apiService.fetchPosts();
}
Using this pattern, if I later decide to fetch data from a local database instead of an API, I only need to modify the repository without affecting the UI.
To keep my dependencies well-organized, I use get_it. This allows me to manage objects in one place and retrieve them anywhere in the app without manually creating instances.
Create locator.dart
import ’package:get_it/get_it.dart’;
import ’api_service.dart’;
import ’post_repository.dart’;
final GetIt locator = GetIt.instance;
void setupLocator() {
locator.registerLazySingleton<ApiService>(() => ApiService());
locator.registerLazySingleton<PostRepository>(() => PostRepository(locator<ApiService>()));
}
By using dependency injection, I can manage the lifecycle of objects efficiently and avoid redundant instance creations.
I need a way to manage API data within my app, and Provider makes this easy. This PostProvider class fetches posts and notifies the UI when data changes.
Create post_provider.dart
import ’package:flutter/material.dart’;
import ’../locator.dart’;
import ’post_repository.dart’;
class PostProvider with ChangeNotifier {
final PostRepository repository = locator<PostRepository>();
List<dynamic> _posts = [];
bool _isLoading = false;
List<dynamic> get posts => _posts;
bool get isLoading => _isLoading;
Future<void> fetchPosts() async {
_isLoading = true;
notifyListeners();
try {
_posts = await repository.getPosts();
} catch (e) {
_posts = [];
}
_isLoading = false;
notifyListeners();
}
}
With this setup, I don’t need to manually trigger UI updates when fetching data – notifyListeners() ensures the UI updates automatically.
Now, I create a screen that displays the posts. The UI listens to PostProvider and updates dynamically.
Create post_screen.dart
import ’package:flutter/material.dart’;
import ’package:provider/provider.dart’;
import ’post_provider.dart’;
class PostScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final postProvider = Provider.of<PostProvider>(context);
return Scaffold(
appBar: AppBar(title: Text("Posts")),
body: postProvider.isLoading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: postProvider.posts.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(postProvider.posts[index][’title’]),
subtitle: Text(postProvider.posts[index][’body’]),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => postProvider.fetchPosts(),
child: Icon(Icons.refresh),
),
);
}
}
Since I use Provider, my widget automatically updates when data is fetched without manually setting states.
I modify main.dart to include the setup and provider integration.
import ’package:flutter/material.dart’;
import ’package:provider/provider.dart’;
import ’locator.dart’;
import ’post_provider.dart’;
import ’post_screen.dart’;
void main() {
setupLocator();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => PostProvider(),
),
],
child: MaterialApp(
home: PostScreen(),
),
);
}
}
By wrapping the app in MultiProvider, I ensure that PostProvider is available throughout the app, making state management seamless.
By following these steps, I achieve: ✅ Separation of concerns – UI, API calls, and state management remain separate. ✅ Scalability – The codebase stays clean as the app grows. ✅ Reusability – Services and repositories can be reused in different parts of the app.
By using this approach, I have found that my development process becomes much smoother. I do not have to worry about tight coupling between different layers of my app. The Repository Pattern ensures that I can switch data sources easily, whether it’s an API or a local database. The Provider simplifies my state management without unnecessary complexity, and get_it helps me organize dependencies in a way that keeps my codebase manageable.
Imagine reducing your operational costs by up to $100,000 annually without compromising on the technology you rely on. Through our partnerships with leading cloud and technology providers like AWS (Amazon Web Services), Google Cloud Platform (GCP), Microsoft Azure, and Nvidia Inception, we can help you secure up to $25,000 in credits over two years (subject to approval).
These credits can cover essential server fees and offer additional perks, such as:
By leveraging these credits, you can significantly optimize your operational expenses. Whether you're a startup or a growing business, the savings from these partnerships ranging from $5,000 to $100,000 annually can make a huge difference in scaling your business efficiently.
The approval process requires company registration and meeting specific requirements, but we provide full support to guide you through every step. Start saving on your cloud infrastructure today and unlock the full potential of your business.

