import 'dart:convert';
import 'package:http/http.dart' as http;
class ApiService {
final String baseUrl = "https://webtoon-crawler.nomadcoders.workers.dev";
final String today = "today";
Future<List<WebtoonModel>> getTodaysToons() async {
List<WebtoonModel> webtoonInstances = [];
final url = Uri.parse('$baseUrl/$today');
final response = await http.get(url);
if (response.statusCode == 200) {
final List<dynamic> webtoons = jsonDecode(response.body);
for (var webtoon in webtoons) {
webtoonInstances.add(WebtoonModel.fromJson(webtoon));
}
return webtoonInstances;
}
throw Error();
}
class WebtoonModel {
final String title, thumb, id;
WebtoonModel.fromJson(Map<String, dynamic> json)
: title = json['title'],
thumb = json['thumb'],
id = json['id'];
}
이 Dart 코드는 웹툰 정보를 가져오고 처리하기 위한 두 가지 주요 클래스, ApiService
와 WebtoonModel
을 정의하고 있습니다. 각 클래스와 그들의 주요 기능을 자세히 살펴보겠습니다.
ApiService
클래스ApiService
클래스는 웹툰 데이터를 웹 서버로부터 비동기적으로 가져오는 역할을 수행합니다.
필드(Field):
baseUrl
: API의 기본 URL을 저장하는 문자열입니다. 이 URL은 웹툰 데이터를 가져오는 데 사용됩니다.today
: "오늘의 웹툰"을 나타내는 경로를 저장하는 문자열입니다. baseUrl
과 결합하여 최종 URL을 생성합니다.메서드(Method):
getTodaysToons
: 이 비동기 메서드는 웹 서버로부터 "오늘의 웹툰" 데이터를 가져옵니다.http.get
: http
패키지의 get
함수를 사용하여 HTTP GET 요청을 보냅니다.jsonDecode
를 통해 Dart 객체로 변환됩니다.WebtoonModel
의 인스턴스로 변환되어 webtoonInstances
리스트에 추가됩니다.Error()
를 던집니다.WebtoonModel
클래스WebtoonModel
클래스는 웹툰 데이터를 모델링하고, JSON 데이터를 이 모델의 인스턴스로 변환하는 데 사용됩니다.
필드(Field):
title
, thumb
, id
: 웹툰의 제목, 썸네일 URL, 고유 ID를 저장하는 문자열 필드입니다.생성자(Constructor):
WebtoonModel.fromJson
: JSON 데이터를 받아 WebtoonModel
의 인스턴스를 생성하는 팩토리 생성자입니다.json['title']
, json['thumb']
, json['id']
: JSON 객체에서 필요한 값을 추출하여 각 필드를 초기화합니다.ApiService
의 getTodaysToons
메서드가 호출됩니다.jsonDecode
를 통해 Dart 객체로 변환됩니다.WebtoonModel.fromJson
을 통해 WebtoonModel
의 인스턴스로 변환되어 webtoonInstances
리스트에 추가됩니다.이 코드는 Dart와 Flutter에서 흔히 사용되는 패턴을 따르고 있으며, API 호출과 JSON 데이터 처리의 기본적인 접근 방식을 보여줍니다. 데이터를 가져오고, 모델링하고, 화면에 표시하는 과정은 모바일 및 웹 애플리케이션 개발에서 매우 일반적입니다.
Dart에서 jsonDecode
메서드는 JSON 형식의 문자열을 Dart 객체로 변환하는 데 사용됩니다. 이는 dart:convert
라이브러리에 포함되어 있으며, JSON 형식의 데이터를 다루는 데 필수적인 기능입니다. jsonDecode
메서드에 대한 상세한 설명과 이 메서드가 ApiService
클래스에서 어떻게 사용되는지 살펴보겠습니다.
jsonDecode
메서드Map<String, dynamic>
, List<dynamic>
등이 됩니다.jsonDecode(String source)
형태로 사용됩니다. 여기서 source
는 JSON 형식의 문자열입니다.var data = jsonDecode('{"name": "John", "age": 30}');
이 코드는 JSON 문자열을 Dart의 Map
객체로 변환합니다.ApiService
클래스에서의 jsonDecode
사용getTodaysToons
메서드는 웹 서버로부터 웹툰 데이터를 JSON 형식으로 받아오고, 이를 Dart 객체로 변환해야 합니다.response.body
)은 JSON 형식의 문자열입니다. 이 문자열은 jsonDecode
를 사용하여 Dart 객체로 변환됩니다.final List<dynamic> webtoons = jsonDecode(response.body);
이 부분에서, 서버 응답은 JSON 배열로 가정되며, jsonDecode
를 통해 List<dynamic>
객체로 변환됩니다.WebtoonModel.fromJson
메서드를 통해 WebtoonModel
객체로 변환됩니다. 이 변환 과정은 WebtoonModel
클래스에 정의된 fromJson
팩토리 생성자를 사용합니다.fromJson
은 JSON 객체(여기서는 Map<String, dynamic>
)를 받아 WebtoonModel
의 인스턴스를 생성합니다.jsonDecode
메서드는 웹 API로부터 받은 JSON 형식의 데이터를 Dart 객체로 변환하는 데 중요한 역할을 합니다. ApiService
클래스에서 이 메서드는 웹툰 데이터를 서버로부터 가져와 WebtoonModel
객체의 리스트로 변환하는 핵심 단계에 사용됩니다. 이러한 처리 과정은 Dart에서 웹 서비스와의 통신에 자주 사용되는 패턴입니다.
Dart의 jsonDecode
메서드는 JavaScript의 JSON.parse
메서드와 유사한 역할을 합니다. 두 메서드 모두 JSON 형식의 문자열을 해당 언어에서 사용 가능한 객체 형태로 변환하는 기능을 제공합니다. 간단히 비교해보면:
JavaScript의 JSON.parse
:
let obj = JSON.parse('{"name": "John", "age": 30}');
obj
는 JavaScript 객체가 되며, obj.name
과 obj.age
로 접근 가능합니다.Dart의 jsonDecode
:
Map<String, dynamic>
또는 List<dynamic>
타입의 객체를 생성합니다.var data = jsonDecode('{"name": "John", "age": 30}');
data
는 Dart의 Map
객체가 되며, data['name']
과 data['age']
로 접근 가능합니다.두 메서드 모두 JSON 데이터를 다룰 때 필수적이며, 웹 개발에서 자주 사용되는 기능입니다. JSON 형식은 데이터 교환의 표준 포맷으로 널리 사용되기 때문에, 이러한 변환 메서드는 다양한 프로그래밍 언어에서 제공됩니다.
Uri.parse
메서드는 Dart에서 중요한 역할을 하는 메서드 중 하나로, 문자열 형태의 URL 또는 URI를 Uri
객체로 변환하는 데 사용됩니다. 이 메서드는 Dart의 Uri
클래스에 정의되어 있으며, 네트워킹 및 웹 요청을 처리할 때 매우 유용합니다.
Uri.parse
메서드의 기본적인 특징과 작동 방식Uri
객체로 파싱합니다.Uri.parse(String uriString)
형태로 사용됩니다. 여기서 uriString
은 파싱할 URL 또는 URI를 나타내는 문자열입니다.Uri
타입의 객체를 반환합니다. Uri
객체는 URL의 다양한 구성 요소(스키마, 호스트, 경로, 쿼리 매개변수 등)에 쉽게 접근할 수 있게 해줍니다.FormatException
이 발생할 수 있습니다. 이러한 경우를 처리하기 위해 try-catch 블록을 사용할 수 있습니다.var uri = Uri.parse('https://example.com/path?query=example');
print(uri.scheme); // 'https'
print(uri.host); // 'example.com'
print(uri.path); // '/path'
print(uri.query); // 'query=example'
Uri
객체로 변환되어야 합니다. http
패키지 등에서 HTTP 요청을 보낼 때 URL 문자열 대신 Uri
객체를 사용합니다.Uri
객체를 사용하면 URL의 구성 요소에 쉽게 접근하고, 수정하거나 분석할 수 있습니다.Uri
객체를 사용하여 URL을 생성하면, 특수 문자를 적절히 인코딩하고, URL 구조를 올바르게 유지할 수 있습니다.Uri.parse
메서드는 Dart에서 URL과 URI를 처리하는 기본적이고 중요한 수단입니다. 이를 통해 네트워킹 요청, URL 분석 및 조작 등 다양한 작업을 보다 안전하고 효율적으로 수행할 수 있습니다.
Dart에서 import 'package:...' as http;
형태로 as
키워드를 사용하는 것은, 해당 패키지를 별칭(alias)으로 가져오기 위함입니다. 이러한 방식은 특히 다음과 같은 상황에서 유용합니다:
다른 패키지들이 동일한 이름의 클래스나 함수를 제공할 때, as
키워드를 사용하여 각 패키지에 대한 명확한 별칭을 지정함으로써 이름 충돌을 방지할 수 있습니다.
패키지에 별칭을 부여함으로써, 코드를 읽는 사람이 해당 패키지에서 제공하는 클래스나 함수를 쉽게 식별할 수 있게 합니다. 특히, 여러 패키지를 동시에 사용할 때 이 방법이 매우 유용합니다.
특정 패키지에 짧고 기억하기 쉬운 별칭을 부여함으로써, 코드를 작성할 때 해당 패키지의 기능을 더 빠르고 쉽게 접근할 수 있습니다.
http
패키지의 경우, 다음과 같은 이유로 as http
를 사용합니다:
import 'package:http/http.dart' as http;
void main() async {
var response = await http.get(Uri.parse('https://example.com'));
print(response.body);
}
http.get
처럼 사용함으로써, 이 코드가 http
패키지의 get
함수를 사용하고 있음을 명확하게 합니다.get
함수를 제공한다면, http.get
과 같은 형태로 사용함으로써 어떤 get
함수인지 명확히 구분할 수 있습니다.따라서, as http
를 사용하는 것은 코드의 명확성과 유지보수성을 높이는 좋은 방법입니다.
Dart에서 생성자 내에서 this
키워드를 생략하는 것은 흔히 발생하는 상황입니다. this
키워드는 클래스의 현재 인스턴스를 가리키며, 주로 클래스의 필드와 생성자의 매개변수 이름이 같을 때 혼동을 방지하기 위해 사용됩니다. 하지만, 생성자의 매개변수 이름과 클래스 필드의 이름이 다를 경우 this
키워드를 생략할 수 있습니다.
WebtoonModel.fromJson(Map<String, dynamic> json)
생성자에서 this
를 생략한 이유는 다음과 같습니다:
매개변수와 필드 이름의 차이: 이 생성자에서는 매개변수 json
과 클래스 필드 title
, thumb
, id
사이에 이름이 다릅니다. 이 경우, 클래스 필드에 접근할 때 this
키워드를 사용하지 않아도 혼동의 여지가 없습니다.
명확한 범위 구분: json['title']
, json['thumb']
, json['id']
는 json
매개변수에서 특정 키에 해당하는 값을 의미합니다. 여기서 json
은 메서드 매개변수이므로 this
를 사용할 필요가 없습니다.
this
사용 예시:class WebtoonModel {
String title;
String thumb;
String id;
WebtoonModel({this.title, this.thumb, this.id});
}
이 예시에서는 생성자 매개변수와 클래스 필드가 같은 이름(title
, thumb
, id
)을 가지므로 this.title
, this.thumb
, this.id
형태로 사용합니다.
WebtoonModel.fromJson
생성자에서 this
를 생략한 것은 매개변수와 클래스 필드 간의 이름 차이가 명확하기 때문입니다. 이로 인해 코드가 더 간결해지고, 의도가 명확해집니다. Dart에서는 이러한 방식이 일반적이며, 코드의 가독성을 높이는 데 도움이 됩니다.