# Flutter Dio Part 2: Handling Responses and Errors

In this part, we’ll enhance our Task Manager app by parsing JSON responses and handling different types of errors. We’ll use Dio’s built-in error handling mechanisms.

You can find the source code of the entire app here: [dio\_tasker](https://github.com/harish-kunchala/dio_tasker)

### Parsing JSON Responses:

We’ll update our `ApiService` to parse JSON response into a list of task objects.

1. **Create a Task Model:**
    

First, we’ll create a new file `lib/models/task.dart`

```dart
class Task {
  final int id;
  final String title;
  final bool completed;

  Task({required this.id, required this.title, required this.completed});

  // Factory method to create a Task from JSON
  factory Task.fromJSON(Map<String, dynamic> json) => Task(
        id: json['id'],
        title: json['title'],
        completed: json['completed'],
      );
}
```

2. **Update** `ApiService`:
    

Now, let’s modify the `lib/services/api_service.dart` to use the Task model:

```dart
import 'package:dio/dio.dart';

import '../models/tasks.dart';

class ApiService {
  // Create an instance of Dio
  final _dio = Dio();

  // Method to fetch tasks from the API
  Future<List<Task>> fetchTasks() async {
    try {
      // Make a GET request to the API endpoint
      final response =
          await _dio.get('https://jsonplaceholder.typicode.com/todos');
      // Parse the response data into a list of Task objects
      return (response.data as List)
          .map((task) => Task.fromJSON(task))
          .toList();
    } catch (e) {
      // Handle errors
      throw Exception('Failed to load tasks');
    }
  }
}
```

### Handling Different Types of Errors:

Now we’ll handle network errors, server errors and other types of errors.

1. **Update** `ApiService` **to Handle Errors**:
    

Let’s modify `lib/services/api_service.dart` to handle different types of errors:

```dart
import 'package:dio/dio.dart';

import '../models/tasks.dart';

class ApiService {
  // Create an instance of Dio
  final _dio = Dio();

  // Method to fetch tasks from the API
  Future<List<Task>> fetchTasks() async {
    try {
      // Make a GET request to the API endpoint
      final response =
          await _dio.get('https://jsonplaceholder.typicode.com/todos');
      // Parse the response data into a list of Task objects
      return (response.data as List)
          .map((task) => Task.fromJSON(task))
          .toList();
    } on DioException catch (dioException) {
      // Handle Dio Exceptions
      if (dioException.type == DioExceptionType.connectionTimeout) {
        throw Exception('Connection Timeout');
      } else if (dioException.type == DioExceptionType.receiveTimeout) {
        throw Exception('Receive Timeout');
      } else if (dioException.type == DioExceptionType.badResponse) {
        throw Exception(
            'Received invalid status code: ${dioException.response?.statusCode}');
      } else {
        throw Exception('Something went wrong');
      }
    } catch (e) {
      // Handle other errors
      throw Exception('Failed to load tasks');
    }
  }
}
```

### Update UI to Display Errors:

We’ll update the UI to display error messages when fetching tasks fails.

1. **Modify TaskListScreen:**
    

Let’s update `lib/main.dart` to display error messages:

```dart
import 'package:dio_tasker/services/api_service.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: TaskListScreen(),
    );
  }
}

class TaskListScreen extends StatefulWidget {
  const TaskListScreen({super.key});

  @override
  State<TaskListScreen> createState() => _TaskListScreenState();
}

class _TaskListScreenState extends State<TaskListScreen> {
  // Create an instance of ApiService
  final ApiService _apiService = ApiService();

  // List to hold the fetched tasks
  List<dynamic> _tasks = [];

  // Variable to hold error messages
  String? _errorMessage;

  @override
  void initState() {
    super.initState();
    // Fetch tasks when the widget is initialized
    _fetchTasks();
  }

  // Method to fetch tasks and update the state
  void _fetchTasks() async {
    try {
      // Fetch tasks from the API
      final tasks = await _apiService.fetchTasks();
      // Update the state with the fetched tasks
      setState(() {
        _tasks = tasks;
      });
    } catch (e) {
      // Update the state with the error message
      setState(() {
        _errorMessage = e.toString();
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Task Manager'),
      ),
      body: _errorMessage != null
          ? Center(
              child: Text(_errorMessage!),
            )
          : ListView.builder(
              // Set the number of items in the list
              itemCount: _tasks.length,
              // Build each item in the list
              itemBuilder: (context, index) {
                return ListTile(
                  // Display the task title
                  title: Text(_tasks[index].title),
                );
              },
            ),
    );
  }
}
```

### Output:

1. **Without Any Errors**
    

Allright so let’s run the app and see if we get any errors.

![app without errors](https://i.postimg.cc/qRWLMcW1/Simulator-Screen-Recording-i-Phone-15-Pro-Max-2024-12-02-at-12-13-58.gif align="left")

2. **With an Error:**
    

Now we’ll change the URL to an invalid URL and see if the app can handle that. So instead of using [https://jsonplaceholder.typicode.com/todos](https://jsonplaceholder.typicode.com/todos) we’ll use [https://jsonplaceholder.typicode.com/to](https://jsonplaceholder.typicode.com/todos). Which is an invalid URL. And here’s the output:

![Error](https://i.postimg.cc/hGYDvhsC/Simulator-Screenshot-i-Phone-15-Pro-Max-2024-12-02-at-13-40-36.png align="left")

Perfect. As we can see, our app is able to handle errors.

You can find the source code for the above example here: [dio\_tasker/02-handling-response-errors](https://github.com/harish-kunchala/dio_tasker/tree/02-handling-response-errors).
