Dio MVVM Get API Integration with GetX in Flutter

Learn how to integrate Dio (HTTP client) with MVVM architecture to perform Get API calls efficiently.

Explore sample code, step-by-step tutorial, and best practices for seamless API integration.




dependencies:
  flutter:
    sdk: flutter
  dio: ^5.3.0
  get: ^4.6.5


MVVM folder structure


lib/
├── data/
│   ├── models/
│   │   └── user.dart // Contains the User model class for representing user data.
│   ├── repositories/
│   │   └── user_repository.dart // Handles fetching user data from the API.
│   └── services/
│       └── api_service.dart // Provides methods to interact with the API using Dio or other HTTP clients.
│
├── utils/
│   ├── constants.dart // Contains constant values used throughout the app.
│   └── logger.dart // Utility for logging app events or errors.
│
├── view/
│   └── user_list.dart // View file for displaying the list of users.
│
├── view_models/
│   └── user_view_model.dart // ViewModel class for managing user data and API calls.
│
├── widgets/
│   ├── user_tile.dart // Reusable widget for displaying user details in a list.
│   └── loading_spinner.dart // Reusable loading spinner widget.
│
├── main.dart // The main entry point of the Flutter app.
└── locator.dart // File for setting up dependency injection using a service locator pattern.

..

Dio MVVM User List App

Build a Flutter user list app using Dio for API calls and MVVM architecture. Learn how to manage user data and API integration efficiently with sample code and best practices.


main.dart : The main entry point of the Flutter app.


// main.dart

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:flutteryfly/viewmodels/user_view_model.dart';
import 'package:get/get.dart';
import './data/repositories/user_repository.dart';
import './data/services/api_service.dart';
import './views/user_list.dart';

void main() {
  // Initialize GetX dependency injection
  Get.put(ApiService(dio: Dio())); // ApiService instance
  Get.put(UserRepository()); // UserRepository instance
  Get.put(UserViewModel()); // UserViewModel instance

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'User List', // Meta Title for the App
      theme: ThemeData(
        primarySwatch: Colors.green,
      ),
      home: const UserList(),
    );
  }
}

..

user_list.dart : View file for displaying the list of users.


// views/user_list.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart'; // Import the getx package.
import '../viewmodels/user_view_model.dart';

class UserList extends StatelessWidget {
  const UserList({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Users'),
      ),
      body: GetBuilder<UserViewModel>( // Use GetBuilder to access the UserViewModel.
        init: UserViewModel(), // Initialize the UserViewModel instance.
        builder: (userViewModel) {
          // Use the userViewModel to access the state data.
          return userViewModel.loading
              ? const Center(
            child: CircularProgressIndicator(),
          )
              : userViewModel.errorMessage.isNotEmpty
              ? Center(
            child: Text(userViewModel.errorMessage),
          )
              : ListView.builder(
            itemCount: userViewModel.users.length,
            itemBuilder: (context, index) {
              final user = userViewModel.users[index];

              return ListTile(
                title: Text(user.name),
                subtitle: Text(user.email),
                leading: CircleAvatar(
                  child: Text(user.id.toString()),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

..

user_view_model.dart : ViewModel class for managing user data and API calls.


// view_models/user_view_model.dart

import 'package:get/get.dart';

import '../data/models/user.dart';
import '../data/repositories/user_repository.dart';

class UserViewModel extends GetxController {
  final UserRepository _userRepository =
      Get.find(); // Use GetX's Get.find() to get the UserRepository instance.

  final RxList<User> _users =
      <User>[].obs; // List to store user data fetched from the API.
  bool _loading =
      false; // Boolean flag to track if data is currently being fetched.
  String _errorMessage =
      ''; // String to store any error message that occurs during data fetching.

  List<User> get users => _users; // Getter method to access the list of users.
  bool get loading => _loading; // Getter method to access the loading flag.
  String get errorMessage =>
      _errorMessage; // Getter method to access the error message.

  @override
  void onInit() {
    super.onInit();
    fetchUsers();
  }

  Future<void> fetchUsers() async {
    _loading = true;
    _errorMessage = '';

    try {
      _users.value = await _userRepository.getUsers();
    } catch (e) {
      _errorMessage = 'Failed to fetch users';
    } finally {
      _loading = false;
      update(); // Use GetX's update() to notify listeners of data change.
    }
  }
}

..

user_repository.dart : Handles fetching user data from the API.


// data/repositories/user_repository.dart

import 'package:get/get.dart';
import '../models/user.dart';
import '../services/api_service.dart';

class UserRepository {
  final ApiService _apiService =
      Get.find(); // Use GetX's Get.find() to get the ApiService instance.

  Future<List<User>> getUsers() async {
    try {
      final data = await _apiService.getUsers();

      // Map the API response data to a List of User objects using the User.fromJson() constructor.
      return data.map((json) => User.fromJson(json)).toList();
    } catch (e) {
      throw Exception('Failed to fetch users');
    }
  }
}

..

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';

class ApiService {
  final Dio _dio; // Dio instance to perform HTTP requests.

  ApiService({required Dio dio}) : _dio = dio;

  Future<List<dynamic>> getUsers() async {
    try {
      // Make a GET request to the API endpoint to fetch user data.
      final response =
          await _dio.get('https://jsonplaceholder.typicode.com/users');

      // Check if the response status code is 200 (OK).
      if (response.statusCode == 200) {
        return response
            .data; // If successful, return the response data (List of dynamic).
      } else {
        // If the response status code is not 200, throw an exception with an error message.
        throw Exception('API failed with status code: ${response.statusCode}');
      }
    } catch (e) {
      // If any exception occurs during the API call, throw an exception with the error message.
      throw Exception('An error occurred: $e');
    }
  }
}

..


..
Json Array:

[
  {
    "id": 1,
    "name": "Leanne Graham",
    "username": "Bret",
    "email": "Sincere@april.biz",
    "address": {
      "street": "Kulas Light",
      "suite": "Apt. 556",
      "city": "Gwenborough",
      "zipcode": "92998-3874",
      "geo": {
        "lat": "-37.3159",
        "lng": "81.1496"
      }
    },
    "phone": "1-770-736-8031 x56442",
    "website": "hildegard.org",
    "company": {
      "name": "Romaguera-Crona",
      "catchPhrase": "Multi-layered client-server neural-net",
      "bs": "harness real-time e-markets"
    }
  },
  {
    "id": 2,
    "name": "Ervin Howell",
    "username": "Antonette",
    "email": "Shanna@melissa.tv",
    "address": {
      "street": "Victor Plains",
      "suite": "Suite 879",
      "city": "Wisokyburgh",
      "zipcode": "90566-7771",
      "geo": {
        "lat": "-43.9509",
        "lng": "-34.4618"
      }
    },
    "phone": "010-692-6593 x09125",
    "website": "anastasia.net",
    "company": {
      "name": "Deckow-Crist",
      "catchPhrase": "Proactive didactic contingency",
      "bs": "synergize scalable supply-chains"
    }
  },
  
]
..


Comments

  1. can you tell me how to create post request using dio mvvm

    ReplyDelete

Post a Comment