dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.22k stars 1.57k forks source link

Fetch API returning Interceptor rather then Response #35751

Open rayk opened 5 years ago

rayk commented 5 years ago

Environment:

Issue Or Not Yes it's not behaving as described in the spec.

Area

Assumptions

  1. Fetch API should ultimately return a Response class, as it does in JS where the Response object is contained in the returned promise.
  2. The signature in dart the would be ...fetch(dynamic input, [ Map init ]) -> Future<Response>

Core Problem Fetch currently is returning an Interceptor and Dart does not appear to know about the Response type.

Reproduction The simplest reproduction I have managed is the following.

import 'dart:html';

class HttpGateway {
  final WorkerGlobalScope wgs = WorkerGlobalScope.instance;

  HttpGateway();

  Future get() async {
    Map call = {'method': 'get'};
    var result;
    await wgs
        .fetch('https://jsonplaceholder.typicode.com/todos/1', call)
        .then((res) {
      print(res.runtimeType);
      result = res;
    });
    return result;
  }
}

Calling the get from a test gives us the following. screen shot 2019-01-25 at 12 52 58 pm

Note: the [object Response] is from the test:

 test("Should fetch some data from external service.", () async {
      var result = await htg.get();
      print(result);
    });

OK this is not a show stopper, we have JSObject we should able to fish out the properties and with getProperty(dynamic o, dynamic property) from js/js_utils, for example:

import 'dart:html';

import 'package:js/js_util.dart';

class HttpGateway {
  final WorkerGlobalScope wgs = WorkerGlobalScope.instance;

  HttpGateway();

  Future get() async {
    Map call = {'method': 'get'};
    var result;
    await wgs
        .fetch('https://jsonplaceholder.typicode.com/todos/1', call)
        .then((res) {
      print(res.runtimeType);
      var status = getProperty(res, 'status');
      result = res;
    });
    return result;
  }
}

So I just fish out 'status' and assign it to status.

screen shot 2019-01-25 at 1 02 34 pm

Interestingly, with a bit digging, namely:

Future get() async {
    Map call = {'method': 'get'};
    var result;
    await wgs
        .fetch('https://jsonplaceholder.typicode.com/todos/1', call)
        .then((res) {
      print(res.runtimeType);
      var status = getProperty(res, 'status');
      var header = getProperty(res, 'headers');
      var url = getProperty(res, 'url');
      var body = getProperty(res, 'body');
      print('status: $status');
      print('header: $header');
      print('url: $url');
      print('body: $body');

      result = res;
    });
    return result;
  }

We are gifted with :

screen shot 2019-01-25 at 1 10 05 pm

So not very helpful.

Expected Behaviour

Thanks in advance..

kevmoo commented 5 years ago

@sigmundch @terrylucas – care to take a look?

rayk commented 5 years ago

Hey guys @kevmoo @sigmundch any thoughts on this one. If not a hot item, let me and I will go back to good old XMLHttp..

sigmundch commented 5 years ago

I'm not sure on this one, it seems like dart:html doesn't even have a definition for those types - @terrylucas, any clues?

rayk commented 5 years ago

Hey guys (@kevmoo @sigmundch ), should we close this issue or cast it into something else. I think the situation is that there is isn't a complete implementation of fetch in dart:html .

Thanks in advance.

kevmoo commented 5 years ago

We did our own thing so we could have one experience for browsers with and without fetch – IIRC.

We might want to look at this again, especially given our plans WRT browser support - https://groups.google.com/a/dartlang.org/forum/#!topic/announce/x7eDinVT6fM

MichealReed commented 4 years ago

Still unable to use fetch because of this. I believe the future should return a Response object for further use. I am trying to fetch an image and get the blob data per https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful.

sigmundch commented 4 years ago

@MichealReed thanks for following up.

This is still not fixed in dart:html, but we thought you would be able to workaround this by using the callMethod and getProperty methods in dart:js_util.

For example:

import 'dart:js_util' as js_util;

...
main() {
   ...
   var promise = js_util.callMethod(wgs, 'fetch', [...]);
   var response = await js_util.promiseToFuture(promise);
   if (js_util.getProperty(response, 'ok')) {
      js_util.callMethod(response, 'blob', []));
   }
}

There is a similar example near the end of @rayk original's message showing what they did for providing more detailed arguments to fetch.

Would these workarounds unblock your use case?

MichealReed commented 4 years ago

I did not have any luck with getProperty and callMethod. I did find a different workaround by casting the response object to html.Body, but it would make sense for dart:html to implement the objects per spec.

sgehrman commented 2 years ago

still broken....

kevmoo commented 2 years ago

@sgehrman – make sure to 👍 the issue!

connor-oleary-pieces commented 2 years ago

Still broken for me. Would love to see fetch return a Response object. Would help immensely for service workers in the browser, especially for chromium-based web extensions where the background script doesnt have direct access to XMLHttp (and I believe support for it was dropped recently).