[Flutter] Dio 패키지를 활용한 HTTP 통신 실습
Flutter로 애플리케이션을 개발할 때, REST API를 활용한 데이터 통신은 매우 중요합니다.
이번 포스팅에서는 Flutter에서 인기 있는 HTTP 통신 패키지인 Dio를 사용하여 서버와 데이터를 주고받는 방법을 단계별로 살펴보겠습니다.
💡 학습 목표
1. Dio 패키지를 설치하고 기본 사용법 익히기
2. REST API로 데이터 가져오기
3. JSON 데이터를 Dart 객체로 변환하기
1. Dio 패키지 설치하기
dio install | Dart package
A powerful HTTP networking package, supports Interceptors, Aborting and canceling a request, Custom adapters, Transformers, etc.
pub.dev
Dio는 강력하고 유연한 HTTP 클라이언트 패키지로, Flutter에서 쉽게 설치하고 사용할 수 있습니다.
pub.dev 사이트에서 dio 패키지를 디펜던시 코드를 가져와서 pubspec.yaml 파일에 의존성을 추가하고 pub get을 실행하여 패키지를 설치했습니다.
dependencies:
flutter:
sdk: flutter
dio: ^5.7.0
2. Dio로 간단한 GET 요청 보내기
Dio를 사용하여 서버에서 데이터를 가져오는 간단한 예제를 만들어봅니다.
전체 코드 구조
- Dio 객체: HTTP 요청을 처리하는 클라이언트.
- _fetchTodos 메서드: 서버에서 데이터를 가져오는 비동기 함수.
- try-catch 문: 예외 처리를 통해 안정성을 높임.
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
body: HomePage(),
),
),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// 통신을 담당하는 클라언트 측 객체를 가져오자
Dio _dio = Dio();
@override
void initState() {
super.initState();
// 객체 실행시 한번 호출 메서드
_fetchTodos();
}
@override
Widget build(BuildContext context) {
return const Placeholder();
}
// 통신을 담당하는 메서드를 만들어 보자.
_fetchTodos() async {
// https://jsonplaceholder.typicode.com/todos/1
// 통신을 담당하는 코드를 기본적으로 예외처리을 꼭 넣자
try {
Response response =
await _dio.get('https://jsonplaceholder.typicode.com/todos/1');
print('HTTP status code : ${response.statusCode}');
print('서버측 전달한 데이터 : ${response.data}');
print(
'json 통신 후 dart 에서는 어떤 타입으로 변경 되었을까? : ${response.data.runtimeType}');
// Map 타입에 값을 출력하는 방법
print('-----------------------------------------------');
print('data-> title 값 확인 : ${response.data['title']}');
} catch (e) {
print('실행 시점 예외가 발생 했어요');
print(e.toString());
}
}
}
테스트 데이터는 아래의 링크에서 받아와 사용했습니다.
JSONPlaceholder - Free Fake REST API
{JSON} Placeholder Free fake and reliable API for testing and prototyping. Powered by JSON Server + LowDB. Serving ~3 billion requests each month.
jsonplaceholder.typicode.com
3. JSON 데이터를 Dart 객체로 변환하기
서버에서 받은 JSON 데이터를 Dart 객체로 변환하여 사용하면 더 간편합니다. 이를 위해 모델 클래스를 생성합니다.
- Todo 모델 클래스 만들기
class Todo {
int? userId;
int? id;
String? title;
bool? completed;
Todo({
required this.userId,
required this.id,
required this.title,
required this.completed,
});
// JSON 데이터를 Dart 객체로 변환하는 생성자
Todo.fromJson(Map<String, dynamic> json)
: userId = json['userId'],
id = json['id'],
title = json['title'],
completed = json['completed'];
@override
String toString() {
return 'Todo{userId: $userId, id: $id, title: $title, completed: $completed}';
}
}
- JSON 데이터를 객체로 변환하기
- _fetchTodos 메서드에서 가져온 데이터를 Todo 객체로 변환합니다.
Future<void> _fetchTodos() async {
try {
Response response =
await _dio.get('https://jsonplaceholder.typicode.com/todos/1');
print('HTTP 상태 코드: ${response.statusCode}');
print('서버 데이터: ${response.data}');
// JSON 데이터를 Dart 객체로 변환
Todo todo = Todo.fromJson(response.data);
print('변환된 Todo 객체: $todo');
} catch (e) {
print('에러 발생: $e');
}
}
4. 예외 처리와 데이터 출력
Dio는 HTTP 요청 실패, 네트워크 연결 문제 등 다양한 예외를 처리할 수 있습니다.
try-catch 블록을 사용하여 안정적인 네트워크 통신을 구현했습니다.
try {
Response response =
await _dio.get('https://jsonplaceholder.typicode.com/todos/1');
print('서버 데이터: ${response.data}');
} catch (e) {
print('에러 발생: $e');
}
실행결과
HTTP 상태 코드: 200
서버 데이터: {userId: 1, id: 1, title: delectus aut autem, completed: false}
변환된 Todo 객체: Todo{userId: 1, id: 1, title: delectus aut autem, completed: false}
전체 코드
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
body: HomePage(),
),
),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// 통신을 담당하는 클라언트 측 객체를 가져오자
Dio _dio = Dio();
@override
void initState() {
super.initState();
// 객체 실행시 한번 호출 메서드
_fetchTodos();
}
@override
Widget build(BuildContext context) {
return const Placeholder();
}
// 통신을 담당하는 메서드를 만들어 보자.
_fetchTodos() async {
// https://jsonplaceholder.typicode.com/todos/1
// 통신을 담당하는 코드를 기본적으로 예외처리을 꼭 넣자
try {
Response response =
await _dio.get('https://jsonplaceholder.typicode.com/todos/1');
print('HTTP status code : ${response.statusCode}');
print('서버측 전달한 데이터 : ${response.data}');
print(
'json 통신 후 dart 에서는 어떤 타입으로 변경 되었을까? : ${response.data.runtimeType}');
// Map 타입에 값을 출력하는 방법
print('-----------------------------------------------');
Todo todo1 = Todo.fromJson(response.data);
print("todo1 : ${todo1}");
print('-----------------------------------------------');
// Map 으로 들어온 데이터를 Todo 객체를 생성해서 상태 값을 담아 보시오
} catch (e) {
print('실행 시점 예외가 발생 했어요');
print(e.toString());
}
}
}
// dart
class Todo {
int? userId;
int? id;
String? title;
bool? completed;
Todo(
{required this.userId,
required this.id,
required this.title,
required this.completed});
// dart 생성자 -> 명명된 생성자
Todo.fromJson(Map<String, dynamic> json)
: userId = json['userId'],
id = json['id'],
title = json['title'],
completed = json['completed'];
@override
String toString() {
return 'Todo{userId: $userId, id: $id, title: $title, completed: $completed}';
}
}
이번 포스팅에서는 Flutter에서 Dio 패키지를 활용하여 REST API와 통신하는 방법을 배웠습니다.
Dio는 강력한 HTTP 클라이언트로, Flutter에서 효율적인 네트워크 요청을 처리할 수 있다고 합니다.
다음에도 Flutter 관련된 유용한 포스팅으로 돌아오도록 할게요~ 감사합니다.