I'm trying to learn how to use APIs, but I've been struggling to get my code to work, here is what I have so far ;
Provider :
class MovieProvider extends GetConnect {
@override
var queryParameters = {
'limit': '8',
'genres': 'comedia',
'sort': 'year',
'type': 'movies'
};
static const String _baseUrl = 'movies-app1.p.rapidapi.com';
void onInit() {
httpClient.baseUrl = _baseUrl;
}
static const Map<String, String> _headers = {
"x-rapidapi-key": "***************",
"x-rapidapi-host": "movies-app1.p.rapidapi.com",
};
// Base API request to get response
Future<dynamic> getStats() async {
Uri uri = Uri.https(_baseUrl, '/api/movies', queryParameters);
final response = await http.get(uri, headers: _headers);
print('provider IS WORKING');
if (response.statusCode == 200) {
// If server returns an OK response, parse the JSON.
print("success");
print(response.body);
return json.decode(response.body);
} else {
print("not success");
// If that response was not OK, throw an error.
throw Exception('Failed to load json data');
}
}
}
Model :
import 'dart:convert';
Movies moviesFromJson(String str) => Movies.fromJson(json.decode(str));
String moviesToJson(Movies data) => json.encode(data.toJson());
class Movies {
Movies({
this.status,
this.success,
this.messageStatus,
this.results,
this.totalResults,
this.totalPages,
});
int? status;
bool? success;
String? messageStatus;
List<Result>? results;
int? totalResults;
int? totalPages;
factory Movies.fromJson(Map<String, dynamic> json) => Movies(
status: json["status"],
success: json["success"],
messageStatus: json["messageStatus"],
results:
List<Result>.from(json["results"].map((x) => Result.fromJson(x))),
totalResults: json["total_results"],
totalPages: json["total_pages"],
);
Map<String, dynamic> toJson() => {
"status": status,
"success": success,
"messageStatus": messageStatus,
"results": List<dynamic>.from(results!.map((x) => x.toJson())),
"total_results": totalResults,
"total_pages": totalPages,
};
}
class Result {
Result({
this.actors,
this.directors,
this.escritors,
this.otherTitles,
this.id,
this.image,
this.title,
this.rating,
this.year,
this.titleOriginal,
this.uuid,
this.description,
this.genres,
this.countries,
this.release,
this.embedUrls,
this.index,
this.episodes,
this.createdAt,
this.updatedAt,
});
List<dynamic>? actors;
List<dynamic>? directors;
List<dynamic>? escritors;
List<dynamic>? otherTitles;
String? id;
String? image;
String? title;
String? rating;
String? year;
String? titleOriginal;
String? uuid;
String? description;
List<Country>? genres;
List<Country>? countries;
String? release;
List<EmbedUrl>? embedUrls;
int? index;
List<dynamic>? episodes;
DateTime? createdAt;
DateTime? updatedAt;
factory Result.fromJson(Map<String, dynamic> json) => Result(
actors: List<dynamic>.from(json["actors"].map((x) => x)),
directors: List<dynamic>.from(json["directors"].map((x) => x)),
escritors: List<dynamic>.from(json["escritors"].map((x) => x)),
otherTitles: List<dynamic>.from(json["otherTitles"].map((x) => x)),
id: json["_id"],
image: json["image"],
title: json["title"],
rating: json["rating"],
year: json["year"],
titleOriginal: json["titleOriginal"],
uuid: json["uuid"],
description: json["description"],
genres:
List<Country>.from(json["genres"].map((x) => Country.fromJson(x))),
countries: List<Country>.from(
json["countries"].map((x) => Country.fromJson(x))),
release: json["release"],
embedUrls: List<EmbedUrl>.from(
json["embedUrls"].map((x) => EmbedUrl.fromJson(x))),
index: json["index"],
episodes: List<dynamic>.from(json["episodes"].map((x) => x)),
createdAt: DateTime.parse(json["createdAt"]),
updatedAt: DateTime.parse(json["updatedAt"]),
);
Map<String, dynamic> toJson() => {
"actors": List<dynamic>.from(actors!.map((x) => x)),
"directors": List<dynamic>.from(directors!.map((x) => x)),
"escritors": List<dynamic>.from(escritors!.map((x) => x)),
"otherTitles": List<dynamic>.from(otherTitles!.map((x) => x)),
"_id": id,
"image": image,
"title": title,
"rating": rating,
"year": year,
"titleOriginal": titleOriginal,
"uuid": uuid,
"description": description,
"genres": List<dynamic>.from(genres!.map((x) => x.toJson())),
"countries": List<dynamic>.from(countries!.map((x) => x.toJson())),
"release": release,
"embedUrls": List<dynamic>.from(embedUrls!.map((x) => x.toJson())),
"index": index,
"episodes": List<dynamic>.from(episodes!.map((x) => x)),
"createdAt": createdAt?.toIso8601String(),
"updatedAt": updatedAt?.toIso8601String(),
};
}
class Country {
Country({
this.name,
this.uuid,
});
String? name;
String? uuid;
factory Country.fromJson(Map<String, dynamic> json) => Country(
name: json["name"],
uuid: json["uuid"],
);
Map<String, dynamic> toJson() => {
"name": name,
"uuid": uuid,
};
}
class EmbedUrl {
EmbedUrl({
this.server,
this.url,
this.priority,
});
String? server;
String? url;
int? priority;
factory EmbedUrl.fromJson(Map<String, dynamic> json) => EmbedUrl(
server: json["server"],
url: json["url"],
priority: json["priority"],
);
Map<String, dynamic> toJson() => {
"server": server,
"url": url,
"priority": priority,
};
}
Controller :
class HomeController extends GetxController {
var m = Movies();
var r = new Result();
final provider = Get.put(MovieProvider());
final count = 0.obs;
@override
void onInit() {
provider.getStats();
super.onInit();
}
@override
void onReady() {
super.onReady();
}
@override
void onClose() {
super.onClose();
}
void increment() => count.value ;
}
And as for my View I've been so far just testing to get the title of one of the movies as a Text, using :
Text(controller.r.titleOriginal[0])
But I get an error related to Null-safety,
I tried adding a '!' in !titleOriginal, but this is what I go :
Exception has occurred. _CastError (Null check operator used on a null value)
adding '?' doesn't work either.
Here's also my View :
class DigiappstoreView extends GetView<DigiappstoreController> {
const DigiappstoreView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(body: Center(child: Text(controller.r.titleOriginal![0])));
}
}
CodePudding user response:
You are returning dynamic
type from your provider. You should return a specific type. As per the code, it should return the type of Movie
.
class MovieProvider extends GetConnect {
@override
var queryParameters = {
'limit': '8',
'genres': 'comedia',
'sort': 'year',
'type': 'movies'
};
static const String _baseUrl = 'movies-app1.p.rapidapi.com';
void onInit() {
httpClient.baseUrl = _baseUrl;
}
static const Map<String, String> _headers = {
"x-rapidapi-key": "***************",
"x-rapidapi-host": "movies-app1.p.rapidapi.com",
};
// Base API request to get response
Future<Movie> getStats() async {
Uri uri = Uri.https(_baseUrl, '/api/movies', queryParameters);
final response = await http.get(uri, headers: _headers);
print('provider IS WORKING');
if (response.statusCode == 200) {
return moviesFromJson(response.body);
} else {
throw Exception('Failed to load json data');
}
}
}
Also, in controller, you should assign the result to the variable like
class HomeController extends GetxController {
var m = Movies();
var r = Result();
final provider = Get.put(MovieProvider());
@override
void onInit() {
getStates();
super.onInit();
}
getStates() async {
movies = await provider.getStats();
r = movies.results;
update();
}
}
Now
in your view, wrap the child inside GetBuilder to update the UI once the data is updated.
class DigiappstoreView extends GetView<DigiappstoreController> {
const DigiappstoreView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(body: GetBuilder<DigiappstoreController>(
init: DigiappstoreController(),
builder: (controller) {
return Center(child: Text(controller.r == null ? '' : controller.r[0].titleOriginal!));
},
));
}
}
There may be some syntax error as i have not tried the code myself but these are the updates that you need to do.
I think you need to read the GetX Documentation in detail to know how it works