Null while returning a Future in Dart - dart

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?

Related

I keep getting Instance of 'Future<dynamic>' even though I tried to use the method getCoinData() with return type void and it is functioning well

Future<dynamic> getCoinData() async{
String url = 'https://rest.coinapi.io/v1/exchangerate/BTC/USD?apikey=$apikey';
final parsedUrl = Uri.parse(url);
http.Response response = await http.get(parsedUrl);`enter code here`
if(response.statusCode == 200){
var data = response.body;
var exchangeRate = jsonDecode(data)['rate'];
return exchangeRate;
}else{
print('An error occured, statusCode: ${response.statusCode}');
}
}
I'm trying to get the exchange rate and used it another dart file.

How to send a GET request with an array as a parameter?

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.

getting current result from method inside another method

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;
}

Convert String to GET request Parameter in Dart using standard library

I have a multiword String that I'd like to convert to a GET request parameter.
I have an API endpoint /search that takes in the parameter query. Now typically your request would look like http://host/search?query=Hello+World.
I have a String Hello World that I'd like to convert to this URL encoded parameter.
Ofcourse, I could just write the logic to break it into words and add a + in between but I was wondering if the URI class could help with this
I'm using Dart's httpClient to make a request.
Future<String> _getJsonData(String queryToSearch) async {
List data = new List();
var httpClient = new HttpClient();
var request = await httpClient.getUrl(Uri.parse(
config['API_ENDPOINT'] + '/search?query=' +
queryToSearch));
var response = await request.close();
if (response.statusCode == HttpStatus.OK) {
var jsonString = await response.transform(utf8.decoder).join();
data = json.decode(jsonString);
print(data[0]);
return data[0].toString();
} else {
return "{}";
}
}
Essentially, need to encode queryToSearch as the URL parameter.
You can use Uri.http(s) which wrap everythings (query, host, and path) together and encode them accordingly.
final uri = new Uri.http(config['API_ENDPOINT'], '/search', {"query": queryToSearch});
The Uri class provides methods for that
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeQueryComponent.html
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeFull.html
https://api.dartlang.org/stable/1.24.3/dart-core/Uri/encodeComponent.html
You can use Uri.parse(url_string) if you have the full URL in this way.
final String accountEndPoint = 'https://api.npoint.io/2e4ef87d9ewqf01e481e';
Future<Account> getAccountData() async {
try {
final uri = Uri.parse(accountEndPoint); // <===
final response = await http.get(uri);
if (response.statusCode == 200) {
Map<String, dynamic> accountJson = jsonDecode(response.body);
return Future.value(Account.fromJson(accountJson));
} else {
throw Exception('Failed to get account');
}
} catch (e) {
return Future.error(e);
}
}

Bad state: Stream has already been listened to Flutter error

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();
}
}

Resources