はじめに
Flutter アプリで住所入力フォームを実装する際、郵便番号から住所を自動補完する機能はよく求められます。
日本郵便が提供する郵便番号検索 API を利用すれば実現できますが、トークン管理や API の呼び出し方法を自前で実装するのは手間がかかります。
japan_post_api_client は、日本郵便 API のクライアントを Flutter 向けにラップしたパッケージです。
トークンの自動取得・管理や、シンプルなインターフェースで郵便番号・住所の検索が簡単に行えます。
インストール
# pubspec.yaml
dependencies:
japan_post_api_client: ^1.0.5
公開 IP アドレスの取得に public_ip_address パッケージも合わせて使うと便利です(後述)。
public_ip_address: any
事前準備:日本郵便 API の認証情報
日本郵便の API を利用するには、クライアント ID とシークレットキーが必要です。
また、トークン取得時にデバイスのパブリック IP アドレスが必要になります。
基本的な使い方
初期化
import 'package:japan_post_api_client/japan_post_api_client.dart';
final apiClient = JapanPostApiClient(
clientId: 'YOUR_CLIENT_ID',
secretKey: 'YOUR_SECRET_KEY',
);
トークンの取得
API を呼び出す前に、まずトークンを取得します。
public_ip_address パッケージでパブリック IP を取得する方法が簡単です。
import 'package:public_ip_address/public_ip_address.dart';
final ipResult = await IpAddress().getIpAddress();
final ipAddress = ipResult.ip;
await apiClient.getToken(ipAddress);
郵便番号で住所を検索する
searchByPostalCode() で郵便番号から住所情報を取得できます。
final result = await apiClient.searchByPostalCode('1000001');
switch (result) {
case ApiResultSuccess(:final data):
for (final address in data) {
print('${address.prefecture} ${address.city} ${address.town}');
}
case ApiResultFailure(:final error):
print('エラー: ${error.message}');
}
ハイフンあり・なしどちらの形式にも対応しています。
await apiClient.searchByPostalCode('100-0001'); // ハイフンあり
await apiClient.searchByPostalCode('1000001'); // ハイフンなし
住所から郵便番号を検索する
searchByAddress() で都道府県・市区町村・町域名から郵便番号を逆引き検索できます。
final result = await apiClient.searchByAddress(
prefecture: '東京都',
city: '千代田区',
town: '千代田',
);
switch (result) {
case ApiResultSuccess(:final data):
for (final address in data) {
print('〒${address.postalCode} ${address.prefecture}${address.city}${address.town}');
}
case ApiResultFailure(:final error):
print('エラー: ${error.message}');
}
エラーハンドリング:ApiResult sealed class
戻り値は ApiResult という sealed class になっており、Dart 3 のパターンマッチングで安全に処理できます。
sealed class ApiResult<T> {}
class ApiResultSuccess<T> extends ApiResult<T> {
final T data;
}
class ApiResultFailure<T> extends ApiResult<T> {
final ApiError error;
}
switch 式や if-case で網羅的に処理できるため、エラーの取りこぼしがありません。
// switch 式で使う例
final message = switch (result) {
ApiResultSuccess(:final data) => '${data.length}件見つかりました',
ApiResultFailure(:final error) => 'エラー: ${error.message}',
};
実装例:住所入力フォームへの組み込み
郵便番号入力に連動して住所を自動補完する例です。
class AddressForm extends StatefulWidget {
@override
State<AddressForm> createState() => _AddressFormState();
}
class _AddressFormState extends State<AddressForm> {
final _postalCodeController = TextEditingController();
final _prefectureController = TextEditingController();
final _cityController = TextEditingController();
final _townController = TextEditingController();
late final JapanPostApiClient _apiClient;
@override
void initState() {
super.initState();
_apiClient = JapanPostApiClient(
clientId: 'YOUR_CLIENT_ID',
secretKey: 'YOUR_SECRET_KEY',
);
_initToken();
}
Future<void> _initToken() async {
final ip = (await IpAddress().getIpAddress()).ip;
await _apiClient.getToken(ip);
}
Future<void> _searchAddress(String postalCode) async {
if (postalCode.replaceAll('-', '').length != 7) return;
final result = await _apiClient.searchByPostalCode(postalCode);
if (result case ApiResultSuccess(:final data) when data.isNotEmpty) {
final address = data.first;
setState(() {
_prefectureController.text = address.prefecture;
_cityController.text = address.city;
_townController.text = address.town;
});
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
controller: _postalCodeController,
decoration: const InputDecoration(labelText: '郵便番号'),
keyboardType: TextInputType.number,
onChanged: _searchAddress,
),
TextField(
controller: _prefectureController,
decoration: const InputDecoration(labelText: '都道府県'),
),
TextField(
controller: _cityController,
decoration: const InputDecoration(labelText: '市区町村'),
),
TextField(
controller: _townController,
decoration: const InputDecoration(labelText: '町域'),
),
],
);
}
}
対応プラットフォーム
| プラットフォーム | 対応 |
|---|---|
| iOS | ✅ |
| Android | ✅ |
| macOS | ✅ |
| Windows | ✅ |
| Linux | ✅ |
| Web | ❌(dart:io 依存のため) |
まとめ
japan_post_api_client を使うことで、日本郵便 API のトークン管理や通信処理を気にせず、郵便番号・住所検索機能を Flutter アプリに簡単に組み込めます。
- 郵便番号 → 住所の正引き検索
- 都道府県・市区町村・町域名 → 郵便番号の逆引き検索
-
ApiResultsealed class による型安全なエラーハンドリング - pub points 160/160 の高品質パッケージ
住所入力フォームの実装にぜひ活用してみてください。
