How Can I get a List object by HttpClientResponse? - dart

How can I get a List object in "result"? I tried with toList() method on "request" object, but I can't solve this.
import 'dart:io';
import 'dart:convert';
void main() async {
var request = await HttpClient().getUrl(Uri.parse('https://jsonplaceholder.typicode.com/posts')); // produces a request object
var response = await request.close(); // sends the request
// transforms and prints the response
var result;
await for (var contents in response.transform(Utf8Decoder())) {
result =contents;
}
print(result);
}
Thanks,
Daniel

Firstly, response.transform return multiple parts of result, you need to get all by joining them together:
var result = new StringBuffer();
await for (var contents in response.transform(Utf8Decoder())) {
result.write(contents);
}
Secondly, you result is just a "text" (in json format), not an "object" as you expect, you need to decode it:
List<dynamic> myList = jsonDecode(result.toString());
print(myList);

Simply the following
List elements = json.decode(response.body);

Related

How to return a Stream in Dart without looping through it

I have a Stream in my code, which I've done some modifications / transformations to. I'd like to return that Stream as the result of my function.
This code works:
Stream<int> returnStream2() async* {
var list = <int>[1,2,3];
var result = Stream<int>.fromIterable(list);
await for( var i in result ) {
yield i;
}
}
Why doesn't this simpler and more readable version work?
Stream<int> returnStream1() async* {
var list = <int>[1,2,3];
var result = Stream<int>.fromIterable(list);
return result;
}
I get an error message "Can't return a value from a generator function (using the 'async*' modifier)
Either use yield* as you already discovered, or just don't make the function an async* function. If this stream is the only thing you yield, you can just do:
Stream<int> returnStream1() {
var list = <int>[1,2,3];
var result = Stream<int>.fromIterable(list);
return result;
}
If you do other things, then yield* stream; or await for (var event in stream) yield event; are both options (they differ in how they handle error events from the stream, but for plain data events the two should be equivalent).
I just discovered the yield* keyword, which solves my problem:
Stream<int> returnStream1() async* {
var list = <int>[1,2,3];
var result = Stream<int>.fromIterable(list);
yield* result;
}

How to make a network request and return a json object in Dart

Making a network request is easy to Python and what makes it easy is that sync request.
In Dart, I can make a request like this:
HttpClient client = new HttpClient();
client.getUrl(Uri.parse("http://www.example.com/"))
.then((HttpClientRequest request) {
// Optionally set up headers...
// Optionally write to the request object...
// Then call close.
...
return request.close();
})
.then((HttpClientResponse response) {
// Process the response.
...
});
Obviously it's async request. In my opinion, above code can be reused many times. So I want to make a request and return a JSON object.
getResponse(String url) async {
HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.getUrl(Uri.parse(url));
HttpClientResponse response = await request.close();
String responseBody = await response.transform(utf8.decoder).join();
Map jsonResponse = jsonDecode(responseBody) as Map;
httpClient.close();
return jsonResponse;
}
As you see, the above method getResponse returns Future<dynamic>. So how can I call it and get the json value?
To get the dynamic from inside the Future you do one of the following:
// option 1 async method
MyAsyncMethod() async {
dynamic result = await getResponse("http://google.com");
if (result is Map) {
// process the data
}
}
// option 2 callback with .then()
MyNonAsyncMethod() {
getResponse("http://google.com").then ( (dynamic result) {
if (result is Map) {
// process the data
}
});
}
Note that your own async method can also return a Future<something> and be treated in the same two ways when called.
Where map is a nested Map<String, Dynamic> and result is an object of type of your creation that conforms to Json serialization interface (See this link).
To access Data in the map:
//given example json structure
var map = {
"myPropertyName":50,
"myArrayProperty":[
"anArrayEntry"
],
"mySubobject": {
"subObjectProperty":"someValue"
}
};
var myProperty = map["myPropertyName"]; // get a property value from the object
var myArrayEntry = map["myArrayProperty"][0]; // get first element of an array property
var mySubobjectPropertyValue = map["mySubobject"]["subObjectProperty"]; // get a property value from a subobject

Make a http request in dart whith dart:io

Hey I'm a beginner and I want to interact with an API with dart:io for fetch JSON files I can fetch the data with this code :
final HttpClient client = HttpClient();
client.getUrl(Uri.parse("https://api.themoviedb.org/3/movie/76341?api_key=fbe54362add6e62e0e959f0e7662d64e&language=fr"))
.then((HttpClientRequest request) {
return request.close();
})
.then((HttpClientResponse response) {
Map a;
print(a);
But I want to have a Map whith the JSON but I can't do it. If I could get a String that contains the JSON I could do it with
json.decode();
also know that the answer is stored in an int list that represents the utf8 values of the characters so with utf8.decode(responce.toList()) I can get the utf8 value but responce.toList() return a Future but even if it may be easy I don't know how to get the list.
import 'dart:convert';
import 'dart:io';
void main() async {
final client = HttpClient();
final request = await client.getUrl(Uri.parse(
'https://api.themoviedb.org/3/movie/76341?api_key=fbe54362add6e62e0e959f0e7662d64e&language=fr'));
final response = await request.close();
final contentAsString = await utf8.decodeStream(response);
final map = json.decode(contentAsString);
print(map);
}

returning a value in sync and await in dart

I am trying to understand the usage of async and await in Dart. Somehow I am having issues returning values in certain methods.
Consider the code below
Future<int> getMrn() async {
var mrnRef = await firebaseClient.child('mrn');
DataSnapshot ss;
StreamSubscription<Event> onValueSubscription = await mrnRef.onValue
.listen((event) {
ss = event.snapshot;
return ss.val();
});
//return Future<int> ss.val();
}
mrn is of type int which should be returned by getMrn method. However each time the returned ss.val() returns null. It seems that ss = event.snapshot is not seen in the last returned value
What is the correct way of doing this.
Thanks
In the code above, you're declaring anonymous function (event){..} as a callback, and your return statement relates to it, while your intention was to return from getMrn().
What are you actually need, is to complete a Future you're returning from getMrn() inside your callback.
Like this:
Future<int> getMrn() async {
var mrnRef = await firebaseClient.child('mrn');
Completer<int> c = new Completer<int>();
StreamSubscription<Event> onValueSubscription = await mrnRef.onValue
.listen((event) {
DataSnapshot ss = event.snapshot;
c.complete(ss.val());
});
return c.future;
}
but that code wouldn't work good if there second event appear in mrnRef.onValue stream. So, assuming mrnRef.onValue is a Stream, and you need only first event, it would be better to rewrite it this way:
Future<int> getMrn() async {
var mrnRef = await firebaseClient.child('mrn');
Event event = await mrnRef.onValue.first;
DataSnapshot ss = event.snapshot;
// note, you're implicitly returning a Future<int> here,
// because our function is asyncronous
return ss.val();
}

Future is completed before function-call is done

I'm working with two functions, both of them should return a future. A third function gets called when both of them are done. Right now the future is returned too early, so that my third function is called before my second function is completed.
Function1:
static var getObjectDataCompleter = new Completer();
static var fillObjectCompleter = new Completer();
static Future getObjectData(List jsonMap) {
for (int i = 0; i < jsonMap.length; i++) {
fillObjectCompleter = new Completer();
var request = buildRequest("GET", resourceUrl);
request.send();
request.onLoadEnd.listen((event) => fillObject(request));
}
if(fillObjectCompleter.isCompleted) {
getObjectDataCompleter.complete(null);
}
return getObjectDataCompleter.future;
}
Function2:
static Future fillObject(HttpRequest request) {
String responseText = request.response;
List stringJson = JSON.decode(responseText);
fillObjectCompleter.complete(null);
return fillObjectCompleter.future;
}
Function1 is returning the future before the call "fillObject()" is completed.
What am I doing wrong?
The function1-future should be returned when the "for-loop" is done and all "fillObject-calls" are completed.
Async code is just scheduled for later execution and the sync code continues executing without waiting for the async code. The method you pass ot Future.then(...) is executed when the scheduled async code is finished. You find a lot of such questions and examples tagged [:dart-async:] here on StackOverflow.
I have a hard time figuring out what you actually try to accomplish. Can you please explain in prosa what you actually try to accomplish, then I can try to fix your code example to do what you want it to do.
Usually there is no need to use a Completer in custom async functions. You just have to ensure that nested async calls are properly chained by always returning the future of the call.
See these two lines of the following code as example. The returns are important for the example to work.
return async.Future.forEach(jsonMap, (item) {
return request.onLoadEnd.first.then((event) => fillObject(event.target));
The Future returned from getObjectData completes after the response of all requests are processed.
import 'dart:html' as dom;
import 'dart:async' as async;
import 'dart:convert' show JSON;
class Xxx {
static async.Future getObjectData(List jsonMap) {
return async.Future.forEach(jsonMap, (item) {
//var request = new dom.HttpRequest();
//request.open("GET", "https://www.googleapis.com/discovery/v1/apis?fields=");
var request = buildRequest("GET", resourceUrl);
request.send();
return request.onLoadEnd.first.then((event) => fillObject(event.target));
});
}
static fillObject(dom.HttpRequest request) {
print('fillObject');
String responseText = request.response;
List stringJson = JSON.decode(responseText);
}
}
void main() {
var json = ['a', 'b', 'c'];
Xxx.getObjectData(json).then((_) => print('done'));
}
See https://www.dartlang.org/articles/event-loop for more details about async execution.

Resources