【Flutter/Dart】HTTPで通信を行う

目次

概要

Flutterでも通信を行う必要が出てくる。
そのためには必要なライブラリを使う必要がある。ただ、ほぼほぼライブラリに任せてしまえば簡単に実装できる。
また、MVVMのようなアーキテクチャも採用して少しコード量も無駄を省くようにする。

また、今回の通信は以下のページの郵便番号を渡すことで住所を返してくれるAPIを使用する。

郵便局検索API

実装

必要なライブラリのインストール

以下の方法でHttp通信に必要なライブラリをインストール使用。

コマンドからは以下

$ flutter pub add http

yamlファイルを編集する時は以下

dependencies:
  http: ^1.1.2

ソースコード

データを受け取るためのクラスは以下

class AddressData {
  String prefectures = "";
  String prefecturesRuby = "";
  String municipalities = "";
  String municipalitiesRuby = "";
  String town = "";
  String townRuby = "";
  String zipcode = "";
  String prefcode = "";

  AddressData(this.prefectures,
      this.prefecturesRuby,
      this.municipalities,
      this.municipalitiesRuby,
      this.town,
      this.townRuby,
      this.zipcode,
      this.prefcode);
}
import 'package:flutter/foundation.dart';

class HttpProcessModel extends ChangeNotifier {

}
import 'package:FlutterDemo/HttpProcess/Response/AddressData.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

import 'HttpProcessModel.dart';

class HttpProcessViewModel extends ChangeNotifier {
  AddressData? addressData;
  late HttpProcessModel _model;
  var zipcodeEditingController = TextEditingController();

  HttpProcessViewModel() {
    _model = HttpProcessModel();
  }

  HttpProcessViewModel.withModel(HttpProcessModel model) {
    _model = model;
  }

  Future<void> getAddress() async {
    try {
      var response = await http.get(Uri.https(
          'zipcloud.ibsnet.co.jp', '/api/search',
          {'zipcode': zipcodeEditingController.text}));
      var jsonResponse = jsonDecode(response.body);
      var result = jsonResponse["results"][0];
      print(result);
      addressData = AddressData(
          result["address1"],
          result["kana1"],
          result["address2"],
          result["kana2"],
          result["address3"],
          result["kana3"],
          result["zipcode"],
          result["prefcode"]);
    } on Exception catch (e) {
      print(e.toString());
    }
    notifyListeners();
  }
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'HttpProcessViewModel.dart';

class HttpProcessView extends StatelessWidget {
  HttpProcessView({Key? key}) : super(key: key);
  HttpProcessViewModel? _viewModel;

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => HttpProcessViewModel(),
      builder: (context, _) {
        _viewModel = context.watch<HttpProcessViewModel>();

        return Scaffold(
          appBar: AppBar(
            backgroundColor: Theme.of(context).colorScheme.inversePrimary,
            title: const Text('Httpテスト'),
          ),
          body: Column(
            children: [
              _zipcodeTextField(),
              _responseDataView(),
              _sendButton()
            ],
          ),
        );
      }
    );
  }

  Widget _zipcodeTextField() {
    return Column(
      children: [
        const Text("郵便番号"),
        TextField(
          controller: _viewModel?.zipcodeEditingController,
          obscureText: false,
          keyboardType: TextInputType.number,
          decoration: const InputDecoration(
            border: OutlineInputBorder(),
            labelText: "",
          ),
        )
      ],
    );
  }

  Widget _responseDataView() {
    return Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.max,
        children: [
          const Text("郵便番号"),
          Text(_viewModel?.addressData?.zipcode ?? "--"),
          const Text("住所カナ"),
          Text("${_viewModel?.addressData?.prefecturesRuby ?? "--"}"
              "${_viewModel?.addressData?.municipalitiesRuby ?? "--"}"
              "${_viewModel?.addressData?.townRuby ?? "--"}"),
          const Text("住所"),
          Text("${_viewModel?.addressData?.prefectures ?? "--"}"
              "${_viewModel?.addressData?.municipalities ?? "--"}"
              "${_viewModel?.addressData?.town ?? "--"}"),
        ]
    );
  }
  
  Widget _sendButton() {
    return OutlinedButton(
        onPressed: () { _viewModel?.getAddress(); },
        child: const Text("送信")
    );
  }
}

デモ動画

詳細

まず今回の主役となるのがこちら。

var response = await http.get(Uri.https(
    'zipcloud.ibsnet.co.jp', '/api/search',
    {'zipcode': zipcodeEditingController.text}));

http.getでGET形式でデータのやり取りをする。getメソッドの内容は以下だ。

引数内容
第一引数
ドメインの文字列を格納
‘zipcloud.ibsnet.co.jp’
第二引数
APIのパスの文字列を格納
‘/api/search’
第三引数
APIのパラメータ
{‘zipcode’: zipcodeEditingController.text}

今回のように、郵便番号のzipcodeに1060045をパラメータとして渡すと、港区麻布十番の住所を取得できる。
上記の例の場合はこちらのURLを叩いているのと同じ。
https://zipcloud.ibsnet.co.jp/api/search?zipcode=1060045

メソッドの引数の部分とURLの部分を見比べると使い方がわかるはずだ。

そして、以下の部分でjsonのデータを取得する。

var jsonResponse = jsonDecode(response.body);

jsonResponseの中身を見てみると以下のような感じ。

{
    message: null,
        results: [
            {
                address1: 東京都,
                address2: 港区,
                address3: 麻布十番,
                kana1: トウキョウト,
                kana2: ミナトク,
                kana3: アザブジュウバン,
                prefcode: 13,
                zipcode: 1060045
            }
        ],
    status: 200
}

その中でresultsを取りたいので以下のようにしている。

var result = jsonResponse["results"][0];

そして、本当に欲しい情報はresultの中のaddress1などなので以下のようにしている。

addressData = AddressData(
    result["address1"],
    result["kana1"],
    result["address2"],
    result["kana2"],
    result["address3"],
    result["kana3"],
    result["zipcode"],
    result["prefcode"]);

参考ページ