What's a good approach to handle API calls in Flutter? - flutter

Well, I am using http package of flutter to handle the api calls in flutter. Since, I am from js/react/redux background, I tried implementing similar approach.
I created a function called api as below which just acts as wrapper function to manage api calls,
Future api({
#required String url,
#required String method,
body,
extra,
}) async {
try {
var headers = {
'Content-Type': 'application/json',
"Authorization": ' jwt token of user provider'
};
var request = http.Request(
method, Uri.parse("$SERVER_URL${getUrl(url, method, extra)}"));
if (isSomething(body)) {
request.body = json.encode(body);
}
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
print(response.statusCode);
var responseBody = await response.stream.bytesToString();
print(responseBody);
return responseBody;
} catch (e) {
throw e;
}
But accessing token of UserProvider seems quite complex to me, like I have to pass provider object from the widget I am using the api function every time I use it.
My UserProvider now looks like this:
class UserProvider extends ChangeNotifier {
String id;
String name;
String email;
String role;
String jwt;
void setUser(
{String id, String name, String email, String role, String jwt}) {
print("here is called");
this.id = id;
this.name = name;
this.email = email;
this.role = role;
this.jwt = jwt;
notifyListeners();
}
Map<String, dynamic> getUser() {
return {
"id": this.id,
"name": this.name,
"email": this.email,
"role": this.role,
"jwt": this.jwt
};
}
}
I don't know if I am doing the things correctly as I am new to Flutter. My question is:
How can I access jwt of User provider in api function?
Is this approach good or not, if not please suggest better approach.

You need to pass the BuildContext in your api method, and then you can access the jwt like so :
Provider.of<UserProvider>(context, listen: false).getUser()['jwt']

Related

Flutter handle future response

i want to store token value and navigate home page using go router after login. i dont know how to handle json data like display or (retrieve)name and role.. i am newbie for programming.
Help me.thanks in advance.i tried futurebuilder examples it not worked. kindly give simple solution.
Future<Loginuser> fetchLoginuser(String mobile, String password) async {
final response = await http.post(
Uri.parse('https://random.url/api/login'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(
<String, String>{'mobile': mobile, 'password': password}));
if (response.statusCode == 200) {
return Loginuser.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to update album.');
}
}
class Userinfo {
double branchcode;
double role;
double name;
Userinfo({required this.branchcode, required this.role, required this.name});
factory Userinfo.fromJson(Map<String, dynamic> json) {
return Userinfo(
branchcode: json['branchcode'], role: json['role'], name: json['name']);
}
}
class Loginuser {
final String message;
final String messagecode;
final String token;
final Userinfo userinfo;
const Loginuser({
required this.message,
required this.messagecode,
required this.token,
required this.userinfo,
});
factory Loginuser.fromJson(Map<String, dynamic> json) {
return Loginuser(
message: json['message'],
messagecode: json['messagecode'],
token: json['token'],
userinfo: json['userinfo']);
}
}
Use shared_preferences usage is straight forward
here just do this
if (response.statusCode == 200) {
Loginuser _user = Loginuser.fromJson(json.decode(response.body));
final prefs = await SharedPreferences.getInstance();
await prefs.setString('token', user.token);
return user;
} else {
throw Exception('Failed to update album.');
}
And next time you want to check wether user was logged in or not
final prefs = await SharedPreferences.getInstance();
final String? action = prefs.getString('token');
if(token == null){ //not logged in}else{ //logged navigate to dashboard}
///Create a separate helper/manager for shared preferences. This is just an example///

Single user api fetch, flutter

I only want to fetch/get single api data, i tried to print the response from service i got all the api data but when i try to pass it to the controller the variable for model didn't correct,
i already look for the anwser for fetching single api with Service and Controller architecture with GetX but i didn't find any suitable answer, i hope you can help me it's very important. thanks
im using http and GetX
the problem is here
var user = <UserModel>{}.obs;
user.value = _user;
it tells
UserModel _user A value of type 'UserModel' can't be assigned to a
variable of type 'Set'. Try changing the type of the
variable, or casting the right-hand type to 'Set
here is the code
Api Service
class ApiService {
Future<UserModel> fetchApi(id) async {
var url = 'https://reqres.in/api/users/$id';
var response = await http.get(Uri.parse(url));
if(response.statusCode == 200){
var dataResponse = jsonDecode(response.body)['data'];
UserModel user = UserModel.fromJson(dataResponse);
return user;
} else {
throw Exception('Failed Get API');
}
}
}
Controller
class Controller extends GetxController {
var user = <UserModel>{}.obs;
Future fetchApi(id) async {
try {
var _user = await ApiService().fetchApi(id);
user.value = _user;
print(user);
} catch (e) {
print(e);
}
}
}
Model
class UserModel {
int id;
String email;
String name;
String avatar;
UserModel({
required this.id,
required this.email,
required this.name,
required this.avatar,
});
factory UserModel.fromJson(Map<String, dynamic> json) => UserModel(
id: json['id'],
email: json['email'],
name: json['first_name'] + ' ' + json['last_name'],
avatar: json['avatar'],
);
}
The main reason is that you are defining user as {} type and you need UserModel Type.
You need change this:
var user = <UserModel>{}.obs;
user.value = _user;
for this:
var user = UserModel().obs;
user.value = _user;

String can't be returned because it has a return type of 'Future<Login?> in Flutter

I'm sending a post request phone number and password to the database and if user send incorrect credentials then it shows the message "the user is not registered". But in else condition it is showing an error on return message "A value of type 'String' can't be returned from the method 'makeRequestLogin' because it has a return type of 'Future<Login?>'."
Future<Login?> makeRequestLogin(String mobileNumber, String password) async {
var response = await http.post(Uri.parse('$baseURL/customer/login'), body: {
"phone_number": mobileNumber,
"password": password,
"registration_type": "normal"
});
if (response.statusCode == 200) {
final responseString = response.body;
final data = jsonDecode(responseString);
Login signUp = Login.fromJson(data);
return signUp;
} else {
final responseString = response.body;
var result = json.decode(responseString);
String message = result["message"];
return message; // On this line getting an error
}
}
Model
class Login {
String? phoneNumber;
String? password;
Login({
this.phoneNumber,
this.password,
});
Login.fromJson(Map<String, dynamic> json) {
phoneNumber = json["phone_number"]?.toString();
password = json["password"]?.toString();
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data["phone_number"] = phoneNumber;
data["password"] = password;
return data;
}
}
Instead of returning Login? return String?.
Convert
Future<Login?> makeRequestLogin(String mobileNumber, String password) async
to
Future<String?> makeRequestLogin(String mobileNumber, String password) async
Change returning Login instances to String.
Your return type of that particular future function is log in as you are writing inside the angle brackets so any return within the body of that function should be of type login and not a simple string.
One solution is to have a string error field in your model class and access that when error occurred

adding token with the url string concatenation

hi I want to send token with my api url i tried it by concatenate the token with api url but not. it's showing the error you cannot call the value on null. i cannot figure it out. any help from your side should be appreciate.
This is my api code:
class APIService {
String baseurl = "https://b2all.live/api";
var log = Logger();
FlutterSecureStorage storage = FlutterSecureStorage();
//old get
Future get(String url) async {
await storage.read(key: "api_token");
url = formater(url);
// /user/register
var response = await http.get(
url,
);
if (response.statusCode == 200) {
log.i(response.body);
return json.decode(response.body);
}
log.i(response.body);
log.i(response.statusCode);
}
String formater (String url) {
return baseurl+url;
}
}
And this is my fetching data from api code:
#override
void initState() {
super.initState();
fetchData();
}
void fetchData() async {
var preferences = await SharedPreferences.getInstance();
String api_token = preferences.getString('api_token');
print(api_token);
var response = await networkHandler.get(
"/profile/DvIXUN1CAgYMQzKri0dx3XVxfcABDjbPEg1QyHVD4vu1pQM8pRF56OjLgVW8");
setState(() {
profileModelFix = ProfileModelFix.fromJson(response);
circular = false;
});
}
this is my model file. it's showing error on model. but i cannot figure it out. any help from your side will be helpful for me.
import 'package:flutter/foundation.dart';
import 'package:json_annotation/json_annotation.dart';
part 'profileModelFix.g.dart';
#JsonSerializable()
class ProfileModelFix {
String name;
String user_name;
String dob;
String phone;
String gender;
String bio;
String api_token;
ProfileModelFix ({
this.name, this.user_name, this.dob, this.phone, this.gender, this.bio, this.api_token,
});
factory ProfileModelFix.fromJson(Map<String,dynamic> json) =>
_$ProfileModelFixFromJson(json);
Map<String,dynamic> toJson() => _$ProfileModelFixToJson(this);
}

About Firebase real time database

I am working on Firebase real time databases in Flutter. I am storing user information and their corresponding data in database. My code is given below:
//User Auth Class
class UserAuth{
final String id;
final String email;
final String token;
UserAuth({#required this.id, #required this.email, #required this.token});
}
//User Details Class for storing data of corresponding user
class UserDetails{
final String userDetailsId;
final String name;
final String email;
UserDetails({#required this.userDetailsId,#required this.name, #required this.email});
}
//I am using this code to add userDetails in database.
List<UserDetails> _detailsList = [];
UserDetails _details;
Future<bool> addUserDetails(String username, String email) async {
_isLoading = true;
notifyListeners();
final Map<String, dynamic> userDetails = {
'username': username,
'email': email,
};
try {
final http.Response response = await http.post(
'https://intro-to-firebase-711d4.firebaseio.com/Users.json',
body: json.encode(userDetails));
if (response.statusCode != 200 && response.statusCode != 201) {
_isLoading = false;
notifyListeners();
return false;
}
final Map<String, dynamic> responseData = json.decode(response.body);
_details = UserDetails(
userDetailsId: responseData['name'], name: username, email: email);
_detailsList.add(_details);
_isLoading = false;
notifyListeners();
return true;
} catch (error) {
_isLoading = false;
notifyListeners();
return false;
}
}
Now I want to get the following highlighted ids of the user so how to fetch it. I am using scoped model as a state management in Flutter.
I did it with javascript so far but in the documentation it seems not taht different for flutter:
private void writeNewUser(String userId, String name, String email) {
User user = new User(name, email);
mDatabase.child("users").child(userId).setValue(user);
}
https://firebase.google.com/docs/database/android/read-and-write?authuser=0
This is the example shown in the docs. with .child('users') you can get the right section .child(userId) gives you access to the values.
All you have to do now is defining the variable userId
flutter
you can achieve this as follows
stream: FirebaseDatabase.instance
.reference()
.child('users')
.equalTo(userId)
.onValue,