Search
📚

EP17. Flutter API 네트워크 통신

생성일
2024/06/09 09:18
마지막 업데이트
2024/06/12

EP17. Flutter API 네트워크 통신

Flutter에서 API를 호출하고 처리하는 방식을 이해하고 구현합니다.

1. 의존성 설치

패키지 수준의 pubspec에 http를 추가합니다.
flutter pub add http flutter pub get
Bash
복사

2. Android Internet 권한 설정

안드로이드의 경우 HTTP/HTTPS 및 소켓통신을 하기 위해 Internet권한이 필요합니다.
android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
XML
복사
실제 디바이스가 아닌 에뮬레이터의 경우 권한설정을 하지 않아도 정상 동작할 수 있습니다.

3. APIClient 구현

패키지에 APIClient 클래스를 구현합니다. API 호출 과정에서 반복되는 코드를 관리하는 역할을 수행합니다.
패키지 lib 디렉토리 하위에 network 디렉토리를 추가하고 api_client.dart 파일을 추가합니다.
lib/network/api_client.dart
import 'dart:convert'; import 'package:http/http.dart' as http; class ApiClient { ApiClient(this.baseUrl); final String baseUrl; Future<String> get(String endpoint) async { final response = await http.get( Uri.parse('$baseUrl$endpoint'), headers: <String, String>{ 'Content-Type': 'application/json; charset=UTF-8', }, ); return _handleResponse(response); } Future<String> post(String endpoint, Object? body) async { final response = await http.post( Uri.parse('$baseUrl$endpoint'), headers: <String, String>{ 'Content-Type': 'application/json; charset=UTF-8', }, body: jsonEncode(body), ); return _handleResponse(response); } Future<String> delete(String endpoint, Object? body) async { final response = await http.delete( Uri.parse('$baseUrl$endpoint'), headers: <String, String>{ 'Content-Type': 'application/json; charset=UTF-8', }, body: jsonEncode(body), ); return _handleResponse(response); } String _handleResponse(http.Response response) { if (response.statusCode >= 200 && response.statusCode < 300) { return response.body; } else { throw Exception('Failed to load data: ${response.statusCode}'); } } }
Dart
복사

4. 테스트를 위한 임시 UI

API를 호출하기 위한 UI를 구현합니다.
views/home/home_view.dart
import 'package:flutter/material.dart'; import 'package:flutter_package_sample/views/home/home_view_model.dart'; import 'package:provider/provider.dart'; import 'package:swm_flutter_package/network/api_client.dart'; class HomeView extends StatelessWidget { HomeView({super.key}); // ApiClient 인스턴스를 생성하여 API 엔드포인트를 설정 ApiClient apiClient = ApiClient('https://dthvcgffzopawocgahnr.supabase.co/functions/v1/api'); Widget build(BuildContext context) { // HomeViewModel을 Provider를 통해 가져옴 var viewModel = Provider.of<HomeViewModel>(context); // TextEditingController 인스턴스를 생성하여 TextField와 연결 TextEditingController textController = TextEditingController(); return Scaffold( appBar: AppBar( title: Text('홈 화면'), ), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // 로그인한 유저 ID를 표시하는 텍스트 위젯 Text( '로그인한 유저 ID: ${viewModel.userID()}', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), ElevatedButton( onPressed: () { // 로그아웃 버튼을 눌렀을 때의 동작 viewModel.signOut(); }, child: Text('로그아웃'), ), SizedBox(height: 20), // 사용자로부터 입력을 받을 TextField TextField( controller: textController, decoration: InputDecoration( labelText: 'Token', border: OutlineInputBorder(), ), ), SizedBox(height: 20), // API 요청을 위한 버튼들을 포함하는 Row Row( children: [ ElevatedButton( onPressed: () { // '추가' 버튼을 눌렀을 때 API의 POST 엔드포인트를 호출 apiClient.post('/users/v1/fcmToken', {'fcmToken': textController.text}) .then((value) => print(value)) // 응답을 출력 .catchError((error) => print(error)); // 에러를 출력 }, child: Text('추가'), ), SizedBox(width: 10), ElevatedButton( onPressed: () { // '삭제' 버튼을 눌렀을 때 API의 DELETE 엔드포인트를 호출 apiClient.delete('/users/v1/fcmToken', {'fcmToken': textController.text}) .then((value) => print(value)) // 응답을 출력 .catchError((error) => print(error)); // 에러를 출력 }, child: Text('삭제'), ), SizedBox(width: 10), ElevatedButton( onPressed: () { // '조회' 버튼을 눌렀을 때 API의 GET 엔드포인트를 호출 apiClient.get('/users/v1/fcmToken') .then((value) => print(value)) // 응답을 출력 .catchError((error) => print(error)); // 에러를 출력 }, child: Text('조회'), ), ], ), ], ), ), ); } }
Dart
복사
TextField: 추가/삭제할 Token을 입력합니다. 실제로는 디바이스로 부터 얻어온 값을 사용해야 하나 현재 작업범위가 아니기 때문에 테스트 Input 값을 받기 위해 추가했습니다.
‘추가’ 버튼: TextField의 값으로 POST 요청을 수행합니다
‘삭제’ 버튼: TextField의 값으로 DELETE 요청을 수행합니다
‘조회’ 버튼: 현재 유저의 FCM Token 목록을 조회합니다.

5. Flutter DevTools

Flutter에서 발생하는 http request를 관할하기 위해서 Flutter DevTools를 사용해야합니다.
Android Studio IDE 하단 Console 에 있는 Flutter DevTools를 클릭합니다.
웹 브라우저에서 Flutter DevTools가 실행되며, DevTools에서는 현재 실행되어 있는 Flutter Application의 상세 정보를 확인할 수 있습니다.
Network탭에서 HTTP Request, Response를 살펴보겠습니다.
앱으로 돌아가 임의의 Token값을 작성하고 추가/삭제/조회 버튼을 클릭합니다.
Request 정보
Response 정보
Flutter앱에서 발생한 HTTP Request의 정보(Method, URL)와 Response(body, status code)등을 확인할 수 있습니다.
현재 Request에 인증정보가 포함되어있지 않으므로 서버 인증 미들웨어에 의해 401 오류가 발생하는게 정상입니다.

강의 코드

files
6