【Flutter】HTTP通信の基本（GET / POST）- http / dio パッケージを比較 -

## 1. はじめに

アプリケーション開発において、HTTP通信は非常に重要な要素です。HTTP（Hypertext Transfer Protocol）は、クライアント（アプリ）とサーバー間でデータを送受信するためのプロトコルです。例えば、ニュースアプリがWebAPIを通して最新のニュースを取得したり、ユーザーが入力した情報をサーバーに送信してデータベースに登録する際に、HTTP通信が使用されます。

この記事では、代表的なHTTP通信パッケージである`http`と`dio`を比較し、さらに`httpbin`という登録不要のWebAPIに対して、GET / POSTリクエストを実装・動作確認する方法を解説します。

## 2. パッケージの比較

FlutterでHTTP通信を行う際に使われる主なライブラリとして、`http`パッケージと`dio`パッケージがあります。それぞれの特徴を以下の丸バツ表で比較してみます。

| 機能/特徴                 | `http` | `dio` |
|--------------------------|--------|-------|
| **シンプルなGET/POST**    | ○      | ○     |
| **ヘッダーやクエリパラメータの設定** | ○      | ○     |
| **非同期処理（async/await）対応** | ○      | ○     |
| **タイムアウト設定**       | ○ | ○ |
| **JSONの自動変換**         | △（手動実装）| ○|
| **ファイルのダウンロード/アップロード** | ×      | ○     |
| **複雑なリクエスト（フォームデータやマルチパート）** | △（手動実装）      | ○     |
| **WebSocketのサポート**   | ×      | ×     |
| **学習コスト**            | ○（低い） | △（やや高い） |
| **プロジェクトの規模**    | 小〜中規模 | 中〜大規模 |

### 解説

- **`http`パッケージ**: シンプルで軽量なHTTPクライアントです。基本的なGETおよびPOSTリクエストを簡単に行うことができ、小規模なプロジェクトや基本的な機能を必要とするアプリケーションに最適です。学習コストも低く、導入が容易です。

- **`dio`パッケージ**: より高度な機能を提供します。大規模なプロジェクトや複雑なHTTP通信が必要な場合に特に有利です。学習コストは少し高めですが、その分柔軟性があります。

---

## 3. httpbinの紹介

`httpbin`は、登録不要で簡単にHTTP通信を試すことができるWebサービスです。これにより、HTTP通信のテストを気軽に行うことができます。

`http://httpbin.org`というURLの後ろに決められたパラメータを付与することで、様々なテストが行えます。今回は、以下の機能を使用します。

| 機能 | エンドポイント | 
| -------- | -------- | 
| GETリクエストのテスト     | http://httpbin.org/get     | 
| POSTリクエストのテスト     |  http://httpbin.org/post   | 

## 4. httpパッケージでの実装

### httpパッケージのインストール

`http`パッケージをプロジェクトに追加します。

```bash
flutter pub add http
```

Flutterコード内で`http`をインポートします。

```dart
import 'package:http/http.dart' as http;
import 'dart:convert';
```

### GETリクエストの実装

以下のコードは、`httpbin`のAPIを使ってGETリクエストを送信し、サーバーからデータを取得する例です。

```dart
Future<void> fetchData() async {
  final response = await http.get(Uri.parse('https://httpbin.org/get'));

  if (response.statusCode == 200) {
    var data = json.decode(response.body);
    print(data); // 取得したデータを表示
  } else {
    print('Failed to load data');
  }
}
```

### POSTリクエストの実装

次に、POSTリクエストを送信する例です。

```dart
Future<void> postData() async {
  final response = await http.post(
    Uri.parse('https://httpbin.org/post'),
    headers: {'Content-Type': 'application/json'},
    body: json.encode({'key1': 'value1', 'key2': 'value2'}),
  );

  if (response.statusCode == 200) {
    var data = json.decode(response.body);
    print(data); // 取得したデータを表示
  } else {
    print('Failed to post data');
  }
}
```

### 動作確認

以下のコードでは、`GET`ボタンを押すとGETリクエスト、`POST`ボタンを押すとPOSTリクエストが実行され、レスポンスの内容が表示されます。

```dart
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'HTTP Requests Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  // GETリクエストを送信
  Future<void> fetchData() async {
    final response = await http.get(Uri.parse('https://httpbin.org/get'));

    if (response.statusCode == 200) {
      var data = json.decode(response.body);
      print(data); // 取得したデータを表示
    } else {
      print('Failed to load data');
    }
  }


  // POSTリクエストを送信
  Future<void> postData() async {
    final response = await http.post(
      Uri.parse('https://httpbin.org/post'),
      headers: {'Content-Type': 'application/json'},
      body: json.encode({'key1': 'value1', 'key2': 'value2'}),      
    );

    if (response.statusCode == 200) {
      var data = json.decode(response.body);
      print(data); // 取得したデータを表示
    } else {
      print('Failed to post data');
    }
  } 

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('HTTP Requests Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            ElevatedButton(
              onPressed: fetchData,
              child: Text('Send GET Request'),
            ),
            ElevatedButton(
              onPressed: postData,
              child: Text('Send POST Request'),
            ),
          ],
        ),
      ),
    );
  }
}
```

### 説明
1. **GETリクエスト**
   - `http.get()`で`httpbin.org/get`にGETリクエストを送信。
   - レスポンスが`200 OK`であれば、レスポンスボディを画面に表示します。

2. **POSTリクエスト**
   - `http.post()`で`httpbin.org/post`にPOSTリクエストを送信。`body`にはJSON形式のデータを送信します。
   - 同様にレスポンスが成功すれば、結果を表示します。

### 実行方法
アプリを実行し、GETまたはPOSTボタンを押すとリクエストを送信し、その結果が画面に表示されます。


---

## 5. dioパッケージでの実装

### dioパッケージのインストール

`dio`パッケージをプロジェクトに追加します。

```bash
flutter pub add dio
```

Flutterコード内で`dio`をインポートします。

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

### GETリクエストの実装

`dio`を使ったGETリクエストの例です。

```dart
Future<void> fetchData() async {
  final dio = Dio();
  try {
    final response = await dio.get('https://httpbin.org/get');
    print(response.data); // 取得したデータを表示
  } catch (e) {
    print('Error: $e');
  }
}
```

### POSTリクエストの実装

次に、POSTリクエストの例です。

```dart
Future<void> postData() async {
  final dio = Dio();
  try {
    final response = await dio.post('https://httpbin.org/post',data: {'key1': 'value1', 'key2': 'value2'});
    print(response.data); // 取得したデータを表示
  } catch (e) {
    print('Error: $e');
  }
}
```

### 動作確認

以下のコードでは、`GET`ボタンを押すとGETリクエスト、`POST`ボタンを押すとPOSTリクエストが実行され、レスポンスの内容が表示されます。

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dio HTTP Requests Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  final _dio = Dio();

  // GETリクエストを送信
  Future<void> fetchData() async {
    try {
      final response = await _dio.get('https://httpbin.org/get');
      print(response.data);
    } catch (e) {
      print('Error: $e');
    }
  }

  // POSTリクエストを送信
  Future<void> postData() async {
    try {
      final response = await _dio.post('https://httpbin.org/post', data: {'key1': 'value1', 'key2': 'value2'});
      print(response.data);
    } catch (e) {
      print('Error: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Dio HTTP Requests Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            ElevatedButton(
              onPressed: fetchData,
              child: Text('Send GET Request'),
            ),
            ElevatedButton(
              onPressed: postData,
              child: Text('Send POST Request'),
            ),
          ],
        ),
      ),
    );
  }
}
```

### 説明
1. **GETリクエスト**
   - `Dio().get()`を使用して、`https://httpbin.org/get`にGETリクエストを送信。
   - レスポンスが成功すれば、レスポンスデータを画面に表示します。

2. **POSTリクエスト**
   - `Dio().post()`を使用して、`https://httpbin.org/post`にPOSTリクエストを送信。送信するデータとして`{'key1': 'value1', 'key2': 'value2'}`を含めています。
   - 同様にレスポンスが成功すれば、結果を表示します。

### 実行方法

アプリを実行し、GETまたはPOSTボタンを押すとリクエストを送信し、その結果が画面に表示されます。

## 6. おわりに

FlutterでのHTTP通信は非常にシンプルで、`http`パッケージと`dio`パッケージを使うことで簡単に実装できます。`http`は軽量で基本的な通信に適しており、`dio`はより多機能で大規模なプロジェクトに向いています。`httpbin`を利用することで、HTTP通信のテストやデバッグも容易に行えます。

これらの知識を活用し、Flutterでのアプリ開発をさらに進めていきましょう！