개발을 하다보면 제일 귀찮은 것이 Model(Type)을 작성하는 것이다. Quick type을 사용하면 간단하게 모델을 작성할 수 있다.
다음은 날씨 API 의 response를 model 로 바꾸는 예시 이다.
url : http://api.weatherapi.com/v1/current.json?key=[API_KEY]&q=London&aqi=no
reponse를 복사 하여 Quick type에서 변환시켜 보자.
오른쪽의 창에서 언어를 선택하여 변환할 수 있다. Dart 언어 뿐 아니라 다양한 언어를 지원하고, 옵션도 지원한다. Dart의 경우에는 Null safetyf를 지원한다.
또한, 창의 Copy Code 버튼으로 간단한게 복사도 가능하다.
// To parse this JSON data, do
//
// final weatherModel = weatherModelFromJson(jsonString);
import 'dart:convert';
WeatherModel weatherModelFromJson(String str) => WeatherModel.fromJson(json.decode(str));
String weatherModelToJson(WeatherModel data) => json.encode(data.toJson());
class WeatherModel {
WeatherModel({
this.location,
this.current,
});
Location? location;
Current? current;
factory WeatherModel.fromJson(Map<String, dynamic> json) => WeatherModel(
location: json["location"] == null ? null : Location.fromJson(json["location"]),
current: json["current"] == null ? null : Current.fromJson(json["current"]),
);
Map<String, dynamic> toJson() => {
"location": location?.toJson(),
"current": current?.toJson(),
};
}
class Current {
Current({
this.lastUpdatedEpoch,
this.lastUpdated,
this.tempC,
this.tempF,
this.isDay,
this.condition,
this.windMph,
this.windKph,
this.windDegree,
this.windDir,
this.pressureMb,
this.pressureIn,
this.precipMm,
this.precipIn,
this.humidity,
this.cloud,
this.feelslikeC,
this.feelslikeF,
this.visKm,
this.visMiles,
this.uv,
this.gustMph,
this.gustKph,
});
int? lastUpdatedEpoch;
String? lastUpdated;
int? tempC;
double? tempF;
int? isDay;
Condition? condition;
double? windMph;
double? windKph;
int? windDegree;
String? windDir;
int? pressureMb;
double? pressureIn;
int? precipMm;
int? precipIn;
int? humidity;
int? cloud;
int? feelslikeC;
double? feelslikeF;
int? visKm;
int? visMiles;
int? uv;
double? gustMph;
double? gustKph;
factory Current.fromJson(Map<String, dynamic> json) => Current(
lastUpdatedEpoch: json["last_updated_epoch"],
lastUpdated: json["last_updated"],
tempC: json["temp_c"],
tempF: json["temp_f"]?.toDouble(),
isDay: json["is_day"],
condition: json["condition"] == null ? null : Condition.fromJson(json["condition"]),
windMph: json["wind_mph"]?.toDouble(),
windKph: json["wind_kph"]?.toDouble(),
windDegree: json["wind_degree"],
windDir: json["wind_dir"],
pressureMb: json["pressure_mb"],
pressureIn: json["pressure_in"]?.toDouble(),
precipMm: json["precip_mm"],
precipIn: json["precip_in"],
humidity: json["humidity"],
cloud: json["cloud"],
feelslikeC: json["feelslike_c"],
feelslikeF: json["feelslike_f"]?.toDouble(),
visKm: json["vis_km"],
visMiles: json["vis_miles"],
uv: json["uv"],
gustMph: json["gust_mph"]?.toDouble(),
gustKph: json["gust_kph"]?.toDouble(),
);
Map<String, dynamic> toJson() => {
"last_updated_epoch": lastUpdatedEpoch,
"last_updated": lastUpdated,
"temp_c": tempC,
"temp_f": tempF,
"is_day": isDay,
"condition": condition?.toJson(),
"wind_mph": windMph,
"wind_kph": windKph,
"wind_degree": windDegree,
"wind_dir": windDir,
"pressure_mb": pressureMb,
"pressure_in": pressureIn,
"precip_mm": precipMm,
"precip_in": precipIn,
"humidity": humidity,
"cloud": cloud,
"feelslike_c": feelslikeC,
"feelslike_f": feelslikeF,
"vis_km": visKm,
"vis_miles": visMiles,
"uv": uv,
"gust_mph": gustMph,
"gust_kph": gustKph,
};
}
class Condition {
Condition({
this.text,
this.icon,
this.code,
});
String? text;
String? icon;
int? code;
factory Condition.fromJson(Map<String, dynamic> json) => Condition(
text: json["text"],
icon: json["icon"],
code: json["code"],
);
Map<String, dynamic> toJson() => {
"text": text,
"icon": icon,
"code": code,
};
}
class Location {
Location({
this.name,
this.region,
this.country,
this.lat,
this.lon,
this.tzId,
this.localtimeEpoch,
this.localtime,
});
String? name;
String? region;
String? country;
double? lat;
double? lon;
String? tzId;
int? localtimeEpoch;
String? localtime;
factory Location.fromJson(Map<String, dynamic> json) => Location(
name: json["name"],
region: json["region"],
country: json["country"],
lat: json["lat"]?.toDouble(),
lon: json["lon"]?.toDouble(),
tzId: json["tz_id"],
localtimeEpoch: json["localtime_epoch"],
localtime: json["localtime"],
);
Map<String, dynamic> toJson() => {
"name": name,
"region": region,
"country": country,
"lat": lat,
"lon": lon,
"tz_id": tzId,
"localtime_epoch": localtimeEpoch,
"localtime": localtime,
};
}
? 를 남발하게 되면 코딩할때 애로사항이 발생한다.(사용할 때 마다 일일히 널 체크를.... ㄷㄷㄷㄷ) 차라리 required 로 모두 변환시키고 서버에서 받은 값중에 null 값이 있다면 디폴트 값으로 변경해주는 것이 편안하다.
In Dart
A ?? B 는 'A가 null 값이면 B를 값으로 가진다'는 의미이다.
A != null ? B:C 는 'A가 null이 아니면 B값, A가 null이면 C값을 가진다'는 의미이다.
이를 활용하여 위의 결과를 예시로 보여주겠다.
//class location
class LocationModel {
LocationModel({
required this.name,
required this.region,
required this.country,
required this.lat,
required this.lon,
required this.tzId,
required this.localtimeEpoch,
required this.localtime,
});
String name;
String region;
String country;
double lat;
double lon;
String tzId;
int localtimeEpoch;
String localtime;
factory LocationModel.fromJson(Map<String, dynamic> json) => LocationModel(
name: json["name"] ?? '',
region: json["region"] ?? '',
country: json["country"] ?? '',
lat: json["lat"] != null ? json["lat"].toDouble() : 0,
lon: json["lon"] != null ? json["lon"].toDouble() : 0,
tzId: json["tz_id"] ?? '',
localtimeEpoch: json["localtime_epoch"] ?? 0,
localtime: json["localtime"] ?? '',
);
Map<String, dynamic> toJson() => {
"name": name,
"region": region,
"country": country,
"lat": lat,
"lon": lon,
"tz_id": tzId,
"localtime_epoch": localtimeEpoch,
"localtime": localtime,
};
}
이렇게 처리하면 서버에서 null값을 보내줄 때에도 문제없이 사용할 수 있다.