Breaking News

Default Placeholder Default Placeholder

はじめに

仕様にもよりますがアプリを作っているとサーバアクセスしたい、なんて時ありますよね。サーバ周りって結構面倒だったり、ステータスコードによって挙動変えたりなど大変なところもあります。

今回の記事ではFlutterアプリからHTTP通信を実行する方法をまとめていきたいと思います。

もちろん、この記事の内容は極々一部の例でしかないので他に方法は山ほどあるはずです。

ただ本記事の方法をコピペすることでHTTP通信を実行することができますので、まずコピペしてやってみて、あぁこんな感じか、というイメージを持っていただくだけでもOKです。

ではやっていきましょう!

筆者の環境

  • M1 Mac BigSur 11.4
  • docker-compose 1.29.2
  • Docker 20.10.7
  • Flutter 2.8.1

API環境

今回は以前の記事で作成したRails製のAPIクライアントを使っていきたいと思います。こちらの記事です。テストで使用するAPIエンドポイントがない場合はこちらの記事(や以前の記事を組み合わせて)をコピペするだけで環境を作ることができるのでそちらからチャレンジしてみてください。既に通信できるものがあればそれに合わせてエンドポイントを変更していただくことで通信実行できるのでそれも大丈夫です。

簡単に説明します。

4つのエンドポイントを用意しています。

  • GET /sample/index
  • POST /sample/create
  • PUT /sample/update
  • DELETE /sample/delete

各々のエンドポイントからは小さなJSONが返ってきます。

やりたいこと

やりたいことは以下の3つです。

  • Flutterアプリで、getpostputdeleteのHTTPメソッドを叩けるようにする。
  • Rails7で作ったAPIエンドポイントを叩く
  • 結果を受け取る

やること

やることリストはこちらです。

  • Flutterプロジェクトにhttpをインストール
  • 通信のクラスを作る
  • Flutterの画面を作る
  • main.dartを修正
  • 挙動確認

ではやっていきましょう!

Flutterプロジェクトにhttpをインストール

通信処理に必要なhttpを取得します。

flutter pub add http

通信のクラスを作ります

以下のクラスを作成します。ファイル名はlib/communication.dartとします。

import 'dart:convert';

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

class Communication {

  static const String baseUrl = "127.0.0.1:3000";

  Map<String, String> getHeaders() {
    return {
      HttpHeaders.contentTypeHeader: 'application/json'
    };
  }

  Future<dynamic> get(String endpoint, [params]) async {
    final uri = Uri.http(baseUrl, endpoint, params);
    Map<String, String> headers = getHeaders();
    dynamic response = await call(() async => http.get(uri, headers: headers));
    return response;
  }

  Future<dynamic> post(String endpoint, [params]) async {
    final uri = Uri.http(baseUrl, endpoint);
    final headers = getHeaders();
    dynamic response = await call(() async => http.post(uri, body: json.encode(params), headers: headers));
    return response;
  }

  Future<dynamic> put(String endpoint, [params]) async {
    final uri = Uri.http(baseUrl, endpoint);
    final headers = getHeaders();
    dynamic response = await call(() async => http.put(uri, body: json.encode(params), headers: headers));
    return response;
  }

  Future<dynamic> delete(String endpoint, [params]) async {
    final uri = Uri.http(baseUrl, endpoint, params);
    final headers = getHeaders();
    dynamic response = await call(() async => http.delete(uri, headers: headers));
    return response;
  }

  Future<dynamic> call(Function callback) async {
    try {
      final response = await callback() as http.Response;
      checkStatusCode(response.statusCode);
      return json.decode(response.body);
    } on SocketException catch (e) {
      throw Exception('No Internet Connection');
    } on Exception catch (e) {
      throw Exception(e.toString());
    }
  }

  void checkStatusCode(int httpStatus) {
    switch (httpStatus) {
      case 200:
      case 201:
        break;
      case 400:
        throw Exception('400 Bad Request');
      case 401:
        throw Exception('401 Unauthorized');
      case 403:
        throw Exception('403 Forbidden');
      case 404:
        throw Exception('404 Not Found');
      case 405:
        throw Exception('405 Method Not Allowed');
      case 500:
        throw Exception('500 Internal Server Error');
      default:
        throw Exception('Http status $httpStatus unknown error.');
    }
  }
}

Flutterの画面を作る

各通信処理を実行するボタンが羅列されてる画面を作ります。ファイル名は `lib/index.dart`とします。



import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http_communication_sample/communication.dart';

class Index extends StatefulWidget {
  @override
  _Index createState() => _Index();  
}

class _Index extends State<Index> {
  @override
  Widget build(BuildContext context) {
    Communication communication = Communication();
    return Container(
      color: Colors.white,
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.height,
      child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            CupertinoButton(
              child: const Text("GET"),
              onPressed: () async {
                dynamic res = await communication.get('/sample/index');
                debugPrint(res.toString());
              }
            ),
            CupertinoButton(
              child: const Text("POST"),
              onPressed: () async {
                dynamic res = await communication.post('/sample/create', { 'aaa': 'aaaaa'});
                debugPrint(res.toString());
              }
            ),
            CupertinoButton(
              child: const Text("PUT"),
              onPressed: () async {
                dynamic res = await communication.put('/sample/update', { 'aaa': 'aaaaa'});
                debugPrint(res.toString());
              }
            ),
            CupertinoButton(
              child: const Text("DELETE"),
              onPressed: () async {
                dynamic res = await communication.delete('/sample/delete');
                debugPrint(res.toString());
              }
            )
          ]
        )
      )
    );
  }
}

main.dartを修正する

Flutterの処理の開始地点であるmain.dartを修正します。

home: const MyHomePage(title: 'Flutter Demo Home Page'),

デフォルトでこうなっている箇所を

home: Index(),

こうします。これでFlutterアプリを開いた時に先ほど作ったボタンが羅列されている画面が表示されます。

Flutterアプリを起動してこんな感じならOKです。筆者はiOSエミュレータで起動しました。

これで準備はOKです。では挙動確認していきましょう!

挙動確認

実行してるところを動画にしました。こんな感じになります。

いかがでしたでしょうか?上の動画のように動きましたか?

以上、簡単でありますがFlutterアプリからHTTP通信する方法まとめでした。最後までお読みいただきありがとうございました。