Single user api fetch, flutter - 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;

Related

Flutter - null safety and models

I have returned to Flutter after while (in the meantime null safety was introduced). I ended up with a need to update a project. Let's say in that project I have a User model. I managed to update most of the project but the part that gives me a headache is logout action. There is a need to clear the user (after logout) which I need to set up as null or empty it otherwise, but of course I am getting an error:
Unhandled Exception: type 'Null' is not a subtype of type 'User'
So my question here is what is the best strategy to clear not only user but any other models I have for a redux state without hitting this problem with models not being able to be null?
User model:
class User {
String id;
String username;
String email;
String jwt;
User({ required this.id, required this.username, required this.email, required this.jwt });
factory User.fromJson(Map<String, dynamic> json) {
return User (
id: json['id'],
username: json['username'],
email: json['email'],
jwt: json['jwt']
);
}
}
User actions:
/* User actions */
ThunkAction<AppState> getUserAction = (Store<AppState> store) async {
final prefs = await SharedPreferences.getInstance();
final String? storedUser = prefs.getString('user');
final user = storedUser != null ? User.fromJson(json.decode(storedUser)) : null;
if(user != null) {
store.dispatch(GetUserAction(user));
}
};
ThunkAction<AppState> logoutUserAction = (Store<AppState> store) async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('user');
var user;
store.dispatch(LogoutUserAction(user));
};
class GetUserAction {
final User _user;
User get user => this._user;
GetUserAction(this._user);
}
class LogoutUserAction {
final User _user;
User get user => this._user;
LogoutUserAction(this._user);
}
NOTE: see how I managed to go about the null in the getUserAction (login) part. I just don't dispatch the action if it is null, however I can not do this in the logout as I need explicitly to set the user to null (clear it) and that way log it out from the app.
Can I make a model accept null values? How would I go about this? Or is there any other way I should go about this? Thank you for your kind answer.
Change your model to:
class User {
String? id;
String? username;
String? email;
String? jwt;
User({ required this.id, required this.username, required this.email, required this.jwt });
factory User.fromJson(Map<String, dynamic> json) {
return User (
id: json['id'] ?? "",
username: json['username'] ?? "",
email: json['email'] ?? "",
jwt: json['jwt'] ?? ""
);
}
}
And you need check null_safety for all variable with operation ??
After logout you can check user null with user.id == "" or user == User()
ThunkAction<AppState> logoutUserAction = (Store<AppState> store) async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('user');
var user = User();
store.dispatch(LogoutUserAction(user));
};

What's a good approach to handle API calls in 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']

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,

property of User model from http request returns null

i am trying to make a login request to my backend and display the authenticated user name on my dashboard screen. I did a print statement to try and access one of the properties and I get null. This is the response I get from my backend
{success: {token: nC2vgm8WJgcLVx0Jpppb1JghR6b8iUnBbWNrSmOH7znjYt06d_, user: {firstName: John, lastName: Doe, phoneNumber: 01234567}
My User model is like this;
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
class AuthUser extends Equatable {
final String firstName;
final String lastName;
final String phoneNumber;
AuthUser({
#required this.firstName,
#required this.lastName,
#required this.phoneNumber,
});
factory AuthUser.fromJson(Map<String, dynamic> json) {
return AuthUser(
firstName: json['firstName'],
lastName: json['lastName'],
phoneNumber: json['phoneNumber'],
);
}
#override
List<Object> get props => [firstName, lastName, email];
}
This is my authRepository
import 'package:flutter_repo/models/auth-user.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:io';
abstract class AuthRepository {
Future<AuthUser> doLogin(data);
}
class Auth implements AuthRepository {
final baseUrl = "http://10.0.2.2:8000/api/v1";
#override
Future<AuthUser> doLogin(data) async {
final response = await http.post('$baseUrl/user/login', body: data);
if (response.statusCode == 200) {
var user = AuthUser.fromJson(json.decode(response.body));
print(user.firstName);
return user;
}else {
throw new Exception('Failed To Login User');
}
}
}
Printing user.firstName gives me null. Here is what my json response gives me
{success: {token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiMmJjNWM1ZDk1NGU2ZDY4ZTg5MTEzMThkMGY0Yjc3OGNlNDJhNDNiNThlODJkMWQ3ZTUxMmMzOTQ0MzFlOTJkNjRiMjMxYzczOTVmZDEyYWUiLCJpYXQiOjE1ODEwODIxNzAsIm5iZiI6MTU4MTA4MjE3MCwiZXhwIjoxNjEyNzA0NTcwLCJzdWIiOiIyIiwic2NvcGVzIjpbXX0.Lnu09KKeL9LdJbKKPega3xIa4c4j_T00rY3pIvp3-b6mi3PRf1oKmw0kaITenmEcPdyjLHiOZWxTXycTQwx1IOKGMf86HS2K8rmuPna9hxoMHOjJWgsw0Rorn0YTkHdGZZJ8uCtbIK3jss0nRjHgLYkvtwZ0jHC8b8qfSf1bcj2nGYLRNboMMo2GuIdBybJdmLM_Z7Z6CiRS2j9QuVhT_oS62QhWSR07jF3NsjCmH8RoUCS0goOan2hkSl3lava7tAoodH_JrxHo86Fk3i8N4Idt3-P-Q3OsWl2t67HizZ7i_87TcYP3RtwSpKMKkllBLiWoXWZriqhv0wdwmxwfAySyKqCEDei9pCFEz-nQYOxmldTMq-UXOZlFjy4Mcx_o-It8CbrHaCcyESV-iAjdoamdjQtujKOGP-GngM7jBgCxjsnavgeYzPLRF9_yTzSdI7CUWQFoK_Ja2DM3WswOGG4kdCp3K7uifklO69pVo1INQQN7Uf6oVI4XfAzeEQGLqW9eX8reFx7SzZglQGePDn1zonWNmUgZ19k5MbRRlH2mwt1pP-dt8L9t07cLdjKqHj68HtmE2tcP0U4Lv1ApT_v0erskolNL6bD3y_dE7re74UQtl5FrGZciDWiYkt1v1BecsIAWumM8eKoWAKgURcgdydIWr8q4GzkRp_BKyXs, user: {firstName: Patrick, lastName: Obafemi, phoneNumber} }
How can I retrieve the values of my user model correctly
Ideally you would have a User class made by you where you could write a .toJson method to help you parse the data coming in, like this for example:
class User {
String firstName;
String lastName;
int phoneNumber;
...
User.fromJson(Map<String, dynamic> json) {
this.firstName = json['firstName'];
this.lastName = json['lastName'];
this.phoneNumber = json['phoneNumber'];
}
}
According to the json structure you shared, this should work:
var response = AuthUser.fromJson(json.decode(response.body));
User user = User.fromJson(
jsonResponse['success']['user']
);
You have to encode only the user. You can try this:
var user = AuthUser.fromJson(json.decode(response.body['success']['user']));
Try this way
Create an Instance of AuthUser,
Future<AuthUser> auser;
//Assign response to it;
auser = AuthUser.fromJson(json.decode(response.body));
Now you can print
print(post.username);
For more detail check out this example or this one