Bird
Raised Fist0
Fluttermobile~20 mins

Dio package for advanced HTTP in Flutter - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Advanced HTTP with Dio
This screen demonstrates advanced HTTP requests using the Dio package in Flutter. It fetches data from a public API, shows loading and error states, and allows retrying the request.
Target UI
┌───────────────────────────────┐
│ Advanced HTTP with Dio         │
├───────────────────────────────┤
│ [Fetch Data]                  │
│                               │
│ Status: Idle                  │
│                               │
│ Response:                    │
│ <empty>                      │
└───────────────────────────────┘
Add a button labeled 'Fetch Data' that triggers an HTTP GET request using Dio.
Show a loading indicator while the request is in progress.
Display the status text: 'Idle', 'Loading...', 'Success', or 'Error'.
Show the fetched JSON response in a scrollable Text widget.
Handle errors gracefully and allow retrying by pressing the button again.
Use Dio interceptors to log request and response info to the console.
Starter Code
Flutter
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';

class AdvancedHttpScreen extends StatefulWidget {
  @override
  State<AdvancedHttpScreen> createState() => _AdvancedHttpScreenState();
}

class _AdvancedHttpScreenState extends State<AdvancedHttpScreen> {
  final Dio dio = Dio();
  String status = 'Idle';
  String responseText = '';

  @override
  void initState() {
    super.initState();
    // TODO: Add Dio interceptors here
  }

  Future<void> fetchData() async {
    setState(() {
      status = 'Loading...';
      responseText = '';
    });
    try {
      // TODO: Make GET request to https://jsonplaceholder.typicode.com/posts/1
      // TODO: Update status and responseText on success
    } catch (e) {
      // TODO: Update status and responseText on error
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Advanced HTTP with Dio')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            ElevatedButton(
              onPressed: fetchData,
              child: Text('Fetch Data'),
            ),
            SizedBox(height: 20),
            Text('Status: $status'),
            SizedBox(height: 20),
            Expanded(
              child: SingleChildScrollView(
                child: Text(responseText),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
Task 1
Task 2
Task 3
Solution
Flutter
import 'package:flutter/material.dart';
import 'package:dio/dio.dart';

class AdvancedHttpScreen extends StatefulWidget {
  @override
  State<AdvancedHttpScreen> createState() => _AdvancedHttpScreenState();
}

class _AdvancedHttpScreenState extends State<AdvancedHttpScreen> {
  final Dio dio = Dio();
  String status = 'Idle';
  String responseText = '';

  @override
  void initState() {
    super.initState();
    dio.interceptors.add(InterceptorsWrapper(
      onRequest: (options, handler) {
        print('Request: ${options.method} ${options.uri}');
        return handler.next(options);
      },
      onResponse: (response, handler) {
        print('Response: ${response.statusCode} ${response.data}');
        return handler.next(response);
      },
      onError: (DioError e, handler) {
        print('Error: ${e.message}');
        return handler.next(e);
      },
    ));
  }

  Future<void> fetchData() async {
    setState(() {
      status = 'Loading...';
      responseText = '';
    });
    try {
      final response = await dio.get('https://jsonplaceholder.typicode.com/posts/1');
      setState(() {
        status = 'Success';
        responseText = response.data.toString();
      });
    } catch (e) {
      setState(() {
        status = 'Error';
        responseText = e.toString();
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Advanced HTTP with Dio')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            ElevatedButton(
              onPressed: fetchData,
              child: Text('Fetch Data'),
            ),
            SizedBox(height: 20),
            Text('Status: $status'),
            SizedBox(height: 20),
            Expanded(
              child: SingleChildScrollView(
                child: Text(responseText),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

We added Dio interceptors in initState to print request, response, and error details to the console. This helps us see what is happening behind the scenes.

The fetchData method uses Dio to make a GET request to a sample API. It updates the UI state to show loading, success, or error messages. The response data is shown as a string in a scrollable area.

This approach teaches how to handle advanced HTTP features like interceptors and error handling with Dio in Flutter.

Final Result
Completed Screen
┌───────────────────────────────┐
│ Advanced HTTP with Dio         │
├───────────────────────────────┤
│ [Fetch Data]                  │
│                               │
│ Status: Success               │
│                               │
│ Response:                    │
│ {                           │
│   "userId": 1,             │
│   "id": 1,                 │
│   "title": "...",        │
│   "body": "..."          │
│ }                           │
└───────────────────────────────┘
User taps 'Fetch Data' button.
Status text changes to 'Loading...'.
After successful fetch, status changes to 'Success' and JSON response is displayed.
If an error occurs, status changes to 'Error' and error message is shown.
Console logs show request and response details due to interceptors.
Stretch Goal
Add a retry button that appears only when the status is 'Error' to allow retrying the fetch.
💡 Hint
Use a conditional widget to show the retry button only on error, and call fetchData again when pressed.

Practice

(1/5)
1. What is the primary purpose of the Dio package in Flutter?
easy
A. To manage local databases
B. To create UI animations
C. To make HTTP requests easily with advanced features
D. To handle user input gestures

Solution

  1. Step 1: Understand Dio's role

    Dio is designed as an HTTP client to simplify network calls in Flutter apps.
  2. Step 2: Compare with other options

    Other options like UI animations or database management are unrelated to Dio's purpose.
  3. Final Answer:

    To make HTTP requests easily with advanced features -> Option C
  4. Quick Check:

    Dio = HTTP client [OK]
Hint: Dio is all about HTTP requests, not UI or storage [OK]
Common Mistakes:
  • Confusing Dio with UI or database packages
  • Thinking Dio handles gestures
  • Assuming Dio is for local storage
2. Which of the following is the correct way to create a Dio instance with a base URL of 'https://api.example.com'?
easy
A. var dio = Dio(BaseOptions(baseUrl: 'https://api.example.com'));
B. var dio = Dio('https://api.example.com');
C. var dio = Dio().setBaseUrl('https://api.example.com');
D. var dio = Dio(baseUrl: 'https://api.example.com');

Solution

  1. Step 1: Check Dio instance creation syntax

    Dio requires BaseOptions to set baseUrl during initialization.
  2. Step 2: Validate each option

    var dio = Dio(BaseOptions(baseUrl: 'https://api.example.com')); uses BaseOptions correctly; others misuse constructor or methods.
  3. Final Answer:

    var dio = Dio(BaseOptions(baseUrl: 'https://api.example.com')); -> Option A
  4. Quick Check:

    BaseOptions sets baseUrl in Dio [OK]
Hint: Use BaseOptions to set baseUrl when creating Dio [OK]
Common Mistakes:
  • Passing URL directly to Dio constructor
  • Using nonexistent setBaseUrl method
  • Setting baseUrl as a direct parameter
3. Given the code snippet:
var dio = Dio();
var response = await dio.get('https://jsonplaceholder.typicode.com/posts/1');
print(response.data['id']);

What will be printed?
medium
A. 1
B. null
C. An error message
D. The entire JSON response

Solution

  1. Step 1: Understand the GET request

    The code fetches post with id 1 from the API.
  2. Step 2: Access response data

    response.data['id'] accesses the 'id' field, which is 1.
  3. Final Answer:

    1 -> Option A
  4. Quick Check:

    response.data['id'] = 1 [OK]
Hint: Access response.data keys to get JSON fields [OK]
Common Mistakes:
  • Expecting entire JSON instead of specific field
  • Not awaiting the async call
  • Using wrong key to access data
4. Identify the error in this Dio request code:
var dio = Dio();
var response = dio.get('https://api.example.com/data');
print(response.data);
medium
A. Dio instance not created properly
B. Incorrect URL format
C. response.data is not a valid property
D. Missing await keyword for async call

Solution

  1. Step 1: Check async call usage

    dio.get returns a Future; it must be awaited to get response.
  2. Step 2: Identify missing await

    Code lacks await, so response is a Future, not the actual response object.
  3. Final Answer:

    Missing await keyword for async call -> Option D
  4. Quick Check:

    Async calls need await [OK]
Hint: Always await async Dio calls to get response [OK]
Common Mistakes:
  • Forgetting await on async requests
  • Assuming dio.get is synchronous
  • Trying to access data on Future object
5. How can you add a custom header 'Authorization: Bearer token123' to all requests made by a Dio instance?
hard
A. Add headers directly in each get/post call only
B. Set headers in BaseOptions when creating Dio instance
C. Use dio.addHeader('Authorization', 'Bearer token123') method
D. Modify the response interceptor to add headers

Solution

  1. Step 1: Understand global headers setup

    Headers for all requests are set in BaseOptions.headers when creating Dio.
  2. Step 2: Evaluate options

    Setting headers in BaseOptions applies them globally to all requests; adding them per get/post call is request-specific; there is no addHeader method on Dio; response interceptors handle responses, not request headers.
  3. Final Answer:

    Set headers in BaseOptions when creating Dio instance -> Option B
  4. Quick Check:

    Global headers = BaseOptions.headers [OK]
Hint: Use BaseOptions.headers for global request headers [OK]
Common Mistakes:
  • Trying to add headers via nonexistent methods
  • Setting headers only per request instead of globally
  • Confusing response interceptors with request headers
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard