2

How would you simply implement this function:

String fetchUrlBodyAsString(String url) {
  ...
}

Usage:

String schema = fetchUrlBodyAsString("http://json-schema.org/draft-04/schema#");

This thread Using dart to download a file explains a good way to get to the data from a main function. But if you try it you see that the real work happens after leaving main. I think that the synchronous function that I want to create is difficult using HttpClient because it is trying to get an async api to work synchronously. According to this thread that may not be possible: https://groups.google.com/a/dartlang.org/d/msg/misc/kAgayQyaPhQ/wonJ776_FGIJ

What is a Dart way to implement this in a non-browser/console setting?

Community
  • 1
  • 1
user1338952
  • 3,233
  • 2
  • 27
  • 41
  • First to verify, are you looking for server-side download (cli application) or client-side. Currently they use separate libraries with slightly different api's. – Matt B Aug 23 '13 at 17:23
  • Eventually both :-) - but initially server side (non-browser/console). – user1338952 Aug 23 '13 at 17:38
  • 1
    Until there is some sync API, this may not be possible with HttpClient. However, if you REALLY want this, you COULD write your own http client with [Sockets](http://api.dartlang.org/docs/releases/latest/dart_io/Socket.html). Yeah, I know, not really helpful, but it is a way, strictly speaking. – MarioP Aug 26 '13 at 15:12

3 Answers3

7

The using of asynchronous methods is really infectious. Once you start using Future inside a function you have to return a Future as result. So your fetchUrlBodyAsString function can look like :

import 'dart:io';
import 'dart:async';

Future<String> fetchUrlBodyAsString(String url) =>
  new HttpClient().getUrl(Uri.parse(url))
    .then((HttpClientRequest request) => request.close())
    .then((HttpClientResponse response) =>
        response.transform(new StringDecoder()).join());

main() {
  final url = "http://json-schema.org/draft-04/schema#";
  Future<String> schema = fetchUrlBodyAsString(url);
  schema.then(handleContent);
}

handleContent(String content) {
  print(content); // or do what you want with content.
}

or with async/await:

import 'dart:io';
import 'dart:async';

Future<String> fetchUrlBodyAsString(String url) async {
  var request = await new HttpClient().getUrl(Uri.parse(url));
  var response = await request.close();
  return response.transform(new StringDecoder()).join();
}

main() async {
  final url = "http://json-schema.org/draft-04/schema#";
  handleContent(await fetchUrlBodyAsString(url));
}

handleContent(String content) {
  print(content); // or do what you want with content.
}
Alexandre Ardhuin
  • 71,959
  • 15
  • 151
  • 132
  • Thanks - this is helpful and I will likely work to that direction, but only after it is confirmed that Dart has no existing synchronous API already. Can you confirm this? -MarioP's comment implies a sync API does not exist but may be in the works. Is this accurate? I would be surprised grabbing data synchronously is not already available. – user1338952 Aug 26 '13 at 16:20
  • I am not aware that such a synchronous API exists. – Alexandre Ardhuin Aug 26 '13 at 20:56
  • 1
    @user1338952 I didn't want to imply that there is something in the works. If you want to wait for this feature based on my comment, you probably shouldn't. AFAIK, no sync API for http connections exists in dart:io, and I can't find a feature request concerning this. However, it seems there is a [general solution planned](http://code.google.com/p/dart/issues/detail?id=104) – MarioP Aug 27 '13 at 08:15
  • Thanks, I'm not waiting. I just did not want to change my APIs if not necessary. It is very interesting and a bit scary that a decision about a low level API can not be encapsulated and necessarily ripples all the way up. – user1338952 Aug 27 '13 at 11:08
3

You can make synchronous http requests by using HttpRequest.open and setting async to false.

https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart-dom-html.HttpRequest#id_open

import 'dart:html';

String fetchUrlBodyAsString(String url) {

    var request = new HttpRequest()
        ..open('GET', url, async: false)
        ..send();

    return request.responseText;
}

String schema = fetchUrlBodyAsString("http://json-schema.org/draft-04/schema#");
Patrick Cornelissen
  • 7,968
  • 6
  • 48
  • 70
kinetifex
  • 96
  • 4
  • 1
    This is only available in the client (browser). The stand-alone VM does not support 'dart:html'. Stil looking for an synchronous version with the stand-alone VM. – Tina Hildebrandt Jan 29 '15 at 16:44
1

There is no way to turn an async API into a sync API; once you have a Future as a result, that is what you will have to deal with.

For your specific example, the only way to achieve what you want would be to build your own synchronous HTTP library from the ground up. Using asynchronous APIs in a synchronous manner is not possible.

Pixel Elephant
  • 20,649
  • 9
  • 66
  • 83