Dio MVVM Get API Integration with Provider in Flutter (With Nested JSON Object)
Learn how to efficiently integrate Dio (HTTP client) with MVVM architecture to perform Get API calls in Flutter.
Explore step-by-step tutorials, best practices, and sample code for seamless API integration with nested JSON objects using Provider for state management.
dependencies:
flutter:
sdk: flutter
dio: ^5.3.0
provider: ^6.0.5
Dio MVVM Get API Integration with Provider in Flutter
Build a user object app demonstrating API integration and data management with Dio and Provider in a clean and organized manner.
main.dart : The main entry point of the Flutter app.
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:flutteryfly/views/user_object.dart';
import 'package:provider/provider.dart';
import './data/services/api_service.dart';
import 'data/models/user_object_repository.dart';
import 'data/repositories/user_object_repository.dart';
void main() {
// Create Dio instance for HTTP requests
final Dio dio = Dio();
// Create ApiService instance with the Dio instance
final ApiService apiService = ApiService(dio: dio);
// Create UserRepository instance with the ApiService instance
final UserObjectRepository userObjectRepository = UserObjectRepository(apiService: apiService);
// Provider
runApp(
MultiProvider(
providers: [
// Provide the UserObjectViewModel with UserObjectViewModel dependency to manage product data and API calls
ChangeNotifierProvider<UserObjectViewModel>(
create: (context) => UserObjectViewModel(userRepository: userObjectRepository),
),
],
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'User Object Dio API', // Meta Title for the App
theme: ThemeData(
primarySwatch: Colors.green,
),
home: const UserObjectPage(),
);
}
}
..
user_object.dart : To displays user data fetched from an API using the Dio library and managed with the Provider package
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../data/models/user_object_repository.dart';
class UserObjectPage extends StatefulWidget {
const UserObjectPage({super.key});
@override
State<UserObjectPage> createState() => _UserObjectPageState();
}
class _UserObjectPageState extends State<UserObjectPage> {
@override
void initState() {
super.initState();
// Fetch product data when the state object is inserted into the tree.
final productViewModel = Provider.of<UserObjectViewModel>(context, listen: false);
productViewModel.fetchUserData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Dio + Provider with API Object'),
),
body: Consumer<UserObjectViewModel>(
builder: (context, userViewModel, _) {
final user = userViewModel.user?.data;
final support = userViewModel.user?.support;
return Center(
child: userViewModel.loading
? const CircularProgressIndicator()
: userViewModel.errorMessage.isNotEmpty
? Text(userViewModel.errorMessage)
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircleAvatar(
backgroundImage: NetworkImage(user?.avatar ?? ''),
radius: 50,
),
const SizedBox(height: 10),
Text('ID: ${user?.id ?? 'N/A'}'),
Text('Email: ${user?.email ?? 'N/A'}'),
Text('First Name: ${user?.firstName ?? 'N/A'}'),
Text('Last Name: ${user?.lastName ?? 'N/A'}'),
const SizedBox(height: 20),
Text('Support URL: ${support?.url ?? 'N/A'}'),
Text('Support Text: ${support?.text ?? 'N/A'}'),
],
),
);
},
),
);
}
}
..
user_object_view_model.dart : ViewModel class for managing user data and API calls.
// viewmodels/user_object_view_model.dart
import 'package:flutter/material.dart';
import 'package:flutteryfly/data/models/user_object.dart';
import '../repositories/user_object_repository.dart';
class UserObjectViewModel extends ChangeNotifier {
final UserObjectRepository userRepository;
// Constructor that takes a UserObjectRepository as a dependency
UserObjectViewModel({required this.userRepository});
// Private variables to hold user data and state information
UserObject? _user;
bool _loading = false;
String _errorMessage = '';
// Getters to access the private variables from outside the class
UserObject? get user => _user;
bool get loading => _loading;
String get errorMessage => _errorMessage;
// Function to fetch user data from the repository
Future<void> fetchUserData() async {
// Set loading to true before fetching data
_loading = true;
// Clear any previous error message
_errorMessage = '';
try {
// Fetch user data using the userRepository
_user = await userRepository.getUserData();
} catch (e) {
// If an error occurs during data fetching, set the error message
_errorMessage = 'Failed to fetch user data';
}
// Set loading to false after data fetching, regardless of success or failure
_loading = false;
// Notify listeners to update the UI with new data
notifyListeners();
}
}
..
user_object_repository.dart : Handles fetching user data from the API.
// data/repositories/user_object_repository.dart
import '../models/user.dart';
import '../models/user_object.dart';
import '../services/api_service.dart';
class UserObjectRepository {
final ApiService apiService;
// Constructor that takes an ApiService as a dependency
UserObjectRepository({required this.apiService});
// Function to fetch user data from the API
Future<UserObject> getUserData() async {
try {
// Call the API service to get user data with an ID of 2
final data = await apiService.getUserObject(2);
// Convert the fetched data into a UserObject model using the fromJson method
return UserObject.fromJson(data);
} catch (e) {
// If an error occurs during data fetching, throw an exception with an error message
throw Exception('Failed to fetch user data');
}
}
}
..
api_service.dart : Provides methods to interact with the API using Dio or other HTTP clients.
// data/services/api_service.dart
import 'package:dio/dio.dart';
import '../../utils/logger_interceptor.dart';
class ApiService {
late Dio _dio; // Dio instance to perform HTTP requests.
// Constructor that takes a Dio instance as a dependency
ApiService({required Dio dio}) {
// Initialize the Dio instance with base options and add interceptors.
_dio = Dio(BaseOptions(
//baseUrl: "https://dummyjson.com/products/",
// connectTimeout: const Duration(seconds:5),
// receiveTimeout: const Duration(seconds: 3),
responseType: ResponseType.json,
))..interceptors.addAll([
// Add any interceptors for the Dio instance here.
// For example, LoggerInterceptor() could be a custom logger interceptor.
// LoggerInterceptor(),
]);
}
// Function to fetch user object data from the API based on the provided ID
Future<Map<String, dynamic>> getUserObject(int id) async {
try {
// Perform a GET request to the API endpoint with the provided ID
final response = await _dio.get('https://reqres.in/api/users/$id');
// Check if the response status code is 200 (success)
if (response.statusCode == 200) {
// If successful, return the response data as a Map of dynamic.
return response.data;
} else {
// If the response status code is not 200, throw an exception with the status code.
throw Exception('API failed with status code: ${response.statusCode}');
}
} catch (e) {
// If an error occurs during the request or response handling, throw an exception with the error message.
throw Exception('An error occurred: $e');
}
}
}
..
..
{
"data": {
"id": 2,
"email": "janet.weaver@reqres.in",
"first_name": "Janet",
"last_name": "Weaver",
"avatar": "https://reqres.in/img/faces/2-image.jpg"
},
"support": {
"url": "https://reqres.in/#support-heading",
"text": "To keep ReqRes free, contributions towards server costs are appreciated!"
}
}
// data/models/user_object_model.dart
class UserObject {
final UserObjectData? data;
final Support? support;
UserObject({this.data, this.support});
factory UserObject.fromJson(Map<String, dynamic> json) {
return UserObject(
data: UserObjectData.fromJson(json['data']),
support: Support.fromJson(json['support']),
);
}
}
class UserObjectData {
final dynamic id;
final String? email;
final String? firstName;
final String? lastName;
final String? avatar;
UserObjectData({this.id, this.email, this.firstName, this.lastName, this.avatar});
factory UserObjectData.fromJson(Map<String, dynamic> json) {
return UserObjectData(
id: json['id'],
email: json['email'],
firstName: json['first_name'],
lastName: json['last_name'],
avatar: json['avatar'],
);
}
}
class Support {
final String? url;
final String? text;
Support({this.url, this.text});
factory Support.fromJson(Map<String, dynamic> json) {
return Support(
url: json['url'],
text: json['text'],
);
}
}
Comments
Post a Comment