I am trying to follow a tutorial on making a data model, implement a GET request and display my data. The api I am trying to hit starts with an object containing key value pairs. The tutorial api does not. I need to know how to do it the way I am trying as a lot of the api's I have encountered are structured that way. Here is the error I am getting.
Here is the code for my GET request:
import 'dart:convert';
import 'package:ffxiv_job_viewer/models/job_list_model.dart';
import 'package:ffxiv_job_viewer/utils/app_constants.dart';
import 'package:http/http.dart' as http;
class ApiService {
Future<List<JobList>> getAllJobs() async {
final allJobsUrl =
Uri.parse(AppConstants.BASE_URL AppConstants.JOB_LIST_URI);
final response = await http.get(allJobsUrl);
List<JobList> allJobs = [];
List body = json.decode(response.body);
body.forEach((job) {
allJobs.add(JobList.fromJson(job));
});
print(response.statusCode);
print(response.body);
return allJobs;
}
}
Here is the code for my model file:
import 'dart:convert';
JobList jobListFromJson(String str) => JobList.fromJson(json.decode(str));
String jobListToJson(JobList data) => json.encode(data.toJson());
class JobList {
JobList({
required this.results,
});
List<Result> results;
factory JobList.fromJson(Map<String, dynamic> json) => JobList(
results: List<Result>.from(json["Results"].map((x) => Result.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Results": List<dynamic>.from(results.map((x) => x.toJson())),
};
}
class Result {
Result({
required this.id,
required this.icon,
required this.name,
required this.url,
});
int id;
String icon;
String name;
String url;
factory Result.fromJson(Map<String, dynamic> json) => Result(
id: json["ID"],
icon: json["Icon"],
name: json["Name"],
url: json["Url"],
);
Map<String, dynamic> toJson() => {
"ID": id,
"Icon": icon,
"Name": name,
"Url": url,
};
}
CodePudding user response:
json.decode()
returns a Map<String, dynamic>
instance not a List
. The server you're sending the request to probably sends back a JSON which needs to be decoded into Map<String, dynamic>
to be used in your mobile application.
Edit :
The URL you've provided returns this response :
{
"Pagination": {
"Page": 1,
"PageNext": null,
"PagePrev": null,
"PageTotal": 1,
"Results": 40,
"ResultsPerPage": 100,
"ResultsTotal": 40
},
"Results": [
{
"ID": 1,
"Icon": "/cj/1/gladiator.png",
"Name": "gladiator",
"Url": "/ClassJob/1"
},
{
"ID": 2,
"Icon": "/cj/1/pugilist.png",
"Name": "pugilist",
"Url": "/ClassJob/2"
},
{
"ID": 3,
"Icon": "/cj/1/marauder.png",
"Name": "marauder",
"Url": "/ClassJob/3"
},
{
"ID": 4,
"Icon": "/cj/1/lancer.png",
"Name": "lancer",
"Url": "/ClassJob/4"
},
{
"ID": 5,
"Icon": "/cj/1/archer.png",
"Name": "archer",
"Url": "/ClassJob/5"
},
{
"ID": 6,
"Icon": "/cj/1/conjurer.png",
"Name": "conjurer",
"Url": "/ClassJob/6"
},
{
"ID": 7,
"Icon": "/cj/1/thaumaturge.png",
"Name": "thaumaturge",
"Url": "/ClassJob/7"
},
{
"ID": 8,
"Icon": "/cj/1/carpenter.png",
"Name": "carpenter",
"Url": "/ClassJob/8"
},
{
"ID": 9,
"Icon": "/cj/1/blacksmith.png",
"Name": "blacksmith",
"Url": "/ClassJob/9"
},
{
"ID": 10,
"Icon": "/cj/1/armorer.png",
"Name": "armorer",
"Url": "/ClassJob/10"
},
{
"ID": 11,
"Icon": "/cj/1/goldsmith.png",
"Name": "goldsmith",
"Url": "/ClassJob/11"
},
{
"ID": 12,
"Icon": "/cj/1/leatherworker.png",
"Name": "leatherworker",
"Url": "/ClassJob/12"
},
{
"ID": 13,
"Icon": "/cj/1/weaver.png",
"Name": "weaver",
"Url": "/ClassJob/13"
},
{
"ID": 14,
"Icon": "/cj/1/alchemist.png",
"Name": "alchemist",
"Url": "/ClassJob/14"
},
{
"ID": 15,
"Icon": "/cj/1/culinarian.png",
"Name": "culinarian",
"Url": "/ClassJob/15"
},
{
"ID": 16,
"Icon": "/cj/1/miner.png",
"Name": "miner",
"Url": "/ClassJob/16"
},
{
"ID": 17,
"Icon": "/cj/1/botanist.png",
"Name": "botanist",
"Url": "/ClassJob/17"
},
{
"ID": 18,
"Icon": "/cj/1/fisher.png",
"Name": "fisher",
"Url": "/ClassJob/18"
},
{
"ID": 19,
"Icon": "/cj/1/paladin.png",
"Name": "paladin",
"Url": "/ClassJob/19"
},
{
"ID": 20,
"Icon": "/cj/1/monk.png",
"Name": "monk",
"Url": "/ClassJob/20"
},
{
"ID": 21,
"Icon": "/cj/1/warrior.png",
"Name": "warrior",
"Url": "/ClassJob/21"
},
{
"ID": 22,
"Icon": "/cj/1/dragoon.png",
"Name": "dragoon",
"Url": "/ClassJob/22"
},
{
"ID": 23,
"Icon": "/cj/1/bard.png",
"Name": "bard",
"Url": "/ClassJob/23"
},
{
"ID": 24,
"Icon": "/cj/1/whitemage.png",
"Name": "white mage",
"Url": "/ClassJob/24"
},
{
"ID": 25,
"Icon": "/cj/1/blackmage.png",
"Name": "black mage",
"Url": "/ClassJob/25"
},
{
"ID": 26,
"Icon": "/cj/1/arcanist.png",
"Name": "arcanist",
"Url": "/ClassJob/26"
},
{
"ID": 27,
"Icon": "/cj/1/summoner.png",
"Name": "summoner",
"Url": "/ClassJob/27"
},
{
"ID": 28,
"Icon": "/cj/1/scholar.png",
"Name": "scholar",
"Url": "/ClassJob/28"
},
{
"ID": 29,
"Icon": "/cj/1/rogue.png",
"Name": "rogue",
"Url": "/ClassJob/29"
},
{
"ID": 30,
"Icon": "/cj/1/ninja.png",
"Name": "ninja",
"Url": "/ClassJob/30"
},
{
"ID": 31,
"Icon": "/cj/1/machinist.png",
"Name": "machinist",
"Url": "/ClassJob/31"
},
{
"ID": 32,
"Icon": "/cj/1/darkknight.png",
"Name": "dark knight",
"Url": "/ClassJob/32"
},
{
"ID": 33,
"Icon": "/cj/1/astrologian.png",
"Name": "astrologian",
"Url": "/ClassJob/33"
},
{
"ID": 34,
"Icon": "/cj/1/samurai.png",
"Name": "samurai",
"Url": "/ClassJob/34"
},
{
"ID": 35,
"Icon": "/cj/1/redmage.png",
"Name": "red mage",
"Url": "/ClassJob/35"
},
{
"ID": 36,
"Icon": "/cj/1/bluemage.png",
"Name": "blue mage",
"Url": "/ClassJob/36"
},
{
"ID": 37,
"Icon": "/cj/1/gunbreaker.png",
"Name": "gunbreaker",
"Url": "/ClassJob/37"
},
{
"ID": 38,
"Icon": "/cj/1/dancer.png",
"Name": "dancer",
"Url": "/ClassJob/38"
},
{
"ID": 39,
"Icon": "/cj/1/reaper.png",
"Name": "reaper",
"Url": "/ClassJob/39"
},
{
"ID": 40,
"Icon": "/cj/1/sage.png",
"Name": "sage",
"Url": "/ClassJob/40"
}
]
}
So the client should decode the response, and extract the data you need from the Results
key
import 'dart:convert';
import 'package:ffxiv_job_viewer/models/job_list_model.dart';
import 'package:ffxiv_job_viewer/utils/app_constants.dart';
import 'package:http/http.dart' as http;
class ApiService {
Future<List<JobList>> getAllJobs() async {
final allJobsUrl =
Uri.parse(AppConstants.BASE_URL AppConstants.JOB_LIST_URI);
final response = await http.get(allJobsUrl);
List<JobList> allJobs = [];
Map<String, dynamic> body = json.decode(response.body);
body['Results'].forEach((job) {
allJobs.add(JobList.fromJson(job));
});
print(response.statusCode);
print(response.body);
return allJobs;
}
}
CodePudding user response:
You cannot return jsonDecode() as Map<String, dynamic> inside a dynamic list. Try changing your dynamic list as List<Map<String, dynamic>>
import 'dart:convert';
import 'package:ffxiv_job_viewer/models/job_list_model.dart';
import 'package:ffxiv_job_viewer/utils/app_constants.dart';
import 'package:http/http.dart' as http;
class ApiService {
Future<List<JobList>> getAllJobs() async {
final allJobsUrl =
Uri.parse(AppConstants.BASE_URL AppConstants.JOB_LIST_URI);
final response = await http.get(allJobsUrl);
List<JobList> allJobs = [];
Map<String, dynamic> body = json.decode(response.body); // Make a change here.
body['Results'].forEach((job) {
allJobs.add(JobList.fromJson(job));
});
print(response.statusCode);
print(response.body);
return allJobs;
}
}