Skip to Content
ドキュメントFlutterコース外部APIと連携しよう

外部APIと連携しよう

このページで学ぶこと

  • Flutter から HTTP リクエストを送れる
  • JSON をDartのオブジェクトに変換できる
  • ローディング・エラーの状態を適切に表示できる

http パッケージをインストールする

Flutter 標準では HTTP 通信の機能がないため、パッケージを追加します。

flutter pub add http
bash

やってみよう

ステップ1: APIからデータを取得する

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
 
void main() => runApp(const MyApp());
 
class MyApp extends StatelessWidget {
  const MyApp({super.key});
 
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: UserListPage());
  }
}
 
class UserListPage extends StatefulWidget {
  const UserListPage({super.key});
 
  @override
  State<UserListPage> createState() => _UserListPageState();
}
 
class _UserListPageState extends State<UserListPage> {
  List<dynamic> _users = [];
  bool _loading = true;
  String? _error;
 
  @override
  void initState() {
    super.initState();
    _fetchUsers();  // ページが表示されたらAPIを叩く
  }
 
  Future<void> _fetchUsers() async {
    try {
      final response = await http.get(
        Uri.parse('https://jsonplaceholder.typicode.com/users'),
      );
 
      if (response.statusCode == 200) {
        setState(() {
          _users = jsonDecode(response.body);  // JSONをDartのListに変換
          _loading = false;
        });
      } else {
        setState(() {
          _error = 'エラー: ${response.statusCode}';
          _loading = false;
        });
      }
    } catch (e) {
      setState(() {
        _error = '通信エラーが発生しました';
        _loading = false;
      });
    }
  }
 
  @override
  Widget build(BuildContext context) {
    if (_loading) {
      return const Scaffold(
        body: Center(child: CircularProgressIndicator()),
      );
    }
 
    if (_error != null) {
      return Scaffold(
        body: Center(child: Text(_error!, style: const TextStyle(color: Colors.red))),
      );
    }
 
    return Scaffold(
      appBar: AppBar(title: const Text('ユーザー一覧')),
      body: ListView.builder(
        itemCount: _users.length,
        itemBuilder: (context, index) {
          final user = _users[index];
          return ListTile(
            leading: CircleAvatar(child: Text('${index + 1}')),
            title: Text(user['name']),
            subtitle: Text(user['email']),
          );
        },
      ),
    );
  }
}
dart

ステップ2: モデルクラスを作る

JSON を都度 user['name'] のように扱うのは大変です。
モデルクラスを作ってDartのオブジェクトに変換しましょう。

// lib/models/user.dart
 
class User {
  final int id;
  final String name;
  final String email;
 
  User({
    required this.id,
    required this.name,
    required this.email,
  });
 
  // JSONからUserオブジェクトを作るファクトリコンストラクタ
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'],
      name: json['name'],
      email: json['email'],
    );
  }
}
dart
// APIから取得したJSONをUserオブジェクトのリストに変換
final List<User> users = (jsonDecode(response.body) as List)
    .map((json) => User.fromJson(json))
    .toList();
 
// 使うとき
print(users[0].name);   // user['name'] の代わりに
print(users[0].email);
dart

ステップ3: POSTリクエストを送る

Future<void> createTodo(String title) async {
  final response = await http.post(
    Uri.parse('https://jsonplaceholder.typicode.com/todos'),
    headers: {'Content-Type': 'application/json'},
    body: jsonEncode({
      'title': title,
      'completed': false,
      'userId': 1,
    }),
  );
 
  if (response.statusCode == 201) {
    final newTodo = jsonDecode(response.body);
    print('作成成功: ${newTodo['id']}');
  }
}
dart

FutureBuilder を使う

非同期処理と Widget を組み合わせる方法として FutureBuilder があります。

class UserPage extends StatelessWidget {
  const UserPage({super.key});
 
  Future<List<User>> fetchUsers() async {
    final res = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));
    final List<dynamic> data = jsonDecode(res.body);
    return data.map((json) => User.fromJson(json)).toList();
  }
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('ユーザー一覧')),
      body: FutureBuilder<List<User>>(
        future: fetchUsers(),
        builder: (context, snapshot) {
          // ローディング中
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          }
          // エラー
          if (snapshot.hasError) {
            return Center(child: Text('エラー: ${snapshot.error}'));
          }
          // データあり
          final users = snapshot.data!;
          return ListView.builder(
            itemCount: users.length,
            itemBuilder: (context, index) {
              return ListTile(title: Text(users[index].name));
            },
          );
        },
      ),
    );
  }
}
dart

確認しよう

  • flutter pub add http でパッケージを追加した
  • APIからデータを取得してリスト表示できた
  • ローディング中・エラー時の表示を実装した
  • モデルクラスを作ってJSONを変換できた

AIに聞いてみよう

「Flutterでローカルにデータを保存するにはどうすればいいですか?shared_preferencesとsqfliteの違いを教えてください」


次のステップ

Flutter の基礎はここで完了です!自分のアプリを作りましょう。

自分のアプリを企画しよう

Last updated on