am trying to call a method which calls another method .. and depending on that method result i will continue with my method .. something like this:
void submit() async{
if (login) {
....
bool result = await Login("966" + phone, _data.code);
if (result) {
successpage();
} else {
.....
}
and login:
bool Login(String phone, String SMScode) {
http.post(baseUrl + loginURL + "?phone=" + phone + "&smsVerificationCode="+ SMScode,
headers: {
'content-type': 'application/json'
}).then((response) {
final jsonResponse = json.decode(Utf8Codec().decode(response.bodyBytes));
print("LOGIN: " + jsonResponse.toString());
Map decoded = json.decode(response.body);
print(decoded['success']);
if (decoded['success']) {
globals.token = decoded['token'];
globals.login = true;
}else{
globals.login = false;
}
});
return globals.login;
}
but this doesn't work and doesn't give me the result of the last bool i need .. how to solve this?
The asynchronous handling is incorrect in your program. Basically your Login function returns without waiting the http post.
The following update should work.
Future<bool> Login(String phone, String SMScode) async {
final response = await http.post('$baseUrl$loginURL?phone=$phone&smsVerificationCode=$SMScode',
headers: {'content-type': 'application/json'});
final jsonResponse = json.decode(Utf8Codec().decode(response.bodyBytes));
print("LOGIN: " + jsonResponse.toString());
Map decoded = json.decode(response.body);
print(decoded['success']);
if (decoded['success']) {
globals.token = decoded['token'];
globals.login = true;
} else {
globals.login = false;
}
return globals.login;
}
Related
I was trying to create a function to make a GET with query parameters. I was dealing with the Mangadex API and was to send a parameter called 'manga' as an array. I created the code as follows:
Future<http.Response> getCoverArtResponse(String mangaID) async {
var queryParameters = {
'limit': '10',
'manga': [mangaID] //Here
};
var unencodedPath = '/cover';
var response = await http.get(
Uri.https(authority, unencodedPath, queryParameters),
headers: {HttpHeaders.contentTypeHeader: 'application/json'});
return response;
}
However, the response was the following error:
{"result":"error","errors":[{"id":"9c346772-7b14-5982-b4b6-7b5888522762","status":400,"title":"validation_exception","detail":"Error validating \/manga: String value found, but an array is required","context":null}]}
How am I supposed to send the parameters? So far I have tried -
'manga': [mangaID]
'manga': '[$mangaID]'
None of them seem to work.
import 'dart:async';
import 'package:wnetworking/wnetworking.dart';
class MangaDex {
static const _base = 'https://api.mangadex.org';
static FutureOr<void> _getter({required String url, required Function(JMap item, int idx) onItem}) async {
await HttpReqService.getJson<JMap>(url)
.then((response) {
var results = response?['results'];
if (results != null) {
if (results is List) {
var i = 0;
results.forEach((manga) => onItem(manga, ++i));
} else {
print(response);
}
}
});
}
static FutureOr<void> cover({int limit = 10, int offset=0, String? mangaId, String? coverId}) async {
final mangas = mangaId != null ? '&manga[]=$mangaId' : '';
final covers = coverId != null ? '&ids[]=$coverId' : '';
final url = '$_base/cover?limit=$limit&offset=$offset$mangas$covers';
await _getter(
url: url,
onItem: (item, idx) {
print('$idx) "${item['data']?['attributes']?['fileName']}"');
print(' id: ${item['data']?['id']}\n');
},
);
}
}
void main(List<String> args) async {
await MangaDex.cover(mangaId: '32d76d19-8a05-4db0-9fc2-e0b0648fe9d0', limit: 2);
print('\nJob done');
}
Result:
1) "f5873770-80a4-470e-a11c-63b709d87eb3.jpg"
id: b6c7ce9c-e671-4f26-90b0-e592188e9cd6
2) "e9f926db-b469-48c4-8cc4-a8e523ad75ca.jpg"
id: 00aae6e0-46bb-4f92-a82a-1c740789b704
Job done
Replace wnetworking package with http package, and JMap with Map<String, dynamic>
NOTE: MangaDex Documentation is lacking and misleading about how to correctly use its endpoints.
I just got my first Lambda function written, but it does not work at this point.
I tried a number of variations in the code; partly following what I could think of and partly following what I could come across on the net; but all failed.
I want the Lambda function to listUsers in a UserPool and get an email for a given sub passed as parameter.
Here is the Swift function making the call to the Lambda function:
func getLambdaInfo() {
let lambdaInvoker = AWSLambdaInvoker.default(),
jsonObject:[String: Any] = ["sub" : "MY-USER-SUB"]
lambdaInvoker.invokeFunction("myLambdaFunc", jsonObject: jsonObject)
.continueWith(block: {
(task:AWSTask<AnyObject>) -> Any? in
if( task.error != nil) {
print("Error: \(task.error!)")
return nil
}
print("\(#function) ---- WE ARE HERE!!!!")
// Handle response in task.result:
if let JSONDictionary = task.result as? NSDictionary {
print("Result: \(JSONDictionary)")
}
return nil
})
}
Here is the Lambda function:
var AWS = require('aws-sdk/dist/aws-sdk-react-native');
exports.handler = async (event,context) => {
var params = {
UserPoolId: 'MY-POOL-ID',
AttributesToGet: ['email'],
Limit: '2'
};
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
cognitoidentityserviceprovider.listUsers(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
// How can I get this data sent in the response is probably the issue ??
});
const response = {
inBound: event.sub,
statusCode: 200,
body: JSON.stringify('Hello from Lambda!')
};
return response;
}
Here is what can be seen in the Xcode debugging console:
getLambdaInfo() ---- WE ARE HERE!!!!
Result: {
body = "\"Hello from Lambda!\"";
inBound = "MY-USER-SUB";
statusCode = 200;
}
I hope someone with more AWSLambda than me will be able to give me some hints concerning the changes I need to make in my code to get the result (email address) I want (into my Swift getLambdaInfo()).
You need to move your return statement in the callback of listUsers:
cognitoidentityserviceprovider.listUsers(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
// return a 500 error ?
}
else {
console.log(data);
const response = {
inBound: event.sub,
statusCode: 200,
body: JSON.stringify(data)
}
return response;
}
});
Since you're using the async pattern you can also do:
try {
const data = await cognitoidentityserviceprovider.listUsers(params).promise() // note the await and .promise() here
const response = {
inBound: event.sub,
statusCode: 200,
body: JSON.stringify(data)
}
return response;
} catch (err) {
// do something with err
}
Otherwise your Lambda function returns before your callback gets executed (async nature of JavaScript).
Based on the SharedPreferences class, I try to retrieve a preference value like so:
String loadIPAddress() {
SharedPreferences.getInstance().then((SharedPreferences prefs) {
try {
var loadedValue = prefs.getString('serverIPAddress');
print('loadIPAddress <= ' + loadedValue);
return loadedValue; // [1]
} catch (e) {
print('loadIPAddress <= NOPE');
return '---'; [2]
}
});
}
Unfortunately, this doesn't return a value each time.
Q: Does the 1 and [2] return statements return the value of loadIPAddress()?
No, as you've guessed, those returns return from the then callback.
To return from loadIPAddress, refactor it like this:
Future<String> loadIPAddress() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
try {
var loadedValue = prefs.getString('serverIPAddress');
print('loadIPAddress <= ' + loadedValue);
return loadedValue;
} catch (e) {
print('loadIPAddress <= NOPE');
return '---';
}
}
Note that having made loadIPAddress async, it now returns a Future, so you should call it like:
String ip = await loadIPAddress();
// or
loadIPAddress().then((String ip) {
// do something with ip - probably setState
});
I am calling an api. I am getting a streamed response after sending the request. But i cannot parse the response and convert it to String/JSON. This is where I am calling the api.
static Future<String> callDeviceListFetchApi() async {
Completer completer = new Completer();
String jsonResponse;
String url = Constants.BASE_URL + Constants.DEVICE_REGISTER_URL;
var client = new http.Client();
var request = new http.Request('GET', Uri.parse(url));
request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json';
request.headers[HttpHeaders.AUTHORIZATION] = '<auth code>';
await client.send(request).then((response) {
response.stream.bytesToString().then((value) {
print(value.toString());
jsonResponse = value.toString();
completer.complete(jsonResponse);
});
}).catchError((error) {
print(error.toString());
});
return completer.future;
}
I am getting the error,
Bad state: Stream has already been listened to Flutter error. Any idea why this is happening?
There's a couple of things wrong with your code. I think you have a slight misunderstanding about how Async and Futures work in dart - you should re-read the docs and this tutorial (part 1 and part 2).
Basically, the problem is that you were returning a 'Future' from an async function. If you return a future from an async function, it has issues (I don't know why the analyzer doesn't catch that).
Future<String> callDeviceListFetchApi() async {
Completer completer = new Completer();
String url = "<url>";
var client = new http.Client();
var request = new http.Request('GET', Uri.parse(url));
request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json';
request.headers[HttpHeaders.AUTHORIZATION] =
'<auth string>';
var response = await client.send(request);
String jsonResponse;
try {
var value = await response.stream.bytesToString();
print(value.toString());
jsonResponse = value.toString();
} catch (error) {
print(error.toString());
}
return completer.complete(jsonResponse);
}
Or not async:
Future<String> callDeviceListFetchApiNotAsync() {
String url = "<url>";
var client = new http.Client();
var request = new http.Request('GET', Uri.parse(url));
request.headers[HttpHeaders.CONTENT_TYPE] = 'application/json';
request.headers[HttpHeaders.AUTHORIZATION] =
'<auth string>';
Completer completer = new Completer();
return client.send(request).then((response) {
return response.stream.bytesToString();
}).then((value) {
print(value.toString());
return value.toString();
}).catchError((error) {
print(error.toString());
// if you use catchError, whatever you return from it
// is the value you'll get wherever you resolve the future.
return null;
});
}
But unless you're trying to do something I'm not seeing, there's a way easier way to do this (assuming all you want to do is get a string from a server):
Future<String> getList() async {
var response = await http.get("<url>", headers: {
HttpHeaders.CONTENT_TYPE: 'application/json',
HttpHeaders.AUTHORIZATION: '<auth string>',
});
if (response.statusCode == 200) {
return response.body;
} else {
throw Error();
}
}
I have two classes, a user_api_manager and a base_api_manager. From user_api_manager i call the get method of base_api_manager which performs an http get request and returns a Future<String>. The getrequest is performed but i am not pass the result to my user_api_manager class. The callback result is always null.
This is my user_api_manager.dart
static Future<Map<String,dynamic>> forgotPasswordAPI(String email) async{
String url = Constants.BASE_URL + Constants.FORGOT_PASSWORD_URL + email;
await BaseApiManager.get(url: url).then((val) {
var response = JSON.decode(val);
var status = response['status'];
String message = '';
print(response);
switch (response['status']) {
case Constants.SUCCESS:
message = Constants.SUCCESS_RESPONSE;
break;
case Constants.SERVER_ERROR:
message = Constants.SERVER_ERROR_MESSAGE;
break;
case Constants.UNAUTHORISED:
message = Constants.UNAUTHORISED_MESSAGE;
break;
}
return {'status':status,'message':message};
});
}
and here is my base_api_manager.dart
static Future<String> get({url : String,
parameters : Map ,
headers: Map }) async {
var client = new http.Client();
Map<String,dynamic> resultJSON;
final c = new Completer();
await client.get(url).then((response) { //response is always null
resultJSON = {
'status' : response.statusCode,
'body' : JSON.decode(response.body)
};
c.complete(resultJSON.toString());
return c.future;
});
}
How to solve this issue?
Move the return c.future outside of the response processing, i.e you want to return this from your get otherwise you will return null.
You can simplify the code. That should make it easier to locate the problem
static Future<String> get({url : String, parameters : Map, headers: Map }) async {
var client = new http.Client();
final response = await client.get(url);
print(response.body);
var resultJSON = {
'status' : response.statusCode,
'body' : JSON.decode(response.body)
};
return resultJSON.toString()
}
What does that code print?