Retrofit
다양한 HTTP 메소드(GET, PUT, POST 등)와 관련된 어노테이션을 활용할 수 있으며, 요청 헤더와 같은 HTTP 기능을 다루는 어노테이션도 존재합니다. 무엇보다 Retrofit은 API 엔드포인트에 필요한 파라미터를 관리하는 데 큰 도움을 주고,이로 인해 요청 파라미터를 보다 간편하게 처리하여, 코드의 가독성과 유지 보수성을 향상시키는 데 도움이 된다.
dependencies:
flutter:
sdk: flutter
dio:
json_annotation:
retrofit:
dev_dependencies:
flutter_test:
sdk: flutter
retrofit_generator:
build_runner:
json_serializable:
Retrofit을 사용하기 위해서는 추가할 것이 dio,retrofit,retrofit_generator,build_runner가 필요하고 추가로 fromJson , toJson을 위하여 json_serialize,json_annotaion이 필요하다.
retrofit을 사용하지 않았을때와 사용했을때의 코드를 통해 비교해 보려고 한다.
api는 개발자들이 웹 및 모바일 애플리케이션을 테스트하고 개발할 때 사용할 수 있는 무료 온라인 RESTful API 서비스인 https://jsonplaceholder.typicode.com/라는곳에서 아래 데이터를 불러올것이다.
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
},
{
"userId": 1,
"id": 2,
"title": "qui est esse",
"body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"
},
{
"userId": 1,
"id": 3,
"title": "ea molestias quasi exercitationem repellat qui ipsa sit aut",
"body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut"
},
{
"userId": 1,
"id": 4,
"title": "eum et est occaecati",
"body": "ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit"
},
{
"userId": 1,
"id": 5,
"title": "nesciunt quas odio",
"body": "repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque"
},
{
"userId": 1,
"id": 6,
"title": "dolorem eum magni eos aperiam quia",
"body": "ut aspernatur corporis harum nihil quis provident sequi\nmollitia nobis aliquid molestiae\nperspiciatis et ea nemo ab reprehenderit accusantium quas\nvoluptate dolores velit et doloremque molestiae"
},
{
"userId": 1,
"id": 7,
"title": "magnam facilis autem",
"body": "dolore placeat quibusdam ea quo vitae\nmagni quis enim qui quis quo nemo aut saepe\nquidem repellat excepturi ut quia\nsunt ut sequi eos ea sed quas"
},
{
"userId": 1,
"id": 8,
"title": "dolorem dolore est ipsam",
"body": "dignissimos aperiam dolorem qui eum\nfacilis quibusdam animi sint suscipit qui sint possimus cum\nquaerat magni maiores excepturi\nipsam ut commodi dolor voluptatum modi aut vitae"
},
{
"userId": 1,
"id": 9,
"title": "nesciunt iure omnis dolorem tempora et accusantium",
"body": "consectetur animi nesciunt iure dolore\nenim quia ad\nveniam autem ut quam aut nobis\net est aut quod aut provident voluptas autem voluptas"
},
{
"userId": 1,
"id": 10,
"title": "optio molestias id quia eum",
"body": "quo et expedita modi cum officia vel magni\ndoloribus qui repudiandae\nvero nisi sit\nquos veniam quod sed accusamus veritatis error"
}
]
우선 두방법에서 사용할 JsonSerializable을 이용한 데이터 모델이다.
import 'package:freezed_annotation/freezed_annotation.dart';
part 'retrofit_sample_model.g.dart';
@JsonSerializable()
class RetrofitSampleModel {
final int userId;
final int id;
final String title;
final String body;
RetrofitSampleModel({
required this.userId,
required this.id,
required this.title,
required this.body,
});
factory RetrofitSampleModel.fromJson(Map<String, dynamic> json) =>
_$RetrofitSampleModelFromJson(json);
}
우선 retrofit을 사용하지 않고 dio만을 사용하여 api로 데이터를 받아온 코드이다.
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_practice/src/default_layout_widget.dart';
import 'package:flutter_practice/src/retrofit/retrofit_sample_model.dart';
class DefaultScreen extends StatelessWidget {
const DefaultScreen({super.key});
Future<List> getData() async {
final dio = Dio();
final resp = await dio.get(
'https://jsonplaceholder.typicode.com/posts',
queryParameters: {
'_page': 1,
'_limit': 10,
},
);
return resp.data;
}
@override
Widget build(BuildContext context) {
return DefaultLayoutWidget(
child: FutureBuilder<List>(
future: getData(),
builder: (context, AsyncSnapshot<List> snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return ListView.separated(
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int index) {
final item = snapshot.data![index];
final pItem = RetrofitSampleModel.fromJson(item);
return Row(
// mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('${pItem.id}'),
const SizedBox(
width: 10,
),
Expanded(child: Text(pItem.title)),
],
);
},
separatorBuilder: (BuildContext context, int index) {
return const SizedBox(
height: 20,
);
},
);
}),
);
}
}
이번에는 retrofit을 사용한 코드이다. 우선 retrofit의 기능들을 사용하기 위한 추상 클래스가 필요하다.
이렇게 추상 클래스를 사용하면 메서드를 호출함으로써 각각의 API 요청을 설정할 수 있고, 더 나아가 Retrofit은 응답 데이터를 자동으로 모델 객체로 변환해주기 때문에 개발자들에게 상당한 편의를 제공한다.
import 'package:dio/dio.dart';
import 'package:flutter_practice/src/retrofit/retrofit_sample_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:retrofit/http.dart';
part 'common_repository.g.dart';
@RestApi(baseUrl: 'https://jsonplaceholder.typicode.com')
abstract class CommonRepository {
factory CommonRepository(Dio dio, {String baseUrl}) = _CommonRepository;
@GET("/posts")
Future<List<RetrofitSampleModel>> getData(
@Query("_page") int page,
@Query("_limit") int limit,
);
}
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_practice/src/default_layout_widget.dart';
import 'package:flutter_practice/src/retrofit/common_repository.dart';
import 'package:flutter_practice/src/retrofit/retrofit_sample_model.dart';
class RetrofitScreen extends StatelessWidget {
const RetrofitScreen({super.key});
Future<List<RetrofitSampleModel>> getRepositoryData() async {
final dio = Dio();
final repository = CommonRepository(dio);
return repository.getData(1, 10);
}
@override
Widget build(BuildContext context) {
return DefaultLayoutWidget(
child: FutureBuilder<List<RetrofitSampleModel>>(
future: getRepositoryData(),
builder: (BuildContext context,
AsyncSnapshot<List<RetrofitSampleModel>> snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return ListView.separated(
itemBuilder: (context, index) {
final pItem = snapshot.data![index];
return Row(
children: [
Text('${pItem.id}'),
const SizedBox(
width: 10,
),
Expanded(child: Text(pItem.title)),
],
);
},
separatorBuilder: (BuildContext context, int index) {
return const SizedBox(
height: 20,
);
},
itemCount: snapshot.data!.length);
},
),
);
}
}
retrofit에 대해 공부 해보니 낯선부분도 많았지만,http,dio를 이용하여 api통신을 할때 보다 api통신적인 부분에서도 편하고 , 자동으로 모델객체로 변경해주는 부분에서도 상당히 편리함을 느꼈다. 앞으로도 자주 사용할것 같다.
참고
https://velog.io/@leeeeeoy/flutter-Retrofit-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0-1