#FlutterでAPI通信をしてエラーが出て困った話
swiftUIを学習していたのですが、androidのAPPもまとめて作れるということでFlutterを使った話。
まずはAPIでhttps通信しなければいけない気がして、ネットで調べその通りに実装してエラーが出てしまいました。これはそのエラーを解決したお話です。
##作ろうとしたもの
ボタンを押すとランダムなユーザー情報を表示するだけの習作App。
出来上がりがこちら。
使ったAPIはこちら。
http://api.randomuser.me/
画像、名前、性別、電話番号などを取得できるテストするには非常に便利なAPIです(有名ですね)
※responseはjsonです。
##コードとエラー内容と解決と
loadData() async {
String url = 'http://api.randomuser.me/';
http.Response response = await http.get(url);
var userData = json.decode(utf8.decode(response.bodyBytes));
setState(() {
_gender = userData['results'][0]['gender'];
_image = userData['results'][0]['picture']['large'];
_firstName = userData['results'][0]['name']['first'];
_lastName = userData['results'][0]['name']['last'];
_country = userData['results'][0]['location']['country'];
_phone = userData['results'][0]['phone'];
_email = userData['results'][0]['email'];
});
print(userData['results'][0]);
//jsonの中身を見るだけ
}
これはAPIのリクエストをして取得したデータをあらかじめ設定しておいたstateにセットする関数を書いたコードです。
これで上手くいくはずなのに、こんなエラーが。
The argument type 'String' can't be assigned to the parameter type 'Uri'
StringをパラメータタイプのUriに設定できない?
よくわからないので公式を調べてみると。。
公式URL→https://pub.dev/packages/http/changelog
どうやらhttps0.13.0(通信に使用しているパッケージです)から仕様に変更があったようでした。
変更内容は
「これまではString型のURLでAPIを叩いてもOKだったけど、これからはURIで叩いてもらっていい?」
と、いった内容でしたので...
loadData() async {
String url = 'http://api.randomuser.me/';
http.Response response = await http.get(Uri.parse(url));
//↑urlをUri.parse()でuriにパースしました。
var userData = json.decode(utf8.decode(response.bodyBytes));
setState(() {
_gender = userData['results'][0]['gender'];
_image = userData['results'][0]['picture']['large'];
_firstName = userData['results'][0]['name']['first'];
_lastName = userData['results'][0]['name']['last'];
_country = userData['results'][0]['location']['country'];
_phone = userData['results'][0]['phone'];
_email = userData['results'][0]['email'];
});
print(userData['results'][0]);
//jsonの中身を見るだけ
}
と改修しました。
これにはFlutterもニッコリ。無事エラーが消えて解決しました。
そしてコードの全体はこんな感じ↓
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ランダムユーザー取得',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'ランダムユーザー取得'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _gender = "";
String _firstName = "";
String _lastName = "";
String _country = "";
String _phone = "";
String _email = "";
String _image = "http://placehold.jp/08e1f5/ffffff/300x300.png";
// APIから取ってくる
loadData() async {
String url = 'http://api.randomuser.me/';
http.Response response = await http.get(Uri.parse(url));
//↑urlをUri.parse()でuriにパースしました。
var userData = json.decode(utf8.decode(response.bodyBytes));
setState(() {
_gender = userData['results'][0]['gender'];
_image = userData['results'][0]['picture']['large'];
_firstName = userData['results'][0]['name']['first'];
_lastName = userData['results'][0]['name']['last'];
_country = userData['results'][0]['location']['country'];
_phone = userData['results'][0]['phone'];
_email = userData['results'][0]['email'];
});
print(userData['results'][0]);
//jsonの中身を見るだけ
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.network(
_image,
width: 300,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'User Name :',
style: TextStyle(color: Colors.blue, fontSize: 20),
),
Text(
_firstName,
style: const TextStyle(fontSize: 30),
),
const Text(
" ",
style: TextStyle(fontSize: 30),
),
Text(
_lastName,
style: const TextStyle(fontSize: 30),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
"Gender :",
style: TextStyle(color: Colors.blue, fontSize: 20),
),
Text(
_gender,
style: const TextStyle(fontSize: 30),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
"Country :",
style: TextStyle(color: Colors.blue, fontSize: 20),
),
Text(
_country,
style: const TextStyle(fontSize: 30),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
"E-Mail :",
style: TextStyle(color: Colors.blue),
),
Text(
_email,
style: const TextStyle(fontSize: 20),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
"Phone :",
style: TextStyle(color: Colors.blue, fontSize: 20),
),
Text(
_phone,
style: const TextStyle(fontSize: 30),
),
],
),
ElevatedButton(
onPressed: () => {loadData()},
child: const Text("ユーザー情報更新"),
)
],
),
),
// This trailing comma makes auto-formatting nicer for build methods.
);
}
}
#感想
Dartってどこか知ってる雰囲気だったのですが、調べるとJavaScriptの後継的な言語とのことでした。
出来上がったアプリはどことなくマッチングアプリっぽくなりました。
今回のアプリはUIがまだまだですが、目的であるAPIを叩いて情報を取得、表示させることができたので無問題です。
次は入力情報によってAPIリクエストを送ったり、端末自体の機能にアクセスする機能も実装していきます。
新しい技術は仕様変更も多く、これまではOKだったのにエラーになったりするので公式ドキュメントは大事やでと思いました。