# Flutter API 通信 Dio の基本

Dio とは

  • イタリア語 Dìo は(キリスト教の)神、天主、創造主、造物主の意味します。コトバンク Dio (opens new window)
  • 本田バイクにも Dio という 50cc スクーターがあります。ギリシア神話に登場する「全知全能の神」ゼウスの息子たち「Dioskuroi(ディオスクーロイ)」からの造語だそうです。Dio の名前の由来を教えて (opens new window)
  • ディスク入出力(Disc Input / Output)の略でも DIO 使っています。Digital Input / Output も同じく

Dio についていろいろ意味があるようですが、Flutter の Dio はイタリア語の神という意味かなと思います。

# Dio の特徴

  • レスポンスの自動変換できる
  • インターセプター、グローバル設定ができる
  • connectTimeout receiveTimeout sendTimeout のタイムアウト設定ができる
  • ファイルアップロード/ダウンロード
  • リクエストのリトライができる
  • リクエストのキャンセルができる
  • 多言語サポート
  • クッキー、キャッシュを管理できるプラグインがある

Flutter Dio Package (opens new window)
Dio Plugins Topic (opens new window)

# Dio の基本

// api_service.dart
import 'dart:convert';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:dio/dio.dart';

class ApiService {
  final _dio = Dio(BaseOptions(
    baseUrl: dotenv.env['API_BASE_URL'] ?? '',
    connectTimeout: const Duration(seconds: 5), // 5秒
    receiveTimeout: const Duration(seconds: 3), // 3秒
    headers: {'Content-Type': 'application/json'},
  ));

  Future<dynamic> get(String endpoint) async {
    try {
      final response = await _dio.get(endpoint);
      return response.data;
    } on DioException catch (e) {
      throw Exception('Failed to load data: ${e.response?.statusCode}');
    }
  }

  Future<dynamic> post(String endpoint, Map<String, dynamic> data) async {
    try {
      final response = await _dio.post(
        endpoint,
        data: jsonEncode(data),
      );
      return response.data;
    } on DioException catch (e) {
      throw Exception('Failed to post data: ${e.response?.statusCode}');
    }
  }

  Future<dynamic> put(String endpoint, Map<String, dynamic> data) async {
    try {
      final response = await _dio.put(
        endpoint,
        data: jsonEncode(data),
      );
      return response.data;
    } on DioException catch (e) {
      throw Exception('Failed to update data: ${e.response?.statusCode}');
    }
  }

  Future<dynamic> delete(String endpoint) async {
    try {
      final response = await _dio.delete(endpoint);
      return response.data;
    } on DioException catch (e) {
      throw Exception('Failed to delete data: ${e.response?.statusCode}');
    }
  }
}
// user_service.dart
import 'package:my_app/models/user.dart';
import 'api_service.dart';

class UserService {
  final ApiService apiService;

  UserService({required this.apiService});

  Future<List<User>> fetchUsers() async {
    final data = await apiService.get('/users');
    return data.map<User>((json) => User.fromJson(json)).toList();
  }

  Future<User> updateUser(int id, Map<String, dynamic> data) async {
    final response = await apiService.put('/users/$id', data);
    return User.fromJson(response);
  }

  Future<dynamic> deleteUser(int id) async {
    final response = await apiService.delete('/users/$id');
    return response;
  }
}

Javascript の Axios パッケージと似ている使い方で、Axios 経験者なら取り扱いやすいですね。

# Dio のインターセプター

リクエストとレスポンスのインターセプター

import 'package:dio/dio.dart';

void main() async {
  Dio dio = Dio();

  dio.interceptors.add(InterceptorsWrapper(
    onRequest: (options, handler) {
      print('Request: ${options.method} ${options.path}');
      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); // エラーを続行
    },
  ));

  try {
    Response response = await dio.get('https://jsonplaceholder.typicode.com/posts/1');
    print(response.data);
  } catch (e) {
    print(e);
  }
}

# Dio のリクエストのキャンセル

import 'package:dio/dio.dart';

void main() async {
  Dio dio = Dio();
  CancelToken cancelToken = CancelToken();

  // リクエストの実行
  dio.get(
    'https://jsonplaceholder.typicode.com/posts/1',
    cancelToken: cancelToken,
  ).catchError((e) {
    if (CancelToken.isCancel(e)) {
      print('Request canceled: ${e.message}');
    } else {
      print('Error: ${e.message}');
    }
  });

  // リクエストのキャンセル
  cancelToken.cancel('Request canceled by user.');
}
2024-06-07
  • flutter