How can i convert Future<User> to User in my class? [duplicate] - flutter

This question already has answers here:
What is a Future and how do I use it?
(6 answers)
Closed 2 years ago.
What i am trying to do is i am fetching profile from fetchUser.But i don't know any other way that i can pull http data other than string.
class FollowingUserModel {
final String id;
final String author;
User profile;
final String profileid;
FollowingUserModel({this.id, this.profileid, this.author, this.profile}) { profile = fetchUser() as User; }
Future<User> fetchUser() async{
final response = await http.get("$SERVER_IP/api/users/$profileid/?format=json");
if (response.statusCode == 200) {
var responseJson = json.decode(response.body);
return User.fromJSON(responseJson);}}
factory FollowingUserModel.fromJSON(Map<String, dynamic> jsonMap) {
return FollowingUserModel(
id: jsonMap['id'] as String,
author: jsonMap['author'] as String,
profileid: jsonMap['profile'] as String,
);}}
Does anybody know how to do it?

Just create an asynchronous function .
If you have Future<User>, to convert it to User, you need to add await; and to use await, you need to add async:
Future<void> test() async {
User user = await fetchUser();
}
You can learn more about asynchronous function here

From where you are calling do this,
User user = await followingUserModel.fetchUser();
Future<User> means it will return an User object by asynchronously(in future), so make the call with await, then your code will wait till it get the return.

Related

flutter return future list in a var to use outside the loop

Hello I'm trying to recuperate the list value of a database.
i can but what i want is to export the result in a var so i can use in all my code just by calling "print(myList);"
this is my code :
static const URL =
'https://xxxhost/employee_actions3.php';
static Future<List<Employee>> getEmployees() async {
try {
final response = await http.post(Uri.parse(
URL,
));
print("getEmployees >> Response:: ${response.body}");
if (response.statusCode == 200) {
List<Employee> list = parsePhotos(response.body);
return list;
} else {
throw <Employee>[];
}
} catch (e) {
return <Employee>[];
}
}
and my classe Employee
class Employee {
String id;
String firstName;
String lastName;
Employee({required this.id, required this.firstName, required this.lastName});
factory Employee.fromJson(Map<String, dynamic> json) {
return Employee(
id: json['id'] as String,
firstName: json['lat'] as String,
lastName: json['lng'] as String,
);
}
}
can i have help please ?
There are two ways to access async data in most modern languages, including dart, they are:
1. By providing a callback then
2. By using the function in an async context and awaiting the result
I've wrapped the code above in a class called API so the examples below are easier to follow,
class API {
static const URL = 'https://xxxhost/employee_actions3.php';
static Future<List<Employee>> getEmployees() async {
try {
final response = await http.post(Uri.parse(URL));
print("getEmployees >> Response:: ${response.body}");
if (response.statusCode == 200) {
List<Employee> list = parsePhotos(response.body);
return list;
} else {
throw("${response.statusCode} Failed to parse photos");
}
} catch (e) {
throw e;
}
}
}
Method 1: Providing a callback to .then, this method will allow you to work with async actions in a synchronous context, but be aware it will not halt the execution flow.
void main() {
API.getEmployees().then((resp) => print(resp)).catchError(e) => print(e);
}
Method 2: Async/Await, this method will allow you to access the data inline, that is var x = await myAsyncFunc() remember the await keyword requires the function to be called within an async context. And the await keyword will halt the execution flow till the future completes.
void main() async {
try {
final list = await API.getEmployees();
print(list);
} catch (e) {
print(e);
}
}
Using either one of the two methods outlined above will allow you to access the data of the list later on.
Additional Reading:
Async programming in dart
Futures and error handling

Unable to use a Future value - Flutter/Dart

I've fetched a json object and deserialized it and then returned it too.
I want to use this in another file.
I'm unable to assign the values that I'm getting in the first step.
Here are all the codes...
Service
Future getGeoPoints(String accessToken, String tripId) async {
String requestUrl;
var response = await get(
Uri.parse(requestUrl),
headers: {
'Authorization': "Bearer $accessToken",
},
);
if (response.statusCode == 200) {
Map<String, dynamic> responseBody = json.decode(response.body);
GetGeoPoints geoPoints = GetGeoPoints.fromJson(responseBody);
List listOfGeoPoints = [];
for (var geoPoint in geoPoints.geoPoints) {
listOfGeoPoints.add(
{
'latitude': geoPoint.latitude,
'longitude': geoPoint.longitude,
'timestamp': geoPoint.timeStamp,
},
);
}
// print('List of geo points: ' + '$listOfGeoPoints');
return listOfGeoPoints;
} else {
throw Exception('Failed to load data from server');
}
}
File where I need the above values
List routeCoordinates;
Future<void> getValues() async {
getGeoPoints(widget.accessToken, widget.tripId)
.then((value) => routeCoordinates = value);
}
When I run the app, routeCoordinates is null but when I hotreload, it contains the value.
I want to have the values as soon as the screen starts. What is the right way to assign the values here?
I've also tried this:
routeCoordinates = getGeoPoints...
It throws error..
Please help.. Thanks..
The function getGeoPoints() is an asynchronous one. But on the other file, you are not using the await keyword, instead you are using then(). So your code is not waiting for that function to return value.
Try using below code,
List routeCoordinates;
Future<void> getValues() async {
routeCoordinates = await getGeoPoints(widget.accessToken, widget.tripId);
}
Let us know how it went.
You need to use a FutureBuilder to define a behaviour depending on the state of the request. You'll be able to tell the widget what to return while your app is waiting for the response to your request. You can also return a specific widget if you get an error(if your user is offline, for example).
Edit: I've linked the official docs but give this article a read if it's not clear enough.

Converting Future to string flutter [duplicate]

This question already has answers here:
What is a Future and how do I use it?
(6 answers)
Closed 2 years ago.
I am trying to convert the response from api to string in flutter. I am still a beginner to Flutter so I'm sorry about that.
Whenever I do the get and assign it to a variable, the value is always 'Instance of Future' rather than the actual text? So does this mean I have to convert it to text?
This is the code that I used.
gethttps() async{
var response = await http.get(url);
print("JSON" + response.body);
String data = response.body;
data = json.decode(response.body.toString());
return data;
}
CALL FROM OUTSIDE THE FUNCTION
var response = gethttps();
you can follow the link : https://stackoverflow.com/a/50296350/6413387
Basically you have two options
gethttps().then((result) {
print(result);
setState(() {
someVal = result;
})
})
or
funcThatMakesAsyncCall() async {
String result = await gethttps();
print(result);
setState(() {
someVal = result;
})
}
You can change signature of function to this one
Future<String> gethttps() async{....}
and then use
var data=await gethttps();
user await

How do I return to the user stream in flutter

I'm having an issue return a Stream to a StreamBuilder widget in a flutter. I'm trying to access a custom class that is stored token.
class User {
String token;
User({this.token});
}
===============================
class AuthService {
String url = 'https://reqres.in/api/login';
String token = '';
// {
// "email": "eve.holt#reqres.in",
// "password": "cityslicka"
// }
Map data;
Future signIn(String email, String password) async {
final response =
await post(url, body: {'email': email, 'password': password});
data = jsonDecode(response.body);
print(data['token']);
token = data['token'];
_userFromDatabaseUser(data);
return data;
}
//create user obj based on the database user
User _userFromDatabaseUser(Map user) {
return user != null ? User(token: user['token']) : null;
}
//user stream for provider
Stream<User> get user {
return .................. ;
}
You could use a stream controller:
class AuthService {
final String url = 'https://reqres.in/api/login';
final controller = StreamController<User>();
Future<User> signIn(String email, String password) async {
final response = await post(url, body: {'email': email, 'password': password});
final data = jsonDecode(response.body);
final user = _userFromDatabaseUser(data);
controller.add(user);
return user;
}
//create user obj based on the database user
User _userFromDatabaseUser(Map user) {
return user != null ? User(token: user['token']) : null;
}
//user stream for provider
Stream<User> get user {
return controller.stream;
}
Please note that this approach is a simplistic example that has some flaws, you should read up on it in the documentation.
If you use this for the purpose you describe, you may want to look into the bloc pattern and it's implementation as flutter-bloc. It might seem easier to do the user in this way by hand, but once you reach the point where you have multiple of those streams, you may want a more structured approach.
You can use
Stream<User> get user async*{
yield .................. ;
}
you can use yield keyword when you want to return stream object.
2nd way you can use a stream controller. You can add value in controller and
listen wherever you want to listen in your app there is no need to return stream

Singleton class for http requests

Can you give some advice how to design class for api requests in flutter? I'm ios developer and I used singleton classes with alamofire. If you provide some code it would be great!
class Client: ApiBase {
static let shared = Client()
private override init() {}
func login(phoneNumber: String, password: String, completion: #escaping(_ error: String?) -> Void) {
let params: [String : String] = [
"userId" : phoneNumber,
"password" : password,
]
baseRequest(route: ApiRouter.login(), params: params) { (response) in
if let json = response.json {
Session.current.sessionId = json["sessionId"].string
}
completion(response.error)
}
}
}
How login method called:
#IBAction func singin(_ sender: TransitionButton) {
Client.shared.login(phoneNumber: "12312", password: "123") { (error) in
guard error == nil else {
// show error
return
}
// navigate to home page
}
}
In flutter you don't have to deal with the relative nastiness of IBActions, protocols as callback, or retain cycles, and you have async and await to help out.
There's a few ways you could do the API calls - one would be to simply put them right in the same code as your UI. That has downsides, but it is certainly readable.
class WhateverMyComponentIsState extends State<WateverMyComponentIs> {
Future<String> _doLogin({#required String phoneNumber, #required String password}) async {
final response = await http.post(LOGIN_URL, body: {'userId': phoneNumber, 'password': password})
if (response.statusCode == 200) {
final jsonResponse = jsonDecode(body);
return jsonResponse['sessionId'];
} else {
... error handling
}
}
String phoneNumber;
String password;
#override
Widget build(BuildContext context) {
return ...(
child: FlatButton(
onPressed: () async {
final sessionId = await _doLogin(phoneNumber: phoneNumber, password: password);
... do whatever - setState(() => loggedIn = true), or Navigator.push ...
}
),
)
}
}
If you wanted, you could extract all of the api calls into a different class - they could be static methods, but that makes it so that it's harder to write good tests if you ever decide to do that.
My personal recommendation is to use a form of more or less 'dependency injection', by utilizing InheritedWidget to provide an implementation of a class that actually performs the login (and could hold the sessionId). Rather than implementing all of that yourself, though, you could use the ScopedModel plugin which I personally like very much as it greatly reduces the amount of boilerplate needed.
If you use ScopedModel properly (which I'll leave as an exercise for you - I'm pretty sure there's other questions about that), you can use it or a class it provides to do the http request, and then have the sessionId stored in the ScopedModel.
The beauty of that is that if you were to ever get to writing tests (or have to deal with two slightly servers, etc), you could then replace the ScopedModel with a different ScopedModel which implemented the same interface but doesn't actually perform http requests or performs them differently.
In flutter you should create a class something like this
class User {
String name;
String pass;
User({
this.name,
this.pass,
});
User.fromJson(Map<String, dynamic> json) {
name = json['name'];
pass= json['pass'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['pass'] = this.pass;
return data;
}
}
Now create the list of type User class something like this
final List<User> user;
Now call the URL (API) for user Auth
Future<void> validateUsr() async {
var client = new http.Client();
try {
var response = await client.get(
'https://xxxxxxxx/wp-json/jwt-auth/v1/token?username=xxxxx2&password=xxxxxx');
if (response.statusCode == 200) {
var data = json.decode(response.body);
var list = data as List;
setState(() {
user=list.map<User>((i) => User.fromJson(i)).toList();
});
} else {
print('Somthing went wrong');
}
} catch (e) {
print(e);
} finally {
client.close();
}
}
Hope this helped you