How to deserialize complex json in Flutter? - json

I have such json from the OpenWeatherMapApi:
{
"coord": {
"lon": 73.9352,
"lat": 40.7306
},
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04d"
}
],
"base": "stations",
"main": {
"temp": 287.27,
"feels_like": 285.57,
"temp_min": 287.27,
"temp_max": 287.27,
"pressure": 1008,
"humidity": 32,
"sea_level": 1008,
"grnd_level": 695
},
"visibility": 10000,
"wind": {
"speed": 3.67,
"deg": 289,
"gust": 5.14
},
"clouds": {
"all": 87
},
"dt": 1659340567,
"sys": {
"country": "KG",
"sunrise": 1659312024,
"sunset": 1659363640
},
"timezone": 21600,
"id": 8145969,
"name": "Kara-Kulja",
"cod": 200
}
And I used such sample to work with json. But in the tutorial as you can see very simple json was used. But for example if I want to get:
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04d"
}
]
or:
"coord": {
"lon": 73.9352,
"lat": 40.7306
}
what I have to do? For example I tried to get weather in such way:
class weatherModel {
int id;
String main, description, icon;
weatherModel(
{required this.id, required this.main, required this.description, required this.icon})
factory weatherModel.fromJson(Map<String, dynamic> json) {
return weatherModel(
id: json['id'],
main: json["main"],
description: json["description"],
icon: json["icon"],
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'main': main,
'description': description,
'icon': icon,
};
}
}
class Forecast {
List<weatherModel> weather;
Forecast({required this.weather});
factory Forecast.fromJson(Map<String, dynamic> json) {
return Forecast(
weather: json['weather'],
);
}
Map<String, dynamic> toJson() {
return {
'weather': weather,
};
}
}
but I got such error:
when in comparison class Forecast doesn't have such error. In the clean android development with kotlin I have to declare all fields of this json and then I will be able to get it after getting some response. But in the Flutter I have to create separate models for each complex field or how it has to be? Because then I will need to declare in the Future my model class:
#RestApi(baseUrl: "https://api.openweathermap.org/data/2.5/")
abstract class ApiClient {
factory ApiClient(Dio dio, {String baseUrl}) = _ApiClient;
#GET("weather?lat={lat}&lon={lon}&appid={appid}")
Future<ResponseData> getUsers(#Path("lat") String lat,
#Path("lon") String lon, #Path("appid") String appid);
}
Maybe I did something wrong only because I'm very new in Flutter and in this mobile development.
update
working with the result of deserialization:
#JsonSerializable()
class Forecast {
List<WeatherModel> weather;
Forecast({required this.weather});
factory Forecast.fromJson(Map<String, dynamic> json) =>
_$ForecastFromJson(json);
Map<String, dynamic> toJson() => _$ForecastToJson(this);
}
#JsonSerializable()
class ResponseData {
int code;
dynamic meta;
List<dynamic> data;
ResponseData({required this.code, this.meta, required this.data});
factory ResponseData.fromJson(Map<String, dynamic> json) =>
_$ResponseDataFromJson(json);
Map<String, dynamic> toJson() => _$ResponseDataToJson(this);
}
then I use ResponseData in the api call class.

You can use your data like this
class WeatherModel {
Coord? coord;
List<Weather>? weather;
String? base;
Main? main;
int? visibility;
Wind? wind;
Clouds? clouds;
int? dt;
Sys? sys;
int? timezone;
int? id;
String? name;
int? cod;
WeatherModel(
{this.coord,
this.weather,
this.base,
this.main,
this.visibility,
this.wind,
this.clouds,
this.dt,
this.sys,
this.timezone,
this.id,
this.name,
this.cod});
WeatherModel.fromJson(Map<String, dynamic> json) {
coord = json['coord'] != null ? new Coord.fromJson(json['coord']) : null;
if (json['weather'] != null) {
weather = <Weather>[];
json['weather'].forEach((v) {
weather!.add(new Weather.fromJson(v));
});
}
base = json['base'];
main = json['main'] != null ? new Main.fromJson(json['main']) : null;
visibility = json['visibility'];
wind = json['wind'] != null ? new Wind.fromJson(json['wind']) : null;
clouds =
json['clouds'] != null ? new Clouds.fromJson(json['clouds']) : null;
dt = json['dt'];
sys = json['sys'] != null ? new Sys.fromJson(json['sys']) : null;
timezone = json['timezone'];
id = json['id'];
name = json['name'];
cod = json['cod'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.coord != null) {
data['coord'] = this.coord!.toJson();
}
if (this.weather != null) {
data['weather'] = this.weather!.map((v) => v.toJson()).toList();
}
data['base'] = this.base;
if (this.main != null) {
data['main'] = this.main!.toJson();
}
data['visibility'] = this.visibility;
if (this.wind != null) {
data['wind'] = this.wind!.toJson();
}
if (this.clouds != null) {
data['clouds'] = this.clouds!.toJson();
}
data['dt'] = this.dt;
if (this.sys != null) {
data['sys'] = this.sys!.toJson();
}
data['timezone'] = this.timezone;
data['id'] = this.id;
data['name'] = this.name;
data['cod'] = this.cod;
return data;
}
}
class Coord {
double? lon;
double? lat;
Coord({this.lon, this.lat});
Coord.fromJson(Map<String, dynamic> json) {
lon = json['lon'];
lat = json['lat'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['lon'] = this.lon;
data['lat'] = this.lat;
return data;
}
}
class Weather {
int? id;
String? main;
String? description;
String? icon;
Weather({this.id, this.main, this.description, this.icon});
Weather.fromJson(Map<String, dynamic> json) {
id = json['id'];
main = json['main'];
description = json['description'];
icon = json['icon'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['main'] = this.main;
data['description'] = this.description;
data['icon'] = this.icon;
return data;
}
}
class Main {
double? temp;
double? feelsLike;
double? tempMin;
double? tempMax;
int? pressure;
int? humidity;
int? seaLevel;
int? grndLevel;
Main(
{this.temp,
this.feelsLike,
this.tempMin,
this.tempMax,
this.pressure,
this.humidity,
this.seaLevel,
this.grndLevel});
Main.fromJson(Map<String, dynamic> json) {
temp = json['temp'];
feelsLike = json['feels_like'];
tempMin = json['temp_min'];
tempMax = json['temp_max'];
pressure = json['pressure'];
humidity = json['humidity'];
seaLevel = json['sea_level'];
grndLevel = json['grnd_level'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['temp'] = this.temp;
data['feels_like'] = this.feelsLike;
data['temp_min'] = this.tempMin;
data['temp_max'] = this.tempMax;
data['pressure'] = this.pressure;
data['humidity'] = this.humidity;
data['sea_level'] = this.seaLevel;
data['grnd_level'] = this.grndLevel;
return data;
}
}
class Wind {
double? speed;
int? deg;
double? gust;
Wind({this.speed, this.deg, this.gust});
Wind.fromJson(Map<String, dynamic> json) {
speed = json['speed'];
deg = json['deg'];
gust = json['gust'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['speed'] = this.speed;
data['deg'] = this.deg;
data['gust'] = this.gust;
return data;
}
}
class Clouds {
int? all;
Clouds({this.all});
Clouds.fromJson(Map<String, dynamic> json) {
all = json['all'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['all'] = this.all;
return data;
}
}
class Sys {
String? country;
int? sunrise;
int? sunset;
Sys({this.country, this.sunrise, this.sunset});
Sys.fromJson(Map<String, dynamic> json) {
country = json['country'];
sunrise = json['sunrise'];
sunset = json['sunset'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['country'] = this.country;
data['sunrise'] = this.sunrise;
data['sunset'] = this.sunset;
return data;
}
}
And if you make it using factory Constructor you can use
// 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.coord,
this.weather,
this.base,
this.main,
this.visibility,
this.wind,
this.clouds,
this.dt,
this.sys,
this.timezone,
this.id,
this.name,
this.cod,
});
Coord coord;
List<Weather> weather;
String base;
Main main;
int visibility;
Wind wind;
Clouds clouds;
int dt;
Sys sys;
int timezone;
int id;
String name;
int cod;
factory WeatherModel.fromJson(Map<String, dynamic> json) => WeatherModel(
coord: Coord.fromJson(json["coord"]),
weather: List<Weather>.from(json["weather"].map((x) => Weather.fromJson(x))),
base: json["base"],
main: Main.fromJson(json["main"]),
visibility: json["visibility"],
wind: Wind.fromJson(json["wind"]),
clouds: Clouds.fromJson(json["clouds"]),
dt: json["dt"],
sys: Sys.fromJson(json["sys"]),
timezone: json["timezone"],
id: json["id"],
name: json["name"],
cod: json["cod"],
);
Map<String, dynamic> toJson() => {
"coord": coord.toJson(),
"weather": List<dynamic>.from(weather.map((x) => x.toJson())),
"base": base,
"main": main.toJson(),
"visibility": visibility,
"wind": wind.toJson(),
"clouds": clouds.toJson(),
"dt": dt,
"sys": sys.toJson(),
"timezone": timezone,
"id": id,
"name": name,
"cod": cod,
};
}
class Clouds {
Clouds({
this.all,
});
int all;
factory Clouds.fromJson(Map<String, dynamic> json) => Clouds(
all: json["all"],
);
Map<String, dynamic> toJson() => {
"all": all,
};
}
class Coord {
Coord({
this.lon,
this.lat,
});
double lon;
double lat;
factory Coord.fromJson(Map<String, dynamic> json) => Coord(
lon: json["lon"].toDouble(),
lat: json["lat"].toDouble(),
);
Map<String, dynamic> toJson() => {
"lon": lon,
"lat": lat,
};
}
class Main {
Main({
this.temp,
this.feelsLike,
this.tempMin,
this.tempMax,
this.pressure,
this.humidity,
this.seaLevel,
this.grndLevel,
});
double temp;
double feelsLike;
double tempMin;
double tempMax;
int pressure;
int humidity;
int seaLevel;
int grndLevel;
factory Main.fromJson(Map<String, dynamic> json) => Main(
temp: json["temp"].toDouble(),
feelsLike: json["feels_like"].toDouble(),
tempMin: json["temp_min"].toDouble(),
tempMax: json["temp_max"].toDouble(),
pressure: json["pressure"],
humidity: json["humidity"],
seaLevel: json["sea_level"],
grndLevel: json["grnd_level"],
);
Map<String, dynamic> toJson() => {
"temp": temp,
"feels_like": feelsLike,
"temp_min": tempMin,
"temp_max": tempMax,
"pressure": pressure,
"humidity": humidity,
"sea_level": seaLevel,
"grnd_level": grndLevel,
};
}
class Sys {
Sys({
this.country,
this.sunrise,
this.sunset,
});
String country;
int sunrise;
int sunset;
factory Sys.fromJson(Map<String, dynamic> json) => Sys(
country: json["country"],
sunrise: json["sunrise"],
sunset: json["sunset"],
);
Map<String, dynamic> toJson() => {
"country": country,
"sunrise": sunrise,
"sunset": sunset,
};
}
class Weather {
Weather({
this.id,
this.main,
this.description,
this.icon,
});
int id;
String main;
String description;
String icon;
factory Weather.fromJson(Map<String, dynamic> json) => Weather(
id: json["id"],
main: json["main"],
description: json["description"],
icon: json["icon"],
);
Map<String, dynamic> toJson() => {
"id": id,
"main": main,
"description": description,
"icon": icon,
};
}
class Wind {
Wind({
this.speed,
this.deg,
this.gust,
});
double speed;
int deg;
double gust;
factory Wind.fromJson(Map<String, dynamic> json) => Wind(
speed: json["speed"].toDouble(),
deg: json["deg"],
gust: json["gust"].toDouble(),
);
Map<String, dynamic> toJson() => {
"speed": speed,
"deg": deg,
"gust": gust,
};
}

You're missing ";" in this code line. This is why you're having that error.
weatherModel(
{required this.id, required this.main, required this.description, required this.icon}); //here
Additional advice: It's recommended to have Uppercase starting name when it comes to models
weatherModel-> WeatherModel

Related

Trying to convert Json to Dart but its giving me 3 errors

I am trying to convert JSON response to dart but over 3 error. I convert the Json from online website https://javiercbk.github.io/json_to_dart/
the errors says : The method 'toJson' isn't defined for the type 'List'.
Try correcting the name to the name of an existing method, or defining a method named 'toJson'.
the code :
class RedZoneModel {
bool? status;
List<Data>? data;
RedZoneModel({this.status, this.data});
RedZoneModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
if (json['data'] != null) {
data = <Data>[];
json['data'].forEach((v) { data!.add(new Data.fromJson(v)); });
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
if (this.data != null) {
data['data'] = this.data!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Data {
int? id;
String? areaName;
Geojson? geojson;
String? createdAt;
String? updatedAt;
Data({this.id, this.areaName, this.geojson, this.createdAt, this.updatedAt});
Data.fromJson(Map<String, dynamic> json) {
id = json['id'];
areaName = json['area_name'];
geojson = json['geojson'] != null ? new Geojson.fromJson(json['geojson']) : null;
createdAt = json['created_at'];
updatedAt = json['updated_at'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['area_name'] = this.areaName;
if (this.geojson != null) {
data['geojson'] = this.geojson!.toJson();
}
data['created_at'] = this.createdAt;
data['updated_at'] = this.updatedAt;
return data;
}
}
class Geojson {
String? type;
List<List>? coordinates;
Geojson({this.type, this.coordinates});
Geojson.fromJson(Map<String, dynamic> json) {
type = json['type'];
if (json['coordinates'] != null) {
coordinates = <List>[];
json['coordinates'].forEach((v) { coordinates!.add(new List.fromJson(v)); }); // ! Error at List.fromJson(v)
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['type'] = this.type;
if (this.coordinates != null) {
data['coordinates'] = this.coordinates!.map((v) => v.toJson()).toList(); // ! Error at v.toJson()
}
return data;
}
}
class Coordinates {
Coordinates({ }); // ! Error at Coordinates({ });
Coordinates.fromJson(Map<String, dynamic> json) {
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
return data;
}
}
and this is the response :
{
"status": true,
"data": [
{
"id": 8,
"area_name": "Surian",
"geojson": {
"type": "Polygon",
"coordinates": [
[
[
-1.2453052,
460.8429751
],
[
-1.2200768,
460.9066456
],
[
-1.2564606,
460.9423423
],
[
-1.2940451,
460.8711205
],
[
-1.2453052,
460.8429751
],
[
-1.2940451,
460.8711205
],
[
-1.2453052,
460.8429751
]
]
]
},
"created_at": "2022-08-29T14:30:10.000000Z",
"updated_at": "2022-12-19T18:30:10.000000Z"
},
{
"id": 13,
"area_name": "test edit",
"geojson": {
"type": "Polygon",
"coordinates": [
[
[
123,
123
],
[
123,
123
],
[
123,
123
],
[
123,
123
],
[
123,
123
]
]
]
},
"created_at": "2022-08-29T15:43:35.000000Z",
"updated_at": "2022-12-20T08:28:00.000000Z"
}
]
}
Anyone have any suggestion?
You shouldn't really use online generators that convert JSON to Dart objects.
Instead, learn about json and serialization. You can use dart packages such as freezed and json_serializable to generate the encoding boilerplate for your JSON response.
Here is sample json to Dart object converter for your json response above:
class Data {
const Data({
required this.id,
required this.area_name,
required this.geojson,
required this.created_at,
required this.updated_at,
});
factory Data.fromJson(Map<String, dynamic> json) => Data(
id: json['id'] as int,
area_name: json['area_name'] as String,
geojson: GeoJson.fromJson(json['geojson'] as Map<String, dynamic>),
created_at: DateTime.parse(json['created_at'] as String),
updated_at: DateTime.parse(json['updated_at'] as String),
);
final int id;
final String area_name;
final GeoJson geojson;
final DateTime created_at;
final DateTime updated_at;
}
class GeoJson {
const GeoJson({
required this.type,
required this.coordinates,
});
factory GeoJson.fromJson(Map<String, dynamic> json) => GeoJson(
type: json['type'] as String,
coordinates: (json['coordinates'] as List<dynamic>)
.map((e) => Polygon.fromJson(e as Map<String, dynamic>))
.toList(),
);
final String type;
final List<Polygon> coordinates;
}
class Polygon {
const Polygon({
required this.lat,
required this.lang,
});
/// Creates a Polygon from Json map
factory Polygon.fromJson(Map<String, dynamic> json) => Polygon(
lat: json['lat'] as num,
lang: json['lang'] as num,
);
final num lat;
final num lang;
}

How can i handle multiple data type for a same key from API in Flutter?

Let's explain my problem..
suppose have a json object like
from this picture i want to handle offer_price key
enter image description here
{
"product": [
{
"id": 1,
"price": 100.0,
"offer_price": 40
},
{
"id": 2,
"price": 80.0,
"offer_price": 10.50
},
{
"id": 3,
"price": 200.0,
"offer_price": "40.5"
},
{
"id": 4,
"price": 100.0,
"offer_price": null,
}
]
}
class Product {
int? id;
int? price;
// if you need the value as String
String? offerPriceAsString;
// Value as a double
double? offerPrice;
Product({this.id, this.price, this.offerPrice});
Product.fromJson(Map<String, dynamic> json) {
id = json['id'];
price = json['price'];
double.parse("1.0");
// Any value to String
offerPriceAsString = json['offer_price'].toString();
// String to Double
offerPrice = double.parse(json['offer_price'].toString());
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['price'] = price;
data['offer_price'] = offerPrice;
return data;
}
}
In the dart data model for offer_price field make its datatype as dynamic via which you'll be able to have a dynamic data in it as run type. And while consuming this in any place just check the runtimeType of the variable and use it by type casting or just using it with .toString().
eg class:
class Products {
Products({this.product});
Products.fromJson(Map<String, dynamic> json) {
if (json['product'] != null) {
product = <Product>[];
json['product'].forEach((v) {
product!.add(Product.fromJson(v));
});
}
}
List<Product>? product;
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
if (this.product != null) {
data['product'] = this.product!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Product {
Product({this.id, this.price, this.offerPrice});
Product.fromJson(Map<String, dynamic> json) {
id = json['id'];
price = json['price'];
offerPrice = json['offer_price'];
}
int? id;
int? price;
dynamic? offerPrice;
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = this.id;
data['price'] = this.price;
data['offer_price'] = this.offerPrice;
return data;
}
}
For consuming it just try:
Products products = List<Products>[];
//assign products = Products.fromJson(jsonData);
//using
products[i].offerPrice == null
? "null"
: products[i].offerPrice.runtimeType == String
? products[i].offerPrice.toString()
: products[i].offerPrice.runtimeType == Int
? int.parse(products[i].offerPrice)
: products[i].offerPrice.runtimeType == Double
? double.parse(products[i].offerPrice)
: ""

snapshot.hasData returning false even though response.body has data [Flutter]

I am trying to get current weather info from OpenWeather and display the result in Text Widget after checking that there is data returned. However, that condtion (snapshot.hasData) is always returned as false and else condition (CircularProgressIndicator) is invoked.
Here is the FutureBuilder.
class WeatherPage extends StatefulWidget {
#override
State<WeatherPage> createState() => _WeatherPageState();
}
class _WeatherPageState extends State<WeatherPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder(
future: getCurrentWeather(),
builder: (context, snapshot) {
if (snapshot.hasData) {
WeatherModelCurrent weather =
snapshot.data as WeatherModelCurrent;
return weatherBox(weather);
} else {
return const CircularProgressIndicator();
}
},
),
),
);
}
here is the getCurrentWeather() function
Future getCurrentWeather() async {
WeatherModelCurrent? weather;
var url = Uri.parse(
"https://api.openweathermap.org/data/2.5/weather?q=Kathmandu&appid=82c7b99e2a8215351147f607592a3e63&units=metric");
var response = await http.get(url);
//response.body has the data returned by API call
print(response.body);
if (response.statusCode == 200) {
weather = WeatherModelCurrent.frommJson(jsonDecode(response.body));
} else {
print('error');
}
return weather;
}
and here is the model class
class WeatherModelCurrent {
double temp;
double feelslike;
double tempmin;
double tempmax;
String description;
WeatherModelCurrent(
{required this.temp,
required this.feelslike,
required this.tempmin,
required this.tempmax,
required this.description});
factory WeatherModelCurrent.frommJson(Map<String, dynamic> jsonn) {
return WeatherModelCurrent(
temp: jsonn['main']['temp'].toDouble(),
feelslike: jsonn['main']['feels_like'].toDouble(),
tempmin: jsonn['main']['temp_min'].toDouble(),
tempmax: jsonn['main']['temp_max'].toDouble(),
description: jsonn['weather']['description'],
);
}
}
Try & catch your getCurrentWeather code block, we can get the following exception:
flutter: exception type 'String' is not a subtype of type 'int' of 'index'
The response json is like:
{
"weather":[
{
"id":803,
"main":"Clouds",
"description":"broken clouds",
"icon":"04d"
}
],
}
Your code description: jsonn['weather']['description'] should be description: jsonn['weather'][0]['description'],
The error is occur because you parse your response.body in wrong class.
Try this model class
class WeatherModelCurrent {
WeatherModelCurrent({
this.coord,
this.weather,
this.base,
this.main,
this.visibility,
this.wind,
this.clouds,
this.dt,
this.sys,
this.timezone,
this.id,
this.name,
this.cod,
});
final Coord? coord;
final List<Weather>? weather;
final String? base;
final Main? main;
final int? visibility;
final Wind? wind;
final Clouds? clouds;
final int? dt;
final Sys? sys;
final int? timezone;
final int? id;
final String? name;
final int? cod;
factory WeatherModelCurrent.fromJson(Map<String, dynamic> json) => WeatherModelCurrent(
coord: Coord.fromJson(json["coord"]),
weather: List<Weather>.from(json["weather"].map((x) => Weather.fromJson(x))),
base: json["base"],
main: Main.fromJson(json["main"]),
visibility: json["visibility"],
wind: Wind.fromJson(json["wind"]),
clouds: Clouds.fromJson(json["clouds"]),
dt: json["dt"],
sys: Sys.fromJson(json["sys"]),
timezone: json["timezone"],
id: json["id"],
name: json["name"],
cod: json["cod"],
);
Map<String, dynamic> toJson() => {
"coord": coord!.toJson(),
"weather": List<dynamic>.from(weather!.map((x) => x.toJson())),
"base": base,
"main": main!.toJson(),
"visibility": visibility,
"wind": wind!.toJson(),
"clouds": clouds!.toJson(),
"dt": dt,
"sys": sys!.toJson(),
"timezone": timezone,
"id": id,
"name": name,
"cod": cod,
};
}
class Clouds {
Clouds({
this.all,
});
final int? all;
factory Clouds.fromJson(Map<String, dynamic> json) => Clouds(
all: json["all"],
);
Map<String, dynamic> toJson() => {
"all": all,
};
}
class Coord {
Coord({
this.lon,
this.lat,
});
final double? lon;
final double? lat;
factory Coord.fromJson(Map<String, dynamic> json) => Coord(
lon: json["lon"].toDouble(),
lat: json["lat"].toDouble(),
);
Map<String, dynamic> toJson() => {
"lon": lon,
"lat": lat,
};
}
class Main {
Main({
this.temp,
this.feelsLike,
this.tempMin,
this.tempMax,
this.pressure,
this.humidity,
});
final double? temp;
final double? feelsLike;
final double? tempMin;
final double? tempMax;
final int? pressure;
final int? humidity;
factory Main.fromJson(Map<String, dynamic> json) => Main(
temp: json["temp"].toDouble(),
feelsLike: json["feels_like"].toDouble(),
tempMin: json["temp_min"].toDouble(),
tempMax: json["temp_max"].toDouble(),
pressure: json["pressure"],
humidity: json["humidity"],
);
Map<String, dynamic> toJson() => {
"temp": temp,
"feels_like": feelsLike,
"temp_min": tempMin,
"temp_max": tempMax,
"pressure": pressure,
"humidity": humidity,
};
}
class Sys {
Sys({
this.type,
this.id,
this.country,
this.sunrise,
this.sunset,
});
final int? type;
final int? id;
final String? country;
final int? sunrise;
final int? sunset;
factory Sys.fromJson(Map<String, dynamic> json) => Sys(
type: json["type"],
id: json["id"],
country: json["country"],
sunrise: json["sunrise"],
sunset: json["sunset"],
);
Map<String, dynamic> toJson() => {
"type": type,
"id": id,
"country": country,
"sunrise": sunrise,
"sunset": sunset,
};
}
class Weather {
Weather({
this.id,
this.main,
this.description,
this.icon,
});
final int? id;
final String? main;
final String? description;
final String? icon;
factory Weather.fromJson(Map<String, dynamic> json) => Weather(
id: json["id"],
main: json["main"],
description: json["description"],
icon: json["icon"],
);
Map<String, dynamic> toJson() => {
"id": id,
"main": main,
"description": description,
"icon": icon,
};
}
class Wind {
Wind({
this.speed,
this.deg,
});
final double? speed;
final int? deg;
factory Wind.fromJson(Map<String, dynamic> json) => Wind(
speed: json["speed"].toDouble(),
deg: json["deg"],
);
Map<String, dynamic> toJson() => {
"speed": speed,
"deg": deg,
};
}

How to parse a complex JSON file in Flutter

I'm having a really complex JSON file to parse:
{
"adult": false,
"backdrop_url": "https://image.tmdb.org/t/p/w500/gLbBRyS7MBrmVUNce91Hmx9vzqI.jpg",
"belongs_to_collection": {
"id": 230,
"name": "The Godfather Collection",
"poster_url": "https://image.tmdb.org/t/p/w200/sSbkKCHtIEakht5rnEjrWeR2LLG.jpg",
"backdrop_url": "https://image.tmdb.org/t/p/w500/3WZTxpgscsmoUk81TuECXdFOD0R.jpg"
},
"budget": 13000000,
"genres": [
"Drama",
"Crime"
],
"homepage": null,
"id": 240,
"imdb_id": "tt0071562",
"original_language": "en",
"original_title": "The Godfather: Part II",
"overview": "In the continuing saga of the Corleone crime family, a young Vito Corleone grows up in Sicily and in 1910s New York. In the 1950s, Michael Corleone attempts to expand the family business into Las Vegas, Hollywood and Cuba.",
"popularity": 17.578,
"poster_url": "https://image.tmdb.org/t/p/w200/bVq65huQ8vHDd1a4Z37QtuyEvpA.jpg",
"production_companies": [
{
"id": 4,
"logo_url": "https://image.tmdb.org/t/p/w200/fycMZt242LVjagMByZOLUGbCvv3.png",
"name": "Paramount",
"origin_country": "US"
},
{
"id": 536,
"logo_url": null,
"name": "The Coppola Company",
"origin_country": ""
}
],
"production_countries": [
{
"iso_3166_1": "US",
"name": "United States of America"
}
],
"release_date": "1974-12-20",
"revenue": 102600000,
"runtime": 200,
"spoken_languages": [
{
"iso_639_1": "en",
"name": "English"
},
{
"iso_639_1": "it",
"name": "Italiano"
},
{
"iso_639_1": "la",
"name": "Latin"
},
{
"iso_639_1": "es",
"name": "EspaƱol"
}
],
"status": "Released",
"tagline": "I don't feel I have to wipe everybody out, Tom. Just my enemies.",
"title": "The Godfather: Part II",
"video": false,
"vote_average": 8.5,
"vote_count": 4794
}
And this is my class for parsing:
class movieDetails {
bool? adult;
String? backdropUrl;
Null? belongsToCollection;
int? budget;
List<String>? genres;
Null? homepage;
int? id;
String? imdbId;
String? originalLanguage;
String? originalTitle;
String? overview;
double? popularity;
String? posterUrl;
List<ProductionCompanies>? productionCompanies;
List<ProductionCountries>? productionCountries;
String? releaseDate;
int? revenue;
int? runtime;
List<SpokenLanguages>? spokenLanguages;
String? status;
String? tagline;
String? title;
bool? video;
double? voteAverage;
int? voteCount;
movieDetails(
{this.adult,
this.backdropUrl,
this.belongsToCollection,
this.budget,
this.genres,
this.homepage,
this.id,
this.imdbId,
this.originalLanguage,
this.originalTitle,
this.overview,
this.popularity,
this.posterUrl,
this.productionCompanies,
this.productionCountries,
this.releaseDate,
this.revenue,
this.runtime,
this.spokenLanguages,
this.status,
this.tagline,
this.title,
this.video,
this.voteAverage,
this.voteCount});
movieDetails.fromJson(Map<String, dynamic> json) {
adult = json['adult'];
backdropUrl = json['backdrop_url'];
belongsToCollection = json['belongs_to_collection'];
budget = json['budget'];
genres = json['genres'].cast<String>();
homepage = json['homepage'];
id = json['id'];
imdbId = json['imdb_id'];
originalLanguage = json['original_language'];
originalTitle = json['original_title'];
overview = json['overview'];
popularity = json['popularity'];
posterUrl = json['poster_url'];
if (json['production_companies'] != null) {
productionCompanies = <ProductionCompanies>[];
json['production_companies'].forEach((v) {
productionCompanies!.add(new ProductionCompanies.fromJson(v));
});
}
if (json['production_countries'] != null) {
productionCountries = <ProductionCountries>[];
json['production_countries'].forEach((v) {
productionCountries!.add(new ProductionCountries.fromJson(v));
});
}
releaseDate = json['release_date'];
revenue = json['revenue'];
runtime = json['runtime'];
if (json['spoken_languages'] != null) {
spokenLanguages = <SpokenLanguages>[];
json['spoken_languages'].forEach((v) {
spokenLanguages!.add(new SpokenLanguages.fromJson(v));
});
}
status = json['status'];
tagline = json['tagline'];
title = json['title'];
video = json['video'];
voteAverage = json['vote_average'];
voteCount = json['vote_count'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['adult'] = this.adult;
data['backdrop_url'] = this.backdropUrl;
data['belongs_to_collection'] = this.belongsToCollection;
data['budget'] = this.budget;
data['genres'] = this.genres;
data['homepage'] = this.homepage;
data['id'] = this.id;
data['imdb_id'] = this.imdbId;
data['original_language'] = this.originalLanguage;
data['original_title'] = this.originalTitle;
data['overview'] = this.overview;
data['popularity'] = this.popularity;
data['poster_url'] = this.posterUrl;
if (this.productionCompanies != null) {
data['production_companies'] =
this.productionCompanies!.map((v) => v.toJson()).toList();
}
if (this.productionCountries != null) {
data['production_countries'] =
this.productionCountries!.map((v) => v.toJson()).toList();
}
data['release_date'] = this.releaseDate;
data['revenue'] = this.revenue;
data['runtime'] = this.runtime;
if (this.spokenLanguages != null) {
data['spoken_languages'] =
this.spokenLanguages!.map((v) => v.toJson()).toList();
}
data['status'] = this.status;
data['tagline'] = this.tagline;
data['title'] = this.title;
data['video'] = this.video;
data['vote_average'] = this.voteAverage;
data['vote_count'] = this.voteCount;
return data;
}
}
class ProductionCompanies {
int? id;
String? logoUrl;
String? name;
String? originCountry;
ProductionCompanies({this.id, this.logoUrl, this.name, this.originCountry});
ProductionCompanies.fromJson(Map<String, dynamic> json) {
id = json['id'];
logoUrl = json['logo_url'];
name = json['name'];
originCountry = json['origin_country'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['logo_url'] = this.logoUrl;
data['name'] = this.name;
data['origin_country'] = this.originCountry;
return data;
}
}
class ProductionCountries {
String? iso31661;
String? name;
ProductionCountries({this.iso31661, this.name});
ProductionCountries.fromJson(Map<String, dynamic> json) {
iso31661 = json['iso_3166_1'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['iso_3166_1'] = this.iso31661;
data['name'] = this.name;
return data;
}
}
class SpokenLanguages {
String? iso6391;
String? name;
SpokenLanguages({this.iso6391, this.name});
SpokenLanguages.fromJson(Map<String, dynamic> json) {
iso6391 = json['iso_639_1'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['iso_639_1'] = this.iso6391;
data['name'] = this.name;
return data;
}
}
Since I'm getting this JSON from the internet, here's the fetching method:
Future<movieDetails> fetchDetails() async {
final response = await http.get(Uri.parse(url)); //url: just a string containing the website's URL
if (response.statusCode == 200){
return compute(parseDetails, response.body);
}
else{
throw Exception('Failed!');
}
}
Everything seems okay from here, but then I have literally no idea how to do the parseDetails function. How should I do it? This JSON file is too complex for me to handle.
Is there any reason you're using compute to parse the JSON file? The file you provided seems to have reasonable length and won't block the main isolate (unless the file is much bigger than what you provided, where compute might be appropriate)
Your code will be something like this (will parse the JSON response in the main isolate). For more details see the official documentation about JSON. Also a tip, follow the dart naming convention PascalCase for classes (MovieDetails instead of movieDetails)
Future<movieDetails> fetchDetails() async {
final response = await http.get(Uri.parse(url)); //url: just a string containing the website's URL
if (response.statusCode == 200){
Map<String, dynamic> movieDetailsMap = jsonDecode(response.body);
return movieDetails.fromJson(movieDetailsMap);
}
else{
throw Exception('Failed!');
}
}
movieDetails parseDetails(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return movieDetails.fromJson(parsed);
}

Parsing Nested JSON Object Flutter

I'm trying to parse an object in JSON and I am able to do so successfully without the nested JSON object Opening Hours. I don't know why. Here is the json data:
{
"location": [
{
"id": 4,
"location_name": "PastryMan",
"cbd_products": "",
"phone": "1231231234",
"street_address": "535 7th Ave",
"location_logo": "https://.s3.amazonaws.com/location_logo/water.png",
"location_photo": "https://dispensaries.s3.amazonaws.com/location_photo/delta9.jpg",
"sponsored_location": "Yes",
"city": "New York",
"state": "New York",
"zip_Code": 10018,
"lat": 40.7538935555556,
"lng": -73.9883851111111,
"latlng": "(40.7770112244898, -74.2110798163265)",
"opening_hours": [
{
"day_of_week": "Tuesday",
"opening_time": "08:00:00",
"closing_time": "22:00:00"
},
{
"day_of_week": "Wednesday",
"opening_time": "08:00:00",
"closing_time": "22:00:00"
},
{
"day_of_week": "Thursday",
"opening_time": "08:00:00",
"closing_time": "22:00:00"
},
{
"day_of_week": "Friday",
"opening_time": "08:00:00",
"closing_time": "22:00:00"
},
{
"day_of_week": "Saturday",
"opening_time": "08:00:00",
"closing_time": "22:00:00"
},
{
"day_of_week": "Sunday",
"opening_time": "08:00:00",
"closing_time": "22:00:00"
},
{
"day_of_week": 7,
"opening_time": "08:00:00",
"closing_time": "22:00:00"
}
],
"ratings": 0.0
},}
I have setup my class like this:
class Location {
int id;
String name;
String phone;
String address;
String city;
String locationPhoto;
String locationLogo;
String state;
num lat;
num long;
List<OpeningHours> openingHours;
String cbdProducts;
num rating;
String zipCode;
String latlng;
String sponsored;
location(
{this.id,
this.name,
this.cbdProducts,
this.phone,
this.address,
this.locationLogo,
this.locationPhoto,
this.sponsored,
this.city,
this.state,
this.zipCode,
this.lat,
this.long,
this.latlng,
this.openingHours,
this.rating});
location.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['location_name'];
cbdProducts = json['cbd_products'];
phone = json['phone'];
address = json['street_address'];
locationLogo = json['location_logo'];
locationPhoto = json['location_photo'];
address = json['sponsored_location'];
city = json['city'];
state = json['state'];
zipCode = json['zip_Code'];
lat = json['lat'];
long = json['long'];
latlng = json['latlng'];
if (json['opening_hours'] != null) {
openingHours = new List<OpeningHours>();
json['opening_hours'].forEach((v) {
openingHours.add(new OpeningHours.fromJson(v));
});
}
rating = json['ratings'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['location_name'] = this.name;
data['cbd_products'] = this.cbdProducts;
data['phone'] = this.phone;
data['street_address'] = this.address;
data['location_logo'] = this.locationLogo;
data['location_photo'] = this.locationPhoto;
data['sponsored_location'] = this.address;
data['city'] = this.city;
data['state'] = this.state;
data['zip_Code'] = this.zipCode;
data['lat'] = this.lat;
data['lng'] = this.long;
data['latlng'] = this.latlng;
if (this.openingHours != null) {
data['opening_hours'] = this.openingHours.map((v) => v.toJson()).toList();
}
data['ratings'] = this.rating;
return data;
}
}
class OpeningHours {
String dayOfWeek;
String openingTime;
String closingTime;
OpeningHours({this.dayOfWeek, this.openingTime, this.closingTime});
OpeningHours.fromJson(Map<String, dynamic> json) {
dayOfWeek = json['day_of_week'];
openingTime = json['opening_time'];
closingTime = json['closing_time'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['day_of_week'] = this.dayOfWeek;
data['opening_time'] = this.openingTime;
data['closing_time'] = this.closingTime;
return data;
}
}
Then I call my api in a future to get the details. Here is the api:
Future getLocations() async {
var url = '$_server/api/customer/location/';
HttpClient client = new HttpClient();
HttpClientRequest request = await client.getUrl(Uri.parse(url));
HttpClientResponse response = await request.close();
String reply = await response.transform(utf8.decoder).join();
var responseData = json.decode(reply);
Locations _location = Locations.fromJson(responseData);
currentLocations = _location.location;
print(currentLocations);
return _location.location;
}
When I call the api currentLocations = null. What have I done wrong here?
One of the easiest ways is to use quicktype.io to generate PODO (Plain Old Dart Objects). Just Select the dart language to create PODO and copy-paste your JSON over there and provide the class Name as "Location". I have done that for you now your location class will look like this:
class Location {
Location({
this.location,
});
List<LocationElement> location;
factory Location.fromJson(Map<String, dynamic> json) => Location(
location: List<LocationElement>.from(json["location"].map((x) => LocationElement.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"location": List<dynamic>.from(location.map((x) => x.toJson())),
};
}
class LocationElement {
LocationElement({
this.id,
this.locationName,
this.cbdProducts,
this.phone,
this.streetAddress,
this.locationLogo,
this.locationPhoto,
this.sponsoredLocation,
this.city,
this.state,
this.zipCode,
this.lat,
this.lng,
this.latlng,
this.openingHours,
this.ratings,
});
int id;
String locationName;
String cbdProducts;
String phone;
String streetAddress;
String locationLogo;
String locationPhoto;
String sponsoredLocation;
String city;
String state;
int zipCode;
double lat;
double lng;
String latlng;
List<OpeningHour> openingHours;
int ratings;
factory LocationElement.fromJson(Map<String, dynamic> json) => LocationElement(
id: json["id"],
locationName: json["location_name"],
cbdProducts: json["cbd_products"],
phone: json["phone"],
streetAddress: json["street_address"],
locationLogo: json["location_logo"],
locationPhoto: json["location_photo"],
sponsoredLocation: json["sponsored_location"],
city: json["city"],
state: json["state"],
zipCode: json["zip_Code"],
lat: json["lat"].toDouble(),
lng: json["lng"].toDouble(),
latlng: json["latlng"],
openingHours: List<OpeningHour>.from(json["opening_hours"].map((x) => OpeningHour.fromJson(x))),
ratings: json["ratings"],
);
Map<String, dynamic> toJson() => {
"id": id,
"location_name": locationName,
"cbd_products": cbdProducts,
"phone": phone,
"street_address": streetAddress,
"location_logo": locationLogo,
"location_photo": locationPhoto,
"sponsored_location": sponsoredLocation,
"city": city,
"state": state,
"zip_Code": zipCode,
"lat": lat,
"lng": lng,
"latlng": latlng,
"opening_hours": List<dynamic>.from(openingHours.map((x) => x.toJson())),
"ratings": ratings,
};
}
class OpeningHour {
OpeningHour({
this.dayOfWeek,
this.openingTime,
this.closingTime,
});
dynamic dayOfWeek;
String openingTime;
String closingTime;
factory OpeningHour.fromJson(Map<String, dynamic> json) => OpeningHour(
dayOfWeek: json["day_of_week"],
openingTime: json["opening_time"],
closingTime: json["closing_time"],
);
Map<String, dynamic> toJson() => {
"day_of_week": dayOfWeek,
"opening_time": openingTime,
"closing_time": closingTime,
};
}
This may work now and if still there is issue then you may be getting null value from backend.