From 2e491a7c54ebb77a1552cde4cda7e638af866e82 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kl=C4=81vs=20Pried=C4=ABtis?= <klavs@prieditis.lv>
Date: Sun, 16 Feb 2020 19:21:40 +0200
Subject: [PATCH 1/2] feat: drop Link layer in favor of package:gql_link and
 package:gql_exec

BREAKING CHANGE: Link layer is now implemented via package:gql_link and package:gql_exec
---
 packages/graphql/example/bin/main.dart        |  17 +-
 packages/graphql/example/pubspec.yaml         |   4 +-
 packages/graphql/lib/client.dart              |   9 -
 packages/graphql/lib/internal.dart            |   3 -
 .../legacy_socket_client.dart                 | 408 -------------
 .../legacy_socket_api/legacy_socket_link.dart |  97 ----
 .../graphql/lib/src/core/query_manager.dart   |  74 +--
 .../graphql/lib/src/core/query_options.dart   |   9 +-
 .../lib/src/core/raw_operation_data.dart      |  25 +-
 .../lib/src/exceptions/exceptions.dart        |  14 +-
 .../lib/src/exceptions/graphql_error.dart     |  61 --
 .../src/exceptions/io_network_exception.dart  |  20 -
 .../exceptions/network_exception_stub.dart    |  31 -
 .../src/exceptions/operation_exception.dart   |   2 +-
 packages/graphql/lib/src/graphql_client.dart  |  13 +-
 .../graphql/lib/src/link/auth/link_auth.dart  |  38 --
 .../lib/src/link/error/link_error.dart        |  70 ---
 .../graphql/lib/src/link/fetch_result.dart    |  19 -
 .../src/link/http/fallback_http_config.dart   |  24 -
 .../lib/src/link/http/http_config.dart        |  43 --
 .../graphql/lib/src/link/http/link_http.dart  | 373 ------------
 .../http/link_http_helper_deprecated_io.dart  |  34 --
 .../link_http_helper_deprecated_stub.dart     |  15 -
 packages/graphql/lib/src/link/link.dart       |  43 --
 packages/graphql/lib/src/link/operation.dart  |  51 --
 .../src/link/web_socket/link_web_socket.dart  |  55 --
 packages/graphql/lib/src/socket_client.dart   | 383 ------------
 packages/graphql/lib/src/utilities/file.dart  |   3 -
 .../graphql/lib/src/utilities/file_html.dart  |  28 -
 .../graphql/lib/src/utilities/file_io.dart    |  23 -
 .../graphql/lib/src/utilities/file_stub.dart  |   6 -
 .../graphql/lib/src/websocket/messages.dart   | 224 --------
 packages/graphql/lib/utilities.dart           |   1 -
 packages/graphql/pubspec.yaml                 |   8 +-
 .../test/anonymous_operations_test.dart       | 169 +++---
 .../graphql/test/graphql_client_test.dart     | 207 ++++---
 packages/graphql/test/helpers.dart            |  14 -
 .../test/link/error/link_error_test.dart      | 110 ----
 .../test/link/http/link_http_test.dart        | 543 ------------------
 packages/graphql/test/link/link_test.dart     |  36 --
 .../test/multipart_upload_io_test.dart        |  94 ---
 .../graphql/test/multipart_upload_test.dart   | 202 -------
 packages/graphql/test/socket_client_test.dart | 178 ------
 .../test/websocket_legacy_io_test.dart        |  96 ----
 .../graphql/test/websocket_legacy_test.dart   |  54 --
 packages/graphql/test/websocket_test.dart     |  37 --
 .../lib/src/widgets/subscription.dart         |  17 +-
 packages/graphql_flutter/pubspec.yaml         |   3 +-
 48 files changed, 284 insertions(+), 3704 deletions(-)
 delete mode 100644 packages/graphql/lib/legacy_socket_api/legacy_socket_client.dart
 delete mode 100644 packages/graphql/lib/legacy_socket_api/legacy_socket_link.dart
 delete mode 100644 packages/graphql/lib/src/exceptions/graphql_error.dart
 delete mode 100644 packages/graphql/lib/src/exceptions/io_network_exception.dart
 delete mode 100644 packages/graphql/lib/src/exceptions/network_exception_stub.dart
 delete mode 100644 packages/graphql/lib/src/link/auth/link_auth.dart
 delete mode 100644 packages/graphql/lib/src/link/error/link_error.dart
 delete mode 100644 packages/graphql/lib/src/link/fetch_result.dart
 delete mode 100644 packages/graphql/lib/src/link/http/fallback_http_config.dart
 delete mode 100644 packages/graphql/lib/src/link/http/http_config.dart
 delete mode 100644 packages/graphql/lib/src/link/http/link_http.dart
 delete mode 100644 packages/graphql/lib/src/link/http/link_http_helper_deprecated_io.dart
 delete mode 100644 packages/graphql/lib/src/link/http/link_http_helper_deprecated_stub.dart
 delete mode 100644 packages/graphql/lib/src/link/link.dart
 delete mode 100644 packages/graphql/lib/src/link/operation.dart
 delete mode 100644 packages/graphql/lib/src/link/web_socket/link_web_socket.dart
 delete mode 100644 packages/graphql/lib/src/socket_client.dart
 delete mode 100644 packages/graphql/lib/src/utilities/file.dart
 delete mode 100644 packages/graphql/lib/src/utilities/file_html.dart
 delete mode 100644 packages/graphql/lib/src/utilities/file_io.dart
 delete mode 100644 packages/graphql/lib/src/utilities/file_stub.dart
 delete mode 100644 packages/graphql/lib/src/websocket/messages.dart
 delete mode 100644 packages/graphql/lib/utilities.dart
 delete mode 100644 packages/graphql/test/link/error/link_error_test.dart
 delete mode 100644 packages/graphql/test/link/http/link_http_test.dart
 delete mode 100644 packages/graphql/test/link/link_test.dart
 delete mode 100644 packages/graphql/test/multipart_upload_io_test.dart
 delete mode 100644 packages/graphql/test/multipart_upload_test.dart
 delete mode 100644 packages/graphql/test/socket_client_test.dart
 delete mode 100644 packages/graphql/test/websocket_legacy_io_test.dart
 delete mode 100644 packages/graphql/test/websocket_legacy_test.dart
 delete mode 100644 packages/graphql/test/websocket_test.dart

diff --git a/packages/graphql/example/bin/main.dart b/packages/graphql/example/bin/main.dart
index 2d224c90a..ab184ad68 100644
--- a/packages/graphql/example/bin/main.dart
+++ b/packages/graphql/example/bin/main.dart
@@ -1,10 +1,13 @@
 import 'dart:io' show stdout, stderr, exit;
 
 import 'package:args/args.dart';
+import 'package:gql_http_link/gql_http_link.dart';
+import 'package:gql_link/gql_link.dart';
 import 'package:graphql/client.dart';
 
 import './graphql_operation/mutations/mutations.dart';
 import './graphql_operation/queries/readRepositories.dart';
+
 // to run the example, create a file ../local.dart with the content:
 // const String YOUR_PERSONAL_ACCESS_TOKEN =
 //    '<YOUR_PERSONAL_ACCESS_TOKEN>';
@@ -15,17 +18,13 @@ ArgResults argResults;
 
 // client - create a graphql client
 GraphQLClient client() {
-  final HttpLink _httpLink = HttpLink(
-    uri: 'https://api.github.com/graphql',
-  );
-
-  final AuthLink _authLink = AuthLink(
-    // ignore: undefined_identifier
-    getToken: () async => 'Bearer $YOUR_PERSONAL_ACCESS_TOKEN',
+  final Link _link = HttpLink(
+    'https://api.github.com/graphql',
+    defaultHeaders: {
+      'Authorization': 'Bearer $YOUR_PERSONAL_ACCESS_TOKEN',
+    },
   );
 
-  final Link _link = _authLink.concat(_httpLink);
-
   return GraphQLClient(
     cache: InMemoryCache(),
     link: _link,
diff --git a/packages/graphql/example/pubspec.yaml b/packages/graphql/example/pubspec.yaml
index a73bdaee6..fce16de6b 100644
--- a/packages/graphql/example/pubspec.yaml
+++ b/packages/graphql/example/pubspec.yaml
@@ -6,7 +6,9 @@ environment:
   sdk: ">=2.6.0 <3.0.0"
 
 dependencies:
-  args: 
+  args:
+  gql_link: ^0.2.3
+  gql_http_link: ^0.2.7
   graphql:
     path: ..
 
diff --git a/packages/graphql/lib/client.dart b/packages/graphql/lib/client.dart
index a11f2b297..00c91ddaa 100644
--- a/packages/graphql/lib/client.dart
+++ b/packages/graphql/lib/client.dart
@@ -10,12 +10,3 @@ export 'package:graphql/src/core/query_options.dart';
 export 'package:graphql/src/core/query_result.dart';
 export 'package:graphql/src/exceptions/exceptions.dart';
 export 'package:graphql/src/graphql_client.dart';
-export 'package:graphql/src/link/auth/link_auth.dart';
-export 'package:graphql/src/link/error/link_error.dart';
-export 'package:graphql/src/link/fetch_result.dart';
-export 'package:graphql/src/link/http/link_http.dart';
-export 'package:graphql/src/link/link.dart';
-export 'package:graphql/src/link/operation.dart';
-export 'package:graphql/src/link/web_socket/link_web_socket.dart';
-export 'package:graphql/src/socket_client.dart';
-export 'package:graphql/src/websocket/messages.dart';
diff --git a/packages/graphql/lib/internal.dart b/packages/graphql/lib/internal.dart
index 79b90c4c1..d38c2a107 100644
--- a/packages/graphql/lib/internal.dart
+++ b/packages/graphql/lib/internal.dart
@@ -1,6 +1,3 @@
 export 'package:graphql/src/utilities/helpers.dart';
 
 export 'package:graphql/src/core/observable_query.dart';
-
-export 'package:graphql/src/link/operation.dart';
-export 'package:graphql/src/link/fetch_result.dart';
diff --git a/packages/graphql/lib/legacy_socket_api/legacy_socket_client.dart b/packages/graphql/lib/legacy_socket_api/legacy_socket_client.dart
deleted file mode 100644
index b47f5ccb2..000000000
--- a/packages/graphql/lib/legacy_socket_api/legacy_socket_client.dart
+++ /dev/null
@@ -1,408 +0,0 @@
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-import 'dart:typed_data';
-
-import 'package:meta/meta.dart';
-import 'package:rxdart/rxdart.dart';
-
-import 'package:uuid_enhanced/uuid.dart';
-
-import 'package:graphql/src/websocket/messages.dart';
-
-enum SocketConnectionState { NOT_CONNECTED, CONNECTING, CONNECTED }
-
-@deprecated
-class SocketClientConfig {
-  const SocketClientConfig({
-    this.autoReconnect = true,
-    this.queryAndMutationTimeout = const Duration(seconds: 10),
-    this.inactivityTimeout = const Duration(seconds: 30),
-    this.delayBetweenReconnectionAttempts = const Duration(seconds: 5),
-    this.compression = CompressionOptions.compressionDefault,
-    this.initPayload,
-    // @todo please review this ignore rule
-    // ignore: deprecated_member_use_from_same_package
-    @deprecated this.legacyInitPayload,
-  });
-
-  /// Whether to reconnect to the server after detecting connection loss.
-  final bool autoReconnect;
-
-  /// The duration after which the connection is considered unstable, because no keep alive message
-  /// was received from the server in the given time-frame. The connection to the server will be closed.
-  /// If [autoReconnect] is set to true, we try to reconnect to the server after the specified [delayBetweenReconnectionAttempts].
-  ///
-  /// If null, the keep alive messages will be ignored.
-  final Duration inactivityTimeout;
-
-  /// The duration that needs to pass before trying to reconnect to the server after a connection loss.
-  /// This only takes effect when [autoReconnect] is set to true.
-  ///
-  /// If null, the reconnection will occur immediately, although not recommended.
-  final Duration delayBetweenReconnectionAttempts;
-
-  // The duration after which a query or mutation should time out.
-  // If null, no timeout is applied, although not recommended.
-  final Duration queryAndMutationTimeout;
-
-  final CompressionOptions compression;
-
-  /// The initial payload that will be sent to the server upon connection.
-  /// Can be null, but must be a valid json structure if provided.
-  final dynamic initPayload;
-
-  final Map<String, dynamic> legacyInitPayload;
-
-  InitOperation get initOperation {
-    if (legacyInitPayload != null) {
-      print(
-        'WARNING: Using a legacyInitPayload which will be removed soon. '
-        'If you need this particular payload serialization behavior, '
-        'please comment on this issue with details on your usecase: '
-        'https://github.com/zino-app/graphql-flutter/pull/277',
-      );
-      // @todo please review this ignore rule
-      // ignore: deprecated_member_use_from_same_package
-      return LegacyInitOperation(legacyInitPayload);
-    }
-    return InitOperation(initPayload);
-  }
-}
-
-/// @deprecated Old SocketClient that accepts and handles headers.
-/// WebSocket headers are not usable in the browser.
-/// So, to encourage universality,
-/// they are not usable in the main socket link and client any longer
-///
-/// Wraps a standard web socket instance to marshal and un-marshal the server /
-/// client payloads into dart object representation.
-///
-/// This class also deals with reconnection, handles timeout and keep alive messages.
-///
-/// It is meant to be instantiated once, and you can let this class handle all the heavy-
-/// lifting of socket state management. Once you're done with the socket connection, make sure
-/// you call the [dispose] method to release all allocated resources.
-@deprecated
-class SocketClient {
-  SocketClient(
-    this.url, {
-    this.protocols = const <String>[
-      'graphql-ws',
-    ],
-    this.headers = const <String, String>{
-      'content-type': 'application/json',
-    },
-    this.config = const SocketClientConfig(),
-    @visibleForTesting this.randomBytesForUuid,
-  }) {
-    _connect();
-  }
-
-  Uint8List randomBytesForUuid;
-  final String url;
-  final SocketClientConfig config;
-  final Iterable<String> protocols;
-  final Map<String, dynamic> headers;
-  final BehaviorSubject<SocketConnectionState> _connectionStateController =
-      BehaviorSubject<SocketConnectionState>();
-
-  Timer _reconnectTimer;
-  WebSocket _socket;
-
-  @visibleForTesting
-  WebSocket get socket => _socket;
-
-  Stream<dynamic> _stream;
-
-  @visibleForTesting
-  @protected
-  Stream<dynamic> get stream => _stream ??= _socket.asBroadcastStream();
-
-  Stream<GraphQLSocketMessage> _messageStream;
-
-  StreamSubscription<ConnectionKeepAlive> _keepAliveSubscription;
-  StreamSubscription<GraphQLSocketMessage> _messageSubscription;
-
-  /// Connects to the server.
-  ///
-  /// If this instance is disposed, this method does nothing.
-  Future<void> _connect() async {
-    if (_connectionStateController.isClosed) {
-      return;
-    }
-
-    _connectionStateController.value = SocketConnectionState.CONNECTING;
-    print('Connecting to websocket: $url...');
-
-    try {
-      _socket = await WebSocket.connect(url,
-          protocols: protocols,
-          headers: headers,
-          compression: config.compression);
-      _connectionStateController.value = SocketConnectionState.CONNECTED;
-      print('Connected to websocket.');
-      _write(config.initOperation);
-
-      _stream ??= _socket.asBroadcastStream();
-      _messageStream = _stream.map<GraphQLSocketMessage>(_parseSocketMessage);
-
-      if (config.inactivityTimeout != null) {
-        _keepAliveSubscription = _messagesOfType<ConnectionKeepAlive>().timeout(
-          config.inactivityTimeout,
-          onTimeout: (EventSink<ConnectionKeepAlive> event) {
-            print(
-                "Haven't received keep alive message for ${config.inactivityTimeout.inSeconds} seconds. Disconnecting..");
-            event.close();
-            _socket.close(WebSocketStatus.goingAway);
-            _connectionStateController.value =
-                SocketConnectionState.NOT_CONNECTED;
-          },
-        ).listen(null);
-      }
-
-      _messageSubscription = _messageStream.listen(
-          (dynamic data) {
-            // print('data: $data');
-          },
-          onDone: () {
-            // print('done');
-            onConnectionLost();
-          },
-          cancelOnError: true,
-          onError: (dynamic e) {
-            print('error: $e');
-          });
-    } catch (e) {
-      onConnectionLost();
-    }
-  }
-
-  void onConnectionLost() {
-    print('Disconnected from websocket.');
-    _reconnectTimer?.cancel();
-    _keepAliveSubscription?.cancel();
-    _messageSubscription?.cancel();
-
-    if (_connectionStateController.isClosed) {
-      return;
-    }
-
-    if (_connectionStateController.value !=
-        SocketConnectionState.NOT_CONNECTED) {
-      _connectionStateController.value = SocketConnectionState.NOT_CONNECTED;
-    }
-
-    if (config.autoReconnect && !_connectionStateController.isClosed) {
-      if (config.delayBetweenReconnectionAttempts != null) {
-        print(
-            'Scheduling to connect in ${config.delayBetweenReconnectionAttempts.inSeconds} seconds...');
-
-        _reconnectTimer = Timer(
-          config.delayBetweenReconnectionAttempts,
-          () {
-            _connect();
-          },
-        );
-      } else {
-        Timer.run(() => _connect());
-      }
-    }
-  }
-
-  /// Closes the underlying socket if connected, and stops reconnection attempts.
-  /// After calling this method, this [SocketClient] instance must be considered
-  /// unusable. Instead, create a new instance of this class.
-  ///
-  /// Use this method if you'd like to disconnect from the specified server permanently,
-  /// and you'd like to connect to another server instead of the current one.
-  Future<void> dispose() async {
-    print('Disposing socket client..');
-    _reconnectTimer?.cancel();
-    await _socket?.close();
-    await _keepAliveSubscription?.cancel();
-    await _messageSubscription?.cancel();
-    await _connectionStateController?.close();
-    _stream = null;
-  }
-
-  static GraphQLSocketMessage _parseSocketMessage(dynamic message) {
-    final Map<String, dynamic> map =
-        json.decode(message as String) as Map<String, dynamic>;
-    final String type = (map['type'] ?? 'unknown') as String;
-    final dynamic payload = map['payload'] ?? <String, dynamic>{};
-    final String id = (map['id'] ?? 'none') as String;
-
-    switch (type) {
-      case MessageTypes.GQL_CONNECTION_ACK:
-        return ConnectionAck();
-      case MessageTypes.GQL_CONNECTION_ERROR:
-        return ConnectionError(payload);
-      case MessageTypes.GQL_CONNECTION_KEEP_ALIVE:
-        return ConnectionKeepAlive();
-      case MessageTypes.GQL_DATA:
-        final dynamic data = payload['data'];
-        final dynamic errors = payload['errors'];
-        return SubscriptionData(id, data, errors);
-      case MessageTypes.GQL_ERROR:
-        return SubscriptionError(id, payload);
-      case MessageTypes.GQL_COMPLETE:
-        return SubscriptionComplete(id);
-      default:
-        return UnknownData(map);
-    }
-  }
-
-  void _write(final GraphQLSocketMessage message) {
-    if (_connectionStateController.value == SocketConnectionState.CONNECTED) {
-      _socket.add(
-        json.encode(
-          message,
-          toEncodable: (dynamic m) => m.toJson(),
-        ),
-      );
-    }
-  }
-
-  /// Sends a query, mutation or subscription request to the server, and returns a stream of the response.
-  ///
-  /// If the request is a query or mutation, a timeout will be applied to the request as specified by
-  /// [SocketClientConfig]'s [queryAndMutationTimeout] field.
-  ///
-  /// If the request is a subscription, obviously no timeout is applied.
-  ///
-  /// In case of socket disconnection, the returned stream will be closed.
-  Stream<SubscriptionData> subscribe(
-      final SubscriptionRequest payload, final bool waitForConnection) {
-    final String id = Uuid.randomUuid(random: randomBytesForUuid).toString();
-    final StreamController<SubscriptionData> response =
-        StreamController<SubscriptionData>();
-    StreamSubscription<SocketConnectionState> sub;
-    final bool addTimeout = !payload.operation.isSubscription &&
-        config.queryAndMutationTimeout != null;
-
-    response.onListen = () {
-      final Stream<SocketConnectionState> waitForConnectedStateWithoutTimeout =
-          _connectionStateController
-              .startWith(
-                  waitForConnection ? null : SocketConnectionState.CONNECTED)
-              .where((SocketConnectionState state) =>
-                  state == SocketConnectionState.CONNECTED)
-              .take(1);
-
-      final Stream<SocketConnectionState> waitForConnectedState = addTimeout
-          ? waitForConnectedStateWithoutTimeout.timeout(
-              config.queryAndMutationTimeout,
-              onTimeout: (EventSink<SocketConnectionState> event) {
-                print('Connection timed out.');
-                response.addError(TimeoutException('Connection timed out.'));
-                event.close();
-                response.close();
-              },
-            )
-          : waitForConnectedStateWithoutTimeout;
-
-      sub = waitForConnectedState.listen((_) {
-        final Stream<GraphQLSocketMessage> dataErrorComplete =
-            _messageStream.where(
-          (GraphQLSocketMessage message) {
-            if (message is SubscriptionData) {
-              return message.id == id;
-            }
-
-            if (message is SubscriptionError) {
-              return message.id == id;
-            }
-
-            if (message is SubscriptionComplete) {
-              return message.id == id;
-            }
-
-            return false;
-          },
-        ).takeWhile((_) => !response.isClosed);
-
-        final Stream<GraphQLSocketMessage> subscriptionComplete = addTimeout
-            ? dataErrorComplete
-                .where((GraphQLSocketMessage message) =>
-                    message is SubscriptionComplete)
-                .take(1)
-                .timeout(
-                config.queryAndMutationTimeout,
-                onTimeout: (EventSink<GraphQLSocketMessage> event) {
-                  print('Request timed out.');
-                  response.addError(TimeoutException('Request timed out.'));
-                  event.close();
-                  response.close();
-                },
-              )
-            : dataErrorComplete
-                .where((GraphQLSocketMessage message) =>
-                    message is SubscriptionComplete)
-                .take(1);
-
-        subscriptionComplete.listen((_) => response.close());
-
-        dataErrorComplete
-            .where(
-                (GraphQLSocketMessage message) => message is SubscriptionData)
-            .cast<SubscriptionData>()
-            .listen((SubscriptionData message) => response.add(message));
-
-        dataErrorComplete
-            .where(
-                (GraphQLSocketMessage message) => message is SubscriptionError)
-            .listen(
-                (GraphQLSocketMessage message) => response.addError(message));
-
-        _write(StartOperation(id, payload));
-      });
-    };
-
-    response.onCancel = () {
-      sub?.cancel();
-      if (_connectionStateController.value == SocketConnectionState.CONNECTED &&
-          _socket != null) {
-        _write(StopOperation(id));
-      }
-    };
-
-    return response.stream;
-  }
-
-  /// These streams will emit done events when the current socket is done.
-
-  /// A stream that emits the last value of the connection state upon subscription.
-  Stream<SocketConnectionState> get connectionState =>
-      _connectionStateController.stream;
-
-  /// Filter `_messageStream` for messages of the given type of [GraphQLSocketMessage]
-  ///
-  /// Example usages:
-  /// `_messagesOfType<ConnectionAck>()` for init acknowledgments
-  /// `_messagesOfType<ConnectionError>()` for errors
-  /// `_messagesOfType<UnknownData>()` for unknown data messages
-  Stream<M> _messagesOfType<M extends GraphQLSocketMessage>() => _messageStream
-      .where((GraphQLSocketMessage message) => message is M)
-      .cast<M>();
-}
-
-/// The old implementation of [InitOperation]
-// @todo please review this ignore rule
-// ignore: deprecated_member_use_from_same_package
-@deprecated
-class LegacyInitOperation extends InitOperation {
-  LegacyInitOperation(dynamic payload) : super(payload);
-
-  @override
-  Map<String, dynamic> toJson() {
-    final Map<String, dynamic> jsonMap = <String, dynamic>{};
-    jsonMap['type'] = type;
-
-    if (payload != null) {
-      jsonMap['payload'] = json.encode(payload);
-    }
-
-    return jsonMap;
-  }
-}
diff --git a/packages/graphql/lib/legacy_socket_api/legacy_socket_link.dart b/packages/graphql/lib/legacy_socket_api/legacy_socket_link.dart
deleted file mode 100644
index e72109fd7..000000000
--- a/packages/graphql/lib/legacy_socket_api/legacy_socket_link.dart
+++ /dev/null
@@ -1,97 +0,0 @@
-import 'package:meta/meta.dart';
-import 'package:graphql/src/link/fetch_result.dart';
-import 'package:graphql/src/link/link.dart';
-import 'package:graphql/src/link/operation.dart';
-import 'package:graphql/src/socket_client.dart';
-import 'package:graphql/src/websocket/messages.dart';
-
-/// @deprecated Old SocketClient that accepts and handles headers.
-/// WebSocket headers are not usable in the browser.
-/// So, to encourage universality,
-/// they are not usable in the main socket link and client any longer
-///
-/// A websocket [Link] implementation to support the websocket transport.
-/// It supports subscriptions, query and mutation operations as well.
-///
-/// This link is aware of [AuthLink], so the headers specified there are automatically
-/// applied when connecting to the socket server, unless explicitly overridden by the [headers]
-/// parameter.
-///
-/// There's an option called [reconnectOnHeaderChange] that makes it possible to reconnect to the server when the
-/// headers have changed. For example, if the user logs in with another user account and the `Authorization` header changes.
-/// This could be desired because of the nature of websocket connections: headers can only be specified upon connecting.
-///
-/// NOTE: the actual socket connection will only get established after an [Operation] is handled by this [WebSocketLink].
-/// If you'd like to connect to the socket server instantly, call the [connectOrReconnect] method after creating this [WebSocketLink] instance.
-@deprecated
-class WebSocketLink extends Link {
-  /// Creates a new [WebSocketLink] instance with the specified config.
-  WebSocketLink({
-    @required this.url,
-    this.headers,
-    this.reconnectOnHeaderChange = true,
-    this.config = const SocketClientConfig(),
-  }) : super() {
-    if (headers != null) {
-      print(
-        'WARNING: Using direct websocket headers which will be removed soon, '
-        'as it is incompatable with dart:html. '
-        'If you need this direct header access, '
-        'please comment on this PR with details on your usecase: '
-        'https://github.com/zino-app/graphql-flutter/pull/323',
-      );
-    } else {
-      print(
-        'WARNING: You are using the deprecated websocket API, '
-        'but do not appear to need direct header access. '
-        'If you also do not need the legacyInitPayload, '
-        'please switch to the new link and client',
-      );
-    }
-    request = _doOperation;
-  }
-
-  final String url;
-  final Map<String, dynamic> headers;
-  final bool reconnectOnHeaderChange;
-  final SocketClientConfig config;
-
-  // cannot be final because we're changing the instance upon a header change.
-  SocketClient _socketClient;
-
-  Stream<FetchResult> _doOperation(Operation operation, [NextLink forward]) {
-    final Map<String, dynamic> concatHeaders = <String, dynamic>{};
-    final Map<String, dynamic> context = operation.getContext();
-    if (context != null && context.containsKey('headers')) {
-      concatHeaders.addAll(context['headers'] as Map<String, dynamic>);
-    }
-    // @todo deprecated
-    if (headers != null) {
-      concatHeaders.addAll(headers);
-    }
-
-    if (_socketClient == null) {
-      connectOrReconnect(headers: concatHeaders);
-    }
-
-    return _socketClient.subscribe(SubscriptionRequest(operation), true).map(
-        (SubscriptionData result) => FetchResult(
-            data: result.data,
-            errors: result.errors as List<dynamic>,
-            context: operation.getContext(),
-            extensions: operation.extensions));
-  }
-
-  /// Connects or reconnects to the server with the specified headers.
-  void connectOrReconnect({Map<String, dynamic> headers}) {
-    _socketClient?.dispose();
-    _socketClient = SocketClient(url, config: config);
-  }
-
-  /// Disposes the underlying socket client explicitly. Only use this, if you want to disconnect from
-  /// the current server in favour of another one. If that's the case, create a new [WebSocketLink] instance.
-  Future<void> dispose() async {
-    await _socketClient?.dispose();
-    _socketClient = null;
-  }
-}
diff --git a/packages/graphql/lib/src/core/query_manager.dart b/packages/graphql/lib/src/core/query_manager.dart
index 73c224b17..fdad03aa7 100644
--- a/packages/graphql/lib/src/core/query_manager.dart
+++ b/packages/graphql/lib/src/core/query_manager.dart
@@ -1,5 +1,7 @@
 import 'dart:async';
 
+import 'package:gql_exec/gql_exec.dart';
+import 'package:gql_link/gql_link.dart';
 import 'package:graphql/src/cache/cache.dart';
 import 'package:graphql/src/cache/normalized_in_memory.dart'
     show NormalizedInMemoryCache;
@@ -8,9 +10,6 @@ import 'package:graphql/src/core/observable_query.dart';
 import 'package:graphql/src/core/query_options.dart';
 import 'package:graphql/src/core/query_result.dart';
 import 'package:graphql/src/exceptions/exceptions.dart';
-import 'package:graphql/src/link/fetch_result.dart';
-import 'package:graphql/src/link/link.dart';
-import 'package:graphql/src/link/operation.dart';
 import 'package:graphql/src/scheduler/scheduler.dart';
 import 'package:meta/meta.dart';
 
@@ -104,35 +103,44 @@ class QueryManager {
     String queryId,
     BaseOptions options,
   ) async {
-    // create a new operation to fetch
-    final Operation operation = Operation.fromOptions(options)
-      ..setContext(options.context);
+    // create a new request to execute
+    final Request request = Request(
+      operation: Operation(
+        document: options.documentNode,
+        operationName: options.operationName,
+      ),
+      variables: options.variables,
+      context: options.context ?? Context(),
+    );
 
-    FetchResult fetchResult;
+    Response response;
     QueryResult queryResult;
 
     try {
-      // execute the operation through the provided link(s)
-      fetchResult = await execute(
-        link: link,
-        operation: operation,
-      ).first;
-
-      // save the data from fetchResult to the cache
-      if (fetchResult.data != null &&
-          options.fetchPolicy != FetchPolicy.noCache) {
+      // execute the request through the provided link(s)
+      response = await link
+          .request(
+            request,
+          )
+          .first;
+
+      // save the data from response to the cache
+      if (response.data != null && options.fetchPolicy != FetchPolicy.noCache) {
         cache.write(
-          operation.toKey(),
-          fetchResult.data,
+          // TODO: think of an alternative to the old toKey(),
+          request.hashCode.toString(),
+          response.data,
         );
       }
 
       queryResult = mapFetchResultToQueryResult(
-        fetchResult,
+        response,
         options,
         source: QueryResultSource.Network,
       );
     } catch (failure) {
+      // TODO: handle Link exceptions
+
       // we set the source to indicate where the source of failure
       queryResult ??= QueryResult(source: QueryResultSource.Network);
 
@@ -147,7 +155,10 @@ class QueryManager {
     if (options.fetchPolicy != FetchPolicy.noCache &&
         cache is NormalizedInMemoryCache) {
       // normalize results if previously written
-      queryResult.data = cache.read(operation.toKey());
+      queryResult.data = cache.read(
+        // TODO: think of an alternative to the old toKey(),
+        request.hashCode.toString(),
+      );
     }
 
     addQueryResult(queryId, queryResult);
@@ -193,7 +204,7 @@ class QueryManager {
             source: QueryResultSource.Cache,
             exception: OperationException(
               clientException: CacheMissException(
-                'Could not find that operation in the cache. (FetchPolicy.cacheOnly)',
+                'Could not find that request in the cache. (FetchPolicy.cacheOnly)',
                 cacheKey,
               ),
             ),
@@ -287,7 +298,7 @@ class QueryManager {
         if (cachedData != null) {
           query.addResult(
             mapFetchResultToQueryResult(
-              FetchResult(data: cachedData),
+              Response(data: cachedData),
               query.options,
               source: QueryResultSource.Cache,
             ),
@@ -317,7 +328,7 @@ class QueryManager {
   }
 
   QueryResult mapFetchResultToQueryResult(
-    FetchResult fetchResult,
+    Response response,
     BaseOptions options, {
     @required QueryResultSource source,
   }) {
@@ -326,26 +337,26 @@ class QueryManager {
 
     // check if there are errors and apply the error policy if so
     // in a nutshell: `ignore` swallows errors, `none` swallows data
-    if (fetchResult.errors != null && fetchResult.errors.isNotEmpty) {
+    if (response.errors != null && response.errors.isNotEmpty) {
       switch (options.errorPolicy) {
         case ErrorPolicy.all:
           // handle both errors and data
-          errors = _errorsFromResult(fetchResult);
-          data = fetchResult.data;
+          errors = response.errors;
+          data = response.data;
           break;
         case ErrorPolicy.ignore:
           // ignore errors
-          data = fetchResult.data;
+          data = response.data;
           break;
         case ErrorPolicy.none:
         default:
           // TODO not actually sure if apollo even casts graphql errors in `none` mode,
           // it's also kind of legacy
-          errors = _errorsFromResult(fetchResult);
+          errors = response.errors;
           break;
       }
     } else {
-      data = fetchResult.data;
+      data = response.data;
     }
 
     return QueryResult(
@@ -354,9 +365,4 @@ class QueryManager {
       exception: coalesceErrors(graphqlErrors: errors),
     );
   }
-
-  List<GraphQLError> _errorsFromResult(FetchResult fetchResult) =>
-      List<GraphQLError>.from(fetchResult.errors.map<GraphQLError>(
-        (dynamic rawError) => GraphQLError.fromJSON(rawError),
-      ));
 }
diff --git a/packages/graphql/lib/src/core/query_options.dart b/packages/graphql/lib/src/core/query_options.dart
index fd99be102..6605b92a9 100644
--- a/packages/graphql/lib/src/core/query_options.dart
+++ b/packages/graphql/lib/src/core/query_options.dart
@@ -1,5 +1,6 @@
 import 'package:gql/ast.dart';
 import 'package:gql/language.dart';
+import 'package:gql_exec/gql_exec.dart';
 import 'package:graphql/client.dart';
 import 'package:graphql/internal.dart';
 import 'package:graphql/src/core/raw_operation_data.dart';
@@ -101,7 +102,7 @@ class BaseOptions extends RawOperationData {
   ErrorPolicy get errorPolicy => policies.error;
 
   /// Context to be passed to link execution chain.
-  Map<String, dynamic> context;
+  Context context;
 }
 
 /// Query options.
@@ -115,7 +116,7 @@ class QueryOptions extends BaseOptions {
     ErrorPolicy errorPolicy,
     Object optimisticResult,
     this.pollInterval,
-    Map<String, dynamic> context,
+    Context context,
   }) : super(
           policies: Policies(fetch: fetchPolicy, error: errorPolicy),
           // ignore: deprecated_member_use_from_same_package
@@ -144,7 +145,7 @@ class MutationOptions extends BaseOptions {
     Map<String, dynamic> variables,
     FetchPolicy fetchPolicy,
     ErrorPolicy errorPolicy,
-    Map<String, dynamic> context,
+    Context context,
     this.onCompleted,
     this.update,
     this.onError,
@@ -262,7 +263,7 @@ class WatchQueryOptions extends QueryOptions {
     int pollInterval,
     this.fetchResults = false,
     this.eagerlyFetchResults,
-    Map<String, dynamic> context,
+    Context context,
   }) : super(
           // ignore: deprecated_member_use_from_same_package
           document: document,
diff --git a/packages/graphql/lib/src/core/raw_operation_data.dart b/packages/graphql/lib/src/core/raw_operation_data.dart
index a3c4a16e2..5d003a9e8 100644
--- a/packages/graphql/lib/src/core/raw_operation_data.dart
+++ b/packages/graphql/lib/src/core/raw_operation_data.dart
@@ -3,10 +3,7 @@ import 'dart:convert' show json;
 
 import 'package:gql/ast.dart';
 import 'package:gql/language.dart';
-import 'package:graphql/src/link/http/link_http_helper_deprecated_stub.dart'
-    if (dart.library.io) 'package:graphql/src/link/http/link_http_helper_deprecated_io.dart';
 import 'package:graphql/src/utilities/get_from_ast.dart';
-import 'package:http/http.dart';
 
 class RawOperationData {
   RawOperationData({
@@ -74,20 +71,14 @@ class RawOperationData {
 
   String toKey() {
     /// SplayTreeMap is always sorted
-    final String encodedVariables =
-        json.encode(variables, toEncodable: (dynamic object) {
-      if (object is MultipartFile) {
-        return object.filename;
-      }
-      // @deprecated, backward compatible only
-      // in case the body is io.File
-      // in future release, io.File will no longer be supported
-      if (isIoFile(object)) {
-        return object.path;
-      }
-      // default toEncodable behavior
-      return object.toJson();
-    });
+    final String encodedVariables = json.encode(
+      variables,
+      toEncodable: (dynamic object) {
+        // TODO: transparently handle multipart file without introducing package:http
+        // default toEncodable behavior
+        return object.toJson();
+      },
+    );
 
     // TODO: document is being depracated, find ways for generating key
     // ignore: deprecated_member_use_from_same_package
diff --git a/packages/graphql/lib/src/exceptions/exceptions.dart b/packages/graphql/lib/src/exceptions/exceptions.dart
index 80bc1bb5e..8875df2b8 100644
--- a/packages/graphql/lib/src/exceptions/exceptions.dart
+++ b/packages/graphql/lib/src/exceptions/exceptions.dart
@@ -1,14 +1,2 @@
-import 'package:graphql/src/exceptions/_base_exceptions.dart' as _b;
-import 'package:graphql/src/exceptions/io_network_exception.dart' as _n;
-
-export 'package:graphql/src/exceptions/_base_exceptions.dart'
-    hide translateFailure;
-export 'package:graphql/src/exceptions/graphql_error.dart';
+export 'package:graphql/src/exceptions/_base_exceptions.dart';
 export 'package:graphql/src/exceptions/operation_exception.dart';
-export 'package:graphql/src/exceptions/network_exception_stub.dart'
-    if (dart.library.io) 'package:graphql/src/exceptions/io_network_exception.dart'
-    hide translateNetworkFailure;
-
-_b.ClientException translateFailure(dynamic failure) {
-  return _n.translateNetworkFailure(failure) ?? _b.translateFailure(failure);
-}
diff --git a/packages/graphql/lib/src/exceptions/graphql_error.dart b/packages/graphql/lib/src/exceptions/graphql_error.dart
deleted file mode 100644
index a3940b102..000000000
--- a/packages/graphql/lib/src/exceptions/graphql_error.dart
+++ /dev/null
@@ -1,61 +0,0 @@
-/// A location where a [GraphQLError] appears.
-class Location {
-  /// Constructs a [Location] from a JSON map.
-  Location.fromJSON(Map<String, int> data)
-      : line = data['line'],
-        column = data['column'];
-
-  /// The line of the error in the query.
-  final int line;
-
-  /// The column of the error in the query.
-  final int column;
-
-  @override
-  String toString() => '{ line: $line, column: $column }';
-}
-
-/// A GraphQL error (returned by a GraphQL server).
-class GraphQLError {
-  GraphQLError({
-    this.raw,
-    this.message,
-    this.locations,
-    this.path,
-    this.extensions,
-  });
-
-  /// Constructs a [GraphQLError] from a JSON map.
-  GraphQLError.fromJSON(this.raw)
-      : message = raw['message'] is String
-            ? raw['message'] as String
-            : 'Invalid server response: message property needs to be of type String',
-        locations = raw['locations'] is List<Map<String, int>>
-            ? List<Location>.from(
-                (raw['locations'] as List<Map<String, int>>).map<Location>(
-                  (Map<String, int> location) => Location.fromJSON(location),
-                ),
-              )
-            : null,
-        path = raw['path'] as List<dynamic>,
-        extensions = raw['extensions'] as Map<String, dynamic>;
-
-  /// The message of the error.
-  final dynamic raw;
-
-  /// The message of the error.
-  final String message;
-
-  /// Locations where the error appear.
-  final List<Location> locations;
-
-  /// The path of the field in error.
-  final List<dynamic> path;
-
-  /// Custom error data returned by your GraphQL API server
-  final Map<String, dynamic> extensions;
-
-  @override
-  String toString() =>
-      '$message: ${locations is List ? locations.map((Location l) => '[${l.toString()}]').join('') : "Undefined location"}';
-}
diff --git a/packages/graphql/lib/src/exceptions/io_network_exception.dart b/packages/graphql/lib/src/exceptions/io_network_exception.dart
deleted file mode 100644
index 2ac59fb83..000000000
--- a/packages/graphql/lib/src/exceptions/io_network_exception.dart
+++ /dev/null
@@ -1,20 +0,0 @@
-import 'dart:io' show SocketException;
-import 'dart:io';
-import './network_exception_stub.dart' as stub;
-
-export './network_exception_stub.dart' show NetworkException;
-
-stub.NetworkException translateNetworkFailure(dynamic failure) {
-  if (failure is SocketException) {
-    return stub.NetworkException(
-      wrappedException: failure,
-      message: failure.message,
-      uri: Uri(
-        scheme: 'http',
-        host: failure.address?.host,
-        port: failure.port,
-      ),
-    );
-  }
-  return stub.translateNetworkFailure(failure);
-}
diff --git a/packages/graphql/lib/src/exceptions/network_exception_stub.dart b/packages/graphql/lib/src/exceptions/network_exception_stub.dart
deleted file mode 100644
index 52a6a6f21..000000000
--- a/packages/graphql/lib/src/exceptions/network_exception_stub.dart
+++ /dev/null
@@ -1,31 +0,0 @@
-import 'package:http/http.dart' as http;
-
-import './_base_exceptions.dart' show ClientException;
-
-class NetworkException implements ClientException {
-  covariant Exception wrappedException;
-
-  String message;
-
-  Uri uri;
-
-  NetworkException({
-    this.wrappedException,
-    this.message,
-    this.uri,
-  });
-
-  String toString() =>
-      'Failed to connect to $uri: ${message ?? wrappedException}';
-}
-
-NetworkException translateNetworkFailure(dynamic failure) {
-  if (failure is http.ClientException) {
-    return NetworkException(
-      wrappedException: failure,
-      message: failure.message,
-      uri: failure.uri,
-    );
-  }
-  return null;
-}
diff --git a/packages/graphql/lib/src/exceptions/operation_exception.dart b/packages/graphql/lib/src/exceptions/operation_exception.dart
index 2be0b531c..ca9a84e70 100644
--- a/packages/graphql/lib/src/exceptions/operation_exception.dart
+++ b/packages/graphql/lib/src/exceptions/operation_exception.dart
@@ -1,5 +1,5 @@
+import 'package:gql_exec/gql_exec.dart';
 import 'package:graphql/src/exceptions/_base_exceptions.dart';
-import './graphql_error.dart';
 
 class OperationException implements Exception {
   /// Any graphql errors returned from the operation
diff --git a/packages/graphql/lib/src/graphql_client.dart b/packages/graphql/lib/src/graphql_client.dart
index 48725bf19..a2c8ac022 100644
--- a/packages/graphql/lib/src/graphql_client.dart
+++ b/packages/graphql/lib/src/graphql_client.dart
@@ -1,13 +1,12 @@
 import 'dart:async';
 
+import 'package:gql_exec/gql_exec.dart';
+import 'package:gql_link/gql_link.dart';
 import 'package:graphql/src/cache/cache.dart';
 import 'package:graphql/src/core/observable_query.dart';
 import 'package:graphql/src/core/query_manager.dart';
 import 'package:graphql/src/core/query_options.dart';
 import 'package:graphql/src/core/query_result.dart';
-import 'package:graphql/src/link/fetch_result.dart';
-import 'package:graphql/src/link/link.dart';
-import 'package:graphql/src/link/operation.dart';
 import 'package:meta/meta.dart';
 
 /// The default [Policies] to set for each client action
@@ -64,7 +63,7 @@ class DefaultPolicies {
   );
 }
 
-/// The link is a [Link] over which GraphQL documents will be resolved into a [FetchResult].
+/// The link is a [Link] over which GraphQL documents will be resolved into a [Response].
 /// The cache is the initial [Cache] to use in the data store.
 class GraphQLClient {
   /// Constructs a [GraphQLClient] given a [Link] and a [Cache].
@@ -83,7 +82,7 @@ class GraphQLClient {
   /// The default [Policies] to set for each client action
   DefaultPolicies defaultPolicies;
 
-  /// The [Link] over which GraphQL documents will be resolved into a [FetchResult].
+  /// The [Link] over which GraphQL documents will be resolved into a [Response].
   final Link link;
 
   /// The initial [Cache] to use in the data store.
@@ -115,7 +114,7 @@ class GraphQLClient {
 
   /// This subscribes to a GraphQL subscription according to the options specified and returns a
   /// [Stream] which either emits received data or an error.
-  Stream<FetchResult> subscribe(Operation operation) {
-    return execute(link: link, operation: operation);
+  Stream<Response> subscribe(Request request) {
+    return link.request(request);
   }
 }
diff --git a/packages/graphql/lib/src/link/auth/link_auth.dart b/packages/graphql/lib/src/link/auth/link_auth.dart
deleted file mode 100644
index ab2ba010e..000000000
--- a/packages/graphql/lib/src/link/auth/link_auth.dart
+++ /dev/null
@@ -1,38 +0,0 @@
-import 'dart:async';
-
-import 'package:graphql/src/link/link.dart';
-import 'package:graphql/src/link/operation.dart';
-import 'package:graphql/src/link/fetch_result.dart';
-
-typedef GetToken = FutureOr<String> Function();
-
-class AuthLink extends Link {
-  AuthLink({
-    this.getToken,
-  }) : super(
-          request: (Operation operation, [NextLink forward]) {
-            StreamController<FetchResult> controller;
-
-            Future<void> onListen() async {
-              try {
-                final String token = await getToken();
-
-                operation.setContext(<String, Map<String, String>>{
-                  'headers': <String, String>{'Authorization': token}
-                });
-              } catch (error) {
-                controller.addError(error);
-              }
-
-              await controller.addStream(forward(operation));
-              await controller.close();
-            }
-
-            controller = StreamController<FetchResult>(onListen: onListen);
-
-            return controller.stream;
-          },
-        );
-
-  GetToken getToken;
-}
diff --git a/packages/graphql/lib/src/link/error/link_error.dart b/packages/graphql/lib/src/link/error/link_error.dart
deleted file mode 100644
index d28e621b7..000000000
--- a/packages/graphql/lib/src/link/error/link_error.dart
+++ /dev/null
@@ -1,70 +0,0 @@
-import 'dart:async';
-
-import 'package:graphql/src/link/link.dart';
-import 'package:graphql/src/link/operation.dart';
-import 'package:graphql/src/link/fetch_result.dart';
-import 'package:graphql/src/exceptions/exceptions.dart';
-import 'package:graphql/src/exceptions/graphql_error.dart';
-import 'package:graphql/src/exceptions/operation_exception.dart';
-
-typedef ErrorHandler = void Function(ErrorResponse);
-
-class ErrorResponse {
-  ErrorResponse({
-    this.operation,
-    this.fetchResult,
-    this.exception,
-  });
-
-  Operation operation;
-  FetchResult fetchResult;
-  OperationException exception;
-}
-
-class ErrorLink extends Link {
-  ErrorLink({
-    this.errorHandler,
-  }) : super(
-          request: (Operation operation, [NextLink forward]) {
-            StreamController<FetchResult> controller;
-
-            Future<void> onListen() async {
-              Stream stream = forward(operation).map((FetchResult fetchResult) {
-                if (fetchResult.errors != null) {
-                  List<GraphQLError> errors = fetchResult.errors
-                      .map((json) => GraphQLError.fromJSON(json))
-                      .toList();
-
-                  ErrorResponse response = ErrorResponse(
-                    operation: operation,
-                    fetchResult: fetchResult,
-                    exception: OperationException(graphqlErrors: errors),
-                  );
-
-                  errorHandler(response);
-                }
-                return fetchResult;
-              }).handleError((error) {
-                ErrorResponse response = ErrorResponse(
-                  operation: operation,
-                  exception: OperationException(
-                    clientException: translateFailure(error),
-                  ),
-                );
-
-                errorHandler(response);
-                throw error;
-              });
-
-              await controller.addStream(stream);
-              await controller.close();
-            }
-
-            controller = StreamController<FetchResult>(onListen: onListen);
-
-            return controller.stream;
-          },
-        );
-
-  ErrorHandler errorHandler;
-}
diff --git a/packages/graphql/lib/src/link/fetch_result.dart b/packages/graphql/lib/src/link/fetch_result.dart
deleted file mode 100644
index 0a6f7383e..000000000
--- a/packages/graphql/lib/src/link/fetch_result.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-class FetchResult {
-  FetchResult({
-    this.statusCode,
-    this.reasonPhrase,
-    this.errors,
-    this.data,
-    this.extensions,
-    this.context,
-  });
-  int statusCode;
-  String reasonPhrase;
-
-  List<dynamic> errors;
-
-  /// List<dynamic> or Map<String, dynamic>
-  dynamic data;
-  Map<String, dynamic> extensions;
-  Map<String, dynamic> context;
-}
diff --git a/packages/graphql/lib/src/link/http/fallback_http_config.dart b/packages/graphql/lib/src/link/http/fallback_http_config.dart
deleted file mode 100644
index 0dcabea6f..000000000
--- a/packages/graphql/lib/src/link/http/fallback_http_config.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-import 'package:graphql/src/link/http/http_config.dart';
-
-HttpQueryOptions defaultHttpOptions = HttpQueryOptions(
-  includeQuery: true,
-  includeExtensions: false,
-);
-
-Map<String, dynamic> defaultOptions = <String, dynamic>{
-  'method': 'POST',
-};
-
-Map<String, String> defaultHeaders = <String, String>{
-  'accept': '*/*',
-  'content-type': 'application/json',
-};
-
-Map<String, dynamic> defaultCredentials = <String, dynamic>{};
-
-HttpConfig fallbackHttpConfig = HttpConfig(
-  http: defaultHttpOptions,
-  options: defaultOptions,
-  headers: defaultHeaders,
-  credentials: defaultCredentials,
-);
diff --git a/packages/graphql/lib/src/link/http/http_config.dart b/packages/graphql/lib/src/link/http/http_config.dart
deleted file mode 100644
index ea3682f14..000000000
--- a/packages/graphql/lib/src/link/http/http_config.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-class HttpQueryOptions {
-  HttpQueryOptions({
-    this.includeQuery,
-    this.includeExtensions,
-  });
-
-  bool includeQuery;
-  bool includeExtensions;
-
-  void addAll(HttpQueryOptions options) {
-    if (options.includeQuery != null) {
-      includeQuery = options.includeQuery;
-    }
-
-    if (options.includeExtensions != null) {
-      includeExtensions = options.includeExtensions;
-    }
-  }
-}
-
-class HttpConfig {
-  HttpConfig({
-    this.http,
-    this.options,
-    this.credentials,
-    this.headers,
-  });
-
-  HttpQueryOptions http;
-  Map<String, dynamic> options;
-  Map<String, dynamic> credentials;
-  Map<String, String> headers;
-}
-
-class HttpHeadersAndBody {
-  HttpHeadersAndBody({
-    this.headers,
-    this.body,
-  });
-
-  final Map<String, String> headers;
-  final Map<String, dynamic> body;
-}
diff --git a/packages/graphql/lib/src/link/http/link_http.dart b/packages/graphql/lib/src/link/http/link_http.dart
deleted file mode 100644
index 394ab79b6..000000000
--- a/packages/graphql/lib/src/link/http/link_http.dart
+++ /dev/null
@@ -1,373 +0,0 @@
-import 'dart:async';
-import 'dart:convert';
-import 'dart:typed_data';
-
-import 'package:graphql/src/exceptions/exceptions.dart' as ex;
-import 'package:meta/meta.dart';
-import 'package:http/http.dart';
-import 'package:http_parser/http_parser.dart';
-
-import 'package:gql/language.dart';
-import 'package:graphql/src/utilities/helpers.dart' show notNull;
-import 'package:graphql/src/link/link.dart';
-import 'package:graphql/src/link/operation.dart';
-import 'package:graphql/src/link/fetch_result.dart';
-import 'package:graphql/src/link/http/fallback_http_config.dart';
-import 'package:graphql/src/link/http/http_config.dart';
-import './link_http_helper_deprecated_stub.dart'
-    if (dart.library.io) './link_http_helper_deprecated_io.dart';
-
-class HttpLink extends Link {
-  HttpLink({
-    @required String uri,
-    bool includeExtensions,
-
-    /// pass on customized httpClient, especially handy for mocking and testing
-    Client httpClient,
-    Map<String, String> headers,
-    Map<String, dynamic> credentials,
-    Map<String, dynamic> fetchOptions,
-  }) : super(
-          // @todo possibly this is a bug in dart analyzer
-          // ignore: undefined_named_parameter
-          request: (
-            Operation operation, [
-            NextLink forward,
-          ]) {
-            final parsedUri = Uri.parse(uri);
-
-            if (operation.isSubscription) {
-              if (forward == null) {
-                throw Exception('This link does not support subscriptions.');
-              }
-              return forward(operation);
-            }
-
-            final Client fetcher = httpClient ?? Client();
-
-            final HttpConfig linkConfig = HttpConfig(
-              http: HttpQueryOptions(
-                includeExtensions: includeExtensions,
-              ),
-              options: fetchOptions,
-              credentials: credentials,
-              headers: headers,
-            );
-
-            final Map<String, dynamic> context = operation.getContext();
-            HttpConfig contextConfig;
-
-            if (context != null) {
-              // TODO: refactor context to use a [HttpConfig] object to avoid dynamic types
-              contextConfig = HttpConfig(
-                http: HttpQueryOptions(
-                  includeExtensions: context['includeExtensions'] as bool,
-                ),
-                options: context['fetchOptions'] as Map<String, dynamic>,
-                credentials: context['credentials'] as Map<String, dynamic>,
-                headers: context['headers'] as Map<String, String>,
-              );
-            }
-
-            final HttpHeadersAndBody httpHeadersAndBody =
-                _selectHttpOptionsAndBody(
-              operation,
-              fallbackHttpConfig,
-              linkConfig,
-              contextConfig,
-            );
-
-            final Map<String, String> httpHeaders = httpHeadersAndBody.headers;
-
-            StreamController<FetchResult> controller;
-
-            Future<void> onListen() async {
-              StreamedResponse response;
-
-              try {
-                // httpOptionsAndBody.body as String
-                final BaseRequest request = await _prepareRequest(
-                    parsedUri, httpHeadersAndBody.body, httpHeaders);
-
-                response = await fetcher.send(request);
-
-                operation.setContext(<String, StreamedResponse>{
-                  'response': response,
-                });
-                final FetchResult parsedResponse =
-                    await _parseResponse(response);
-
-                controller.add(parsedResponse);
-              } catch (failure) {
-                // we overwrite socket uri for now:
-                // https://github.com/dart-lang/sdk/issues/12693
-                dynamic translated = ex.translateFailure(failure);
-                if (translated is ex.NetworkException) {
-                  translated.uri = parsedUri;
-                }
-                controller.addError(translated);
-              }
-
-              await controller.close();
-            }
-
-            controller = StreamController<FetchResult>(onListen: onListen);
-
-            return controller.stream;
-          },
-        );
-}
-
-Future<Map<String, MultipartFile>> _getFileMap(
-  dynamic body, {
-  Map<String, MultipartFile> currentMap,
-  List<String> currentPath = const <String>[],
-}) async {
-  currentMap ??= <String, MultipartFile>{};
-  if (body is Map<String, dynamic>) {
-    final Iterable<MapEntry<String, dynamic>> entries = body.entries;
-    for (MapEntry<String, dynamic> element in entries) {
-      currentMap.addAll(await _getFileMap(
-        element.value,
-        currentMap: currentMap,
-        currentPath: List<String>.from(currentPath)..add(element.key),
-      ));
-    }
-    return currentMap;
-  }
-  if (body is List<dynamic>) {
-    for (int i = 0; i < body.length; i++) {
-      currentMap.addAll(await _getFileMap(
-        body[i],
-        currentMap: currentMap,
-        currentPath: List<String>.from(currentPath)..add(i.toString()),
-      ));
-    }
-    return currentMap;
-  }
-  if (body is MultipartFile) {
-    return currentMap
-      ..addAll(<String, MultipartFile>{currentPath.join('.'): body});
-  }
-
-  // @deprecated, backward compatible only
-  // in case the body is io.File
-  // in future release, io.File will no longer be supported
-  if (isIoFile(body)) {
-    return deprecatedHelper(body, currentMap, currentPath);
-  }
-
-  // else should only be either String, num, null; NOTHING else
-  return currentMap;
-}
-
-Future<BaseRequest> _prepareRequest(
-  Uri uri,
-  Map<String, dynamic> body,
-  Map<String, String> httpHeaders,
-) async {
-  final Map<String, MultipartFile> fileMap = await _getFileMap(body);
-  if (fileMap.isEmpty) {
-    final Request r = Request('post', uri);
-    r.headers.addAll(httpHeaders);
-    r.body = json.encode(body);
-    return r;
-  }
-
-  final MultipartRequest r = MultipartRequest('post', uri);
-  r.headers.addAll(httpHeaders);
-  r.fields['operations'] = json.encode(body, toEncodable: (dynamic object) {
-    if (object is MultipartFile) {
-      return null;
-    }
-    // @deprecated, backward compatible only
-    // in case the body is io.File
-    // in future release, io.File will no longer be supported
-    if (isIoFile(object)) {
-      return null;
-    }
-    return object.toJson();
-  });
-
-  final Map<String, List<String>> fileMapping = <String, List<String>>{};
-  final List<MultipartFile> fileList = <MultipartFile>[];
-
-  final List<MapEntry<String, MultipartFile>> fileMapEntries =
-      fileMap.entries.toList(growable: false);
-
-  for (int i = 0; i < fileMapEntries.length; i++) {
-    final MapEntry<String, MultipartFile> entry = fileMapEntries[i];
-    final String indexString = i.toString();
-    fileMapping.addAll(<String, List<String>>{
-      indexString: <String>[entry.key],
-    });
-    final MultipartFile f = entry.value;
-    fileList.add(MultipartFile(
-      indexString,
-      f.finalize(),
-      f.length,
-      contentType: f.contentType,
-      filename: f.filename,
-    ));
-  }
-
-  r.fields['map'] = json.encode(fileMapping);
-
-  r.files.addAll(fileList);
-  return r;
-}
-
-HttpHeadersAndBody _selectHttpOptionsAndBody(
-  Operation operation,
-  HttpConfig fallbackConfig, [
-  HttpConfig linkConfig,
-  HttpConfig contextConfig,
-]) {
-  final Map<String, dynamic> options = <String, dynamic>{
-    'headers': <String, String>{},
-    'credentials': <String, dynamic>{},
-  };
-  final HttpQueryOptions http = HttpQueryOptions();
-
-  // http options
-
-  // initialize with fallback http options
-  http.addAll(fallbackConfig.http);
-
-  // inject the configured http options
-  if (linkConfig.http != null) {
-    http.addAll(linkConfig.http);
-  }
-
-  // override with context http options
-  if (contextConfig.http != null) {
-    http.addAll(contextConfig.http);
-  }
-
-  // options
-
-  // initialize with fallback options
-  options.addAll(fallbackConfig.options);
-
-  // inject the configured options
-  if (linkConfig.options != null) {
-    options.addAll(linkConfig.options);
-  }
-
-  // override with context options
-  if (contextConfig.options != null) {
-    options.addAll(contextConfig.options);
-  }
-
-  // headers
-
-  // initialze with fallback headers
-  options['headers'].addAll(fallbackConfig.headers);
-
-  // inject the configured headers
-  if (linkConfig.headers != null) {
-    options['headers'].addAll(linkConfig.headers);
-  }
-
-  // inject the context headers
-  if (contextConfig.headers != null) {
-    options['headers'].addAll(contextConfig.headers);
-  }
-
-  // credentials
-
-  // initialze with fallback credentials
-  options['credentials'].addAll(fallbackConfig.credentials);
-
-  // inject the configured credentials
-  if (linkConfig.credentials != null) {
-    options['credentials'].addAll(linkConfig.credentials);
-  }
-
-  // inject the context credentials
-  if (contextConfig.credentials != null) {
-    options['credentials'].addAll(contextConfig.credentials);
-  }
-
-  // the body depends on the http options
-  final Map<String, dynamic> body = <String, dynamic>{
-    'operationName': operation.operationName,
-    'variables': operation.variables,
-  };
-
-  // not sending the query (i.e persisted queries)
-  if (http.includeExtensions) {
-    body['extensions'] = operation.extensions;
-  }
-
-  if (http.includeQuery) {
-    body['query'] = printNode(operation.documentNode);
-  }
-
-  return HttpHeadersAndBody(
-    headers: options['headers'] as Map<String, String>,
-    body: body,
-  );
-}
-
-Future<FetchResult> _parseResponse(StreamedResponse response) async {
-  final int statusCode = response.statusCode;
-
-  final Encoding encoding = _determineEncodingFromResponse(response);
-  // @todo limit bodyBytes
-  final Uint8List responseByte = await response.stream.toBytes();
-  final String decodedBody = encoding.decode(responseByte);
-
-  Map<String, dynamic> jsonResponse;
-  try {
-      jsonResponse=  json.decode(decodedBody) as Map<String, dynamic>;
-  }catch(e){
-    throw ClientException('Invalid response body: $decodedBody');
-  }
-  final FetchResult fetchResult = FetchResult();
-
-  if (jsonResponse['errors'] != null) {
-    fetchResult.errors =
-        (jsonResponse['errors'] as List<dynamic>).where(notNull).toList();
-  }
-
-  if (jsonResponse['data'] != null) {
-    fetchResult.data = jsonResponse['data'];
-  }
-
-  if (fetchResult.data == null && fetchResult.errors == null) {
-    if (statusCode < 200 || statusCode >= 400) {
-      throw ClientException(
-        'Network Error: $statusCode $decodedBody',
-      );
-    }
-    throw ClientException('Invalid response body: $decodedBody');
-  }
-
-  return fetchResult;
-}
-
-/// Returns the charset encoding for the given response.
-///
-/// The default fallback encoding is set to UTF-8 according to the IETF RFC4627 standard
-/// which specifies the application/json media type:
-///   "JSON text SHALL be encoded in Unicode. The default encoding is UTF-8."
-Encoding _determineEncodingFromResponse(BaseResponse response,
-    [Encoding fallback = utf8]) {
-  final String contentType = response.headers['content-type'];
-
-  if (contentType == null) {
-    return fallback;
-  }
-
-  final MediaType mediaType = MediaType.parse(contentType);
-  final String charset = mediaType.parameters['charset'];
-
-  if (charset == null) {
-    return fallback;
-  }
-
-  final Encoding encoding = Encoding.getByName(charset);
-
-  return encoding == null ? fallback : encoding;
-}
diff --git a/packages/graphql/lib/src/link/http/link_http_helper_deprecated_io.dart b/packages/graphql/lib/src/link/http/link_http_helper_deprecated_io.dart
deleted file mode 100644
index 8288e86bc..000000000
--- a/packages/graphql/lib/src/link/http/link_http_helper_deprecated_io.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-import 'dart:io' as io;
-
-import 'package:http/http.dart';
-import 'package:graphql/src/utilities/file_io.dart' show multipartFileFrom;
-
-// @deprecated, backward compatible only
-// in case the body is io.File
-// in future release, io.File will no longer be supported
-Future<Map<String, MultipartFile>> deprecatedHelper(
-    body, currentMap, currentPath) async {
-  if (body is io.File) {
-    return currentMap
-      ..addAll(<String, MultipartFile>{
-        currentPath.join('.'): await multipartFileFrom(body)
-      });
-  }
-  return null;
-}
-
-bool isIoFile(object) {
-  final r = object is io.File;
-  if (r) {
-    print(r'''
-⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️ DEPRECATION WARNING ⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️
-
-Please do not use `File` direcly anymore. Instead, use
-`MultipartFile`. There's also a utitlity method to help you
-`import 'package:graphql/utilities.dart' show multipartFileFrom;`
-
-⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️ DEPRECATION WARNING ⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️
-    ''');
-  }
-  return r;
-}
diff --git a/packages/graphql/lib/src/link/http/link_http_helper_deprecated_stub.dart b/packages/graphql/lib/src/link/http/link_http_helper_deprecated_stub.dart
deleted file mode 100644
index 23c32aac8..000000000
--- a/packages/graphql/lib/src/link/http/link_http_helper_deprecated_stub.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-import 'package:http/http.dart';
-
-// @deprecated, backward compatible only
-// in case the body is io.File
-// in future release, io.File will no longer be supported
-// but this stub is noop
-Future<Map<String, MultipartFile>> deprecatedHelper(
-        body, currentMap, currentPath) async =>
-    null;
-
-// @deprecated, backward compatible only
-// in case the body is io.File
-// in future release, io.File will no longer be supported
-// but this stub always returns false
-bool isIoFile(object) => false;
diff --git a/packages/graphql/lib/src/link/link.dart b/packages/graphql/lib/src/link/link.dart
deleted file mode 100644
index d51d5a82b..000000000
--- a/packages/graphql/lib/src/link/link.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-import 'dart:async';
-
-import 'package:graphql/src/link/fetch_result.dart';
-import 'package:graphql/src/link/operation.dart';
-
-typedef NextLink = Stream<FetchResult> Function(
-  Operation operation,
-);
-
-typedef RequestHandler = Stream<FetchResult> Function(
-  Operation operation, [
-  NextLink forward,
-]);
-
-Link _concat(
-  Link first,
-  Link second,
-) {
-  return Link(request: (
-    Operation operation, [
-    NextLink forward,
-  ]) {
-    return first.request(operation, (Operation op) {
-      return second.request(op, forward);
-    });
-  });
-}
-
-class Link {
-  Link({this.request});
-
-  RequestHandler request;
-
-  static Link from(List<Link> links) {
-    assert(links.isNotEmpty);
-    return links.reduce((first, second) => first.concat(second));
-  }
-
-  Link concat(Link next) => _concat(this, next);
-}
-
-Stream<FetchResult> execute({Link link, Operation operation}) =>
-    link.request(operation);
diff --git a/packages/graphql/lib/src/link/operation.dart b/packages/graphql/lib/src/link/operation.dart
deleted file mode 100644
index b8bcd1c51..000000000
--- a/packages/graphql/lib/src/link/operation.dart
+++ /dev/null
@@ -1,51 +0,0 @@
-import 'package:gql/ast.dart';
-
-import 'package:graphql/src/core/raw_operation_data.dart';
-import 'package:graphql/src/utilities/get_from_ast.dart';
-
-class Operation extends RawOperationData {
-  Operation({
-    @Deprecated('The "document" option has been deprecated, use "documentNode" instead')
-        String document,
-    DocumentNode documentNode,
-    Map<String, dynamic> variables,
-    this.extensions,
-    String operationName,
-  }) : super(
-            // ignore: deprecated_member_use_from_same_package
-            document: document,
-            documentNode: documentNode,
-            variables: variables,
-            operationName: operationName);
-
-  factory Operation.fromOptions(RawOperationData options) {
-    return Operation(
-      documentNode: options.documentNode,
-      variables: options.variables,
-    );
-  }
-
-  final Map<String, dynamic> extensions;
-
-  final Map<String, dynamic> _context = <String, dynamic>{};
-
-  /// Sets the context of an operation by merging the new context with the old one.
-  void setContext(Map<String, dynamic> next) {
-    if (next != null) {
-      _context.addAll(next);
-    }
-  }
-
-  Map<String, dynamic> getContext() {
-    final Map<String, dynamic> result = <String, dynamic>{};
-    result.addAll(_context);
-
-    return result;
-  }
-
-  bool get isSubscription => isOfType(
-        OperationType.subscription,
-        documentNode,
-        operationName,
-      );
-}
diff --git a/packages/graphql/lib/src/link/web_socket/link_web_socket.dart b/packages/graphql/lib/src/link/web_socket/link_web_socket.dart
deleted file mode 100644
index acfd0fd46..000000000
--- a/packages/graphql/lib/src/link/web_socket/link_web_socket.dart
+++ /dev/null
@@ -1,55 +0,0 @@
-import 'package:meta/meta.dart';
-
-import 'package:graphql/src/link/fetch_result.dart';
-import 'package:graphql/src/link/link.dart';
-import 'package:graphql/src/link/operation.dart';
-import 'package:graphql/src/socket_client.dart';
-import 'package:graphql/src/websocket/messages.dart';
-
-/// A Universal Websocket [Link] implementation to support the websocket transport.
-/// It supports subscriptions, query and mutation operations as well.
-///
-/// NOTE: the actual socket connection will only get established after an [Operation] is handled by this [WebSocketLink].
-/// If you'd like to connect to the socket server instantly, call the [connectOrReconnect] method after creating this [WebSocketLink] instance.
-class WebSocketLink extends Link {
-  /// Creates a new [WebSocketLink] instance with the specified config.
-  WebSocketLink({
-    @required this.url,
-    this.config = const SocketClientConfig(),
-  }) : super() {
-    request = _doOperation;
-  }
-
-  final String url;
-  final SocketClientConfig config;
-
-  // cannot be final because we're changing the instance upon a header change.
-  SocketClient _socketClient;
-
-  Stream<FetchResult> _doOperation(Operation operation, [NextLink forward]) {
-    if (_socketClient == null) {
-      connectOrReconnect();
-    }
-
-    return _socketClient.subscribe(SubscriptionRequest(operation), true).map(
-          (SubscriptionData result) => FetchResult(
-              data: result.data,
-              errors: result.errors as List<dynamic>,
-              context: operation.getContext(),
-              extensions: operation.extensions),
-        );
-  }
-
-  /// Connects or reconnects to the server with the specified headers.
-  void connectOrReconnect() {
-    _socketClient?.dispose();
-    _socketClient = SocketClient(url, config: config);
-  }
-
-  /// Disposes the underlying socket client explicitly. Only use this, if you want to disconnect from
-  /// the current server in favour of another one. If that's the case, create a new [WebSocketLink] instance.
-  Future<void> dispose() async {
-    await _socketClient?.dispose();
-    _socketClient = null;
-  }
-}
diff --git a/packages/graphql/lib/src/socket_client.dart b/packages/graphql/lib/src/socket_client.dart
deleted file mode 100644
index 306257903..000000000
--- a/packages/graphql/lib/src/socket_client.dart
+++ /dev/null
@@ -1,383 +0,0 @@
-import 'dart:async';
-import 'dart:collection';
-import 'dart:convert';
-import 'dart:typed_data';
-import 'package:meta/meta.dart';
-import 'package:websocket/websocket.dart' show WebSocket, WebSocketStatus;
-
-import 'package:rxdart/rxdart.dart';
-import 'package:uuid_enhanced/uuid.dart';
-
-import 'package:graphql/src/websocket/messages.dart';
-
-typedef GetInitPayload = FutureOr<dynamic> Function();
-
-class SocketClientConfig {
-  const SocketClientConfig({
-    this.autoReconnect = true,
-    this.queryAndMutationTimeout = const Duration(seconds: 10),
-    this.inactivityTimeout = const Duration(seconds: 30),
-    this.delayBetweenReconnectionAttempts = const Duration(seconds: 5),
-    this.initPayload,
-  });
-
-  /// Whether to reconnect to the server after detecting connection loss.
-  final bool autoReconnect;
-
-  /// The duration after which the connection is considered unstable, because no keep alive message
-  /// was received from the server in the given time-frame. The connection to the server will be closed.
-  /// If [autoReconnect] is set to true, we try to reconnect to the server after the specified [delayBetweenReconnectionAttempts].
-  ///
-  /// If null, the keep alive messages will be ignored.
-  final Duration inactivityTimeout;
-
-  /// The duration that needs to pass before trying to reconnect to the server after a connection loss.
-  /// This only takes effect when [autoReconnect] is set to true.
-  ///
-  /// If null, the reconnection will occur immediately, although not recommended.
-  final Duration delayBetweenReconnectionAttempts;
-
-  // The duration after which a query or mutation should time out.
-  // If null, no timeout is applied, although not recommended.
-  final Duration queryAndMutationTimeout;
-
-  /// The initial payload that will be sent to the server upon connection.
-  /// Can be null, but must be a valid json structure if provided.
-  final GetInitPayload initPayload;
-
-  Future<InitOperation> get initOperation async {
-    if (initPayload != null) {
-      dynamic payload = await initPayload();
-      return InitOperation(payload);
-    }
-
-    return InitOperation(null);
-  }
-}
-
-enum SocketConnectionState { NOT_CONNECTED, CONNECTING, CONNECTED }
-
-/// Wraps a standard web socket instance to marshal and un-marshal the server /
-/// client payloads into dart object representation.
-///
-/// This class also deals with reconnection, handles timeout and keep alive messages.
-///
-/// It is meant to be instantiated once, and you can let this class handle all the heavy-
-/// lifting of socket state management. Once you're done with the socket connection, make sure
-/// you call the [dispose] method to release all allocated resources.
-class SocketClient {
-  SocketClient(
-    this.url, {
-    this.protocols = const <String>[
-      'graphql-ws',
-    ],
-    this.config = const SocketClientConfig(),
-    @visibleForTesting this.randomBytesForUuid,
-  }) {
-    _connect();
-  }
-
-  Uint8List randomBytesForUuid;
-  final String url;
-  final SocketClientConfig config;
-  final Iterable<String> protocols;
-  final BehaviorSubject<SocketConnectionState> _connectionStateController =
-      BehaviorSubject<SocketConnectionState>();
-
-  final HashMap<String, Function> _subscriptionInitializers = HashMap();
-  bool _connectionWasLost = false;
-
-  Timer _reconnectTimer;
-  WebSocket _socket;
-
-  @visibleForTesting
-  WebSocket get socket => _socket;
-  Stream<GraphQLSocketMessage> _messageStream;
-
-  StreamSubscription<ConnectionKeepAlive> _keepAliveSubscription;
-  StreamSubscription<GraphQLSocketMessage> _messageSubscription;
-
-  /// Connects to the server.
-  ///
-  /// If this instance is disposed, this method does nothing.
-  Future<void> _connect() async {
-    final InitOperation initOperation = await config.initOperation;
-
-    if (_connectionStateController.isClosed) {
-      return;
-    }
-
-    _connectionStateController.value = SocketConnectionState.CONNECTING;
-    print('Connecting to websocket: $url...');
-
-    try {
-      _socket = await WebSocket.connect(
-        url,
-        protocols: protocols,
-      );
-      _connectionStateController.value = SocketConnectionState.CONNECTED;
-      print('Connected to websocket.');
-      _write(initOperation);
-
-      _messageStream =
-          _socket.stream.map<GraphQLSocketMessage>(_parseSocketMessage);
-
-      if (config.inactivityTimeout != null) {
-        _keepAliveSubscription = _messagesOfType<ConnectionKeepAlive>().timeout(
-          config.inactivityTimeout,
-          onTimeout: (EventSink<ConnectionKeepAlive> event) {
-            print(
-                "Haven't received keep alive message for ${config.inactivityTimeout.inSeconds} seconds. Disconnecting..");
-            event.close();
-            _socket.close(WebSocketStatus.goingAway);
-            _connectionStateController.value =
-                SocketConnectionState.NOT_CONNECTED;
-          },
-        ).listen(null);
-      }
-
-      _messageSubscription = _messageStream.listen(
-          (dynamic data) {
-            // print('data: $data');
-          },
-          onDone: () {
-            // print('done');
-            onConnectionLost();
-          },
-          cancelOnError: true,
-          onError: (dynamic e) {
-            print('error: $e');
-          });
-
-      if (_connectionWasLost) {
-        for (Function callback in _subscriptionInitializers.values) {
-          callback();
-        }
-
-        _connectionWasLost = false;
-      }
-    } catch (e) {
-      onConnectionLost(e);
-    }
-  }
-
-  void onConnectionLost([e]) {
-    if (e != null) {
-      print('There was an error causing connection lost: $e');
-    }
-    print('Disconnected from websocket.');
-    _reconnectTimer?.cancel();
-    _keepAliveSubscription?.cancel();
-    _messageSubscription?.cancel();
-
-    if (_connectionStateController.isClosed) {
-      return;
-    }
-
-    _connectionWasLost = true;
-
-    if (_connectionStateController.value !=
-        SocketConnectionState.NOT_CONNECTED) {
-      _connectionStateController.value = SocketConnectionState.NOT_CONNECTED;
-    }
-
-    if (config.autoReconnect && !_connectionStateController.isClosed) {
-      if (config.delayBetweenReconnectionAttempts != null) {
-        print(
-            'Scheduling to connect in ${config.delayBetweenReconnectionAttempts.inSeconds} seconds...');
-
-        _reconnectTimer = Timer(
-          config.delayBetweenReconnectionAttempts,
-          () {
-            _connect();
-          },
-        );
-      } else {
-        Timer.run(() => _connect());
-      }
-    }
-  }
-
-  /// Closes the underlying socket if connected, and stops reconnection attempts.
-  /// After calling this method, this [SocketClient] instance must be considered
-  /// unusable. Instead, create a new instance of this class.
-  ///
-  /// Use this method if you'd like to disconnect from the specified server permanently,
-  /// and you'd like to connect to another server instead of the current one.
-  Future<void> dispose() async {
-    print('Disposing socket client..');
-    _reconnectTimer?.cancel();
-    await Future.wait([
-      _socket?.close(),
-      _keepAliveSubscription?.cancel(),
-      _messageSubscription?.cancel(),
-      _connectionStateController?.close(),
-    ]);
-  }
-
-  static GraphQLSocketMessage _parseSocketMessage(dynamic message) {
-    final Map<String, dynamic> map =
-        json.decode(message as String) as Map<String, dynamic>;
-    final String type = (map['type'] ?? 'unknown') as String;
-    final dynamic payload = map['payload'] ?? <String, dynamic>{};
-    final String id = (map['id'] ?? 'none') as String;
-
-    switch (type) {
-      case MessageTypes.GQL_CONNECTION_ACK:
-        return ConnectionAck();
-      case MessageTypes.GQL_CONNECTION_ERROR:
-        return ConnectionError(payload);
-      case MessageTypes.GQL_CONNECTION_KEEP_ALIVE:
-        return ConnectionKeepAlive();
-      case MessageTypes.GQL_DATA:
-        final dynamic data = payload['data'];
-        final dynamic errors = payload['errors'];
-        return SubscriptionData(id, data, errors);
-      case MessageTypes.GQL_ERROR:
-        return SubscriptionError(id, payload);
-      case MessageTypes.GQL_COMPLETE:
-        return SubscriptionComplete(id);
-      default:
-        return UnknownData(map);
-    }
-  }
-
-  void _write(final GraphQLSocketMessage message) {
-    if (_connectionStateController.value == SocketConnectionState.CONNECTED) {
-      _socket.add(
-        json.encode(
-          message,
-          toEncodable: (dynamic m) => m.toJson(),
-        ),
-      );
-    }
-  }
-
-  /// Sends a query, mutation or subscription request to the server, and returns a stream of the response.
-  ///
-  /// If the request is a query or mutation, a timeout will be applied to the request as specified by
-  /// [SocketClientConfig]'s [queryAndMutationTimeout] field.
-  ///
-  /// If the request is a subscription, obviously no timeout is applied.
-  ///
-  /// In case of socket disconnection, the returned stream will be closed.
-  Stream<SubscriptionData> subscribe(
-      final SubscriptionRequest payload, final bool waitForConnection) {
-    final String id = Uuid.randomUuid(random: randomBytesForUuid).toString();
-    final StreamController<SubscriptionData> response =
-        StreamController<SubscriptionData>();
-    StreamSubscription<SocketConnectionState> sub;
-    final bool addTimeout = !payload.operation.isSubscription &&
-        config.queryAndMutationTimeout != null;
-
-    final onListen = () {
-      final Stream<SocketConnectionState> waitForConnectedStateWithoutTimeout =
-          _connectionStateController
-              .startWith(
-                  waitForConnection ? null : SocketConnectionState.CONNECTED)
-              .where((SocketConnectionState state) =>
-                  state == SocketConnectionState.CONNECTED)
-              .take(1);
-
-      final Stream<SocketConnectionState> waitForConnectedState = addTimeout
-          ? waitForConnectedStateWithoutTimeout.timeout(
-              config.queryAndMutationTimeout,
-              onTimeout: (EventSink<SocketConnectionState> event) {
-                print('Connection timed out.');
-                response.addError(TimeoutException('Connection timed out.'));
-                event.close();
-                response.close();
-              },
-            )
-          : waitForConnectedStateWithoutTimeout;
-
-      sub = waitForConnectedState.listen((_) {
-        final Stream<GraphQLSocketMessage> dataErrorComplete =
-            _messageStream.where(
-          (GraphQLSocketMessage message) {
-            if (message is SubscriptionData) {
-              return message.id == id;
-            }
-
-            if (message is SubscriptionError) {
-              return message.id == id;
-            }
-
-            if (message is SubscriptionComplete) {
-              return message.id == id;
-            }
-
-            return false;
-          },
-        ).takeWhile((_) => !response.isClosed);
-
-        final Stream<GraphQLSocketMessage> subscriptionComplete = addTimeout
-            ? dataErrorComplete
-                .where((GraphQLSocketMessage message) =>
-                    message is SubscriptionComplete)
-                .take(1)
-                .timeout(
-                config.queryAndMutationTimeout,
-                onTimeout: (EventSink<GraphQLSocketMessage> event) {
-                  print('Request timed out.');
-                  response.addError(TimeoutException('Request timed out.'));
-                  event.close();
-                  response.close();
-                },
-              )
-            : dataErrorComplete
-                .where((GraphQLSocketMessage message) =>
-                    message is SubscriptionComplete)
-                .take(1);
-
-        subscriptionComplete.listen((_) => response.close());
-
-        dataErrorComplete
-            .where(
-                (GraphQLSocketMessage message) => message is SubscriptionData)
-            .cast<SubscriptionData>()
-            .listen((SubscriptionData message) => response.add(message));
-
-        dataErrorComplete
-            .where(
-                (GraphQLSocketMessage message) => message is SubscriptionError)
-            .listen(
-                (GraphQLSocketMessage message) => response.addError(message));
-
-        _write(StartOperation(id, payload));
-      });
-    };
-
-    response.onListen = onListen;
-
-    response.onCancel = () {
-      _subscriptionInitializers.remove(id);
-
-      sub?.cancel();
-      if (_connectionStateController.value == SocketConnectionState.CONNECTED &&
-          _socket != null) {
-        _write(StopOperation(id));
-      }
-    };
-
-    _subscriptionInitializers[id] = onListen;
-
-    return response.stream;
-  }
-
-  /// These streams will emit done events when the current socket is done.
-
-  /// A stream that emits the last value of the connection state upon subscription.
-  Stream<SocketConnectionState> get connectionState =>
-      _connectionStateController.stream;
-
-  /// Filter `_messageStream` for messages of the given type of [GraphQLSocketMessage]
-  ///
-  /// Example usages:
-  /// `_messagesOfType<ConnectionAck>()` for init acknowledgments
-  /// `_messagesOfType<ConnectionError>()` for errors
-  /// `_messagesOfType<UnknownData>()` for unknown data messages
-  Stream<M> _messagesOfType<M extends GraphQLSocketMessage>() => _messageStream
-      .where((GraphQLSocketMessage message) => message is M)
-      .cast<M>();
-}
diff --git a/packages/graphql/lib/src/utilities/file.dart b/packages/graphql/lib/src/utilities/file.dart
deleted file mode 100644
index 1ebf5ff6c..000000000
--- a/packages/graphql/lib/src/utilities/file.dart
+++ /dev/null
@@ -1,3 +0,0 @@
-export './file_stub.dart'
-    if (dart.library.html) './file_html.dart'
-    if (dart.library.io) './file_io.dart';
diff --git a/packages/graphql/lib/src/utilities/file_html.dart b/packages/graphql/lib/src/utilities/file_html.dart
deleted file mode 100644
index c10ea16bf..000000000
--- a/packages/graphql/lib/src/utilities/file_html.dart
+++ /dev/null
@@ -1,28 +0,0 @@
-import 'dart:async';
-import 'dart:html' as html;
-import 'package:http/http.dart';
-import 'package:http_parser/http_parser.dart';
-
-Stream<List<int>> _readFile(html.File file) {
-  final reader = html.FileReader();
-  final streamController = StreamController<List<int>>();
-
-  reader.onLoad.listen((_) {
-    // streamController.add(reader.result);
-    streamController.close();
-  });
-
-  reader.onError.listen((error) => streamController.addError(error));
-
-  reader.readAsArrayBuffer(file);
-
-  return streamController.stream;
-}
-
-MultipartFile multipartFileFrom(html.File f) => MultipartFile(
-      '',
-      _readFile(f),
-      f.size,
-      contentType: MediaType.parse(f.type),
-      filename: f.name,
-    );
diff --git a/packages/graphql/lib/src/utilities/file_io.dart b/packages/graphql/lib/src/utilities/file_io.dart
deleted file mode 100644
index 0ee0a00f2..000000000
--- a/packages/graphql/lib/src/utilities/file_io.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-import 'dart:async';
-import 'dart:io' as io;
-import 'package:http/http.dart';
-import 'package:http_parser/http_parser.dart';
-import 'package:mime/mime.dart';
-import 'package:path/path.dart';
-
-MediaType contentType(f) {
-  final a = lookupMimeType(f.path);
-  if (a == null) {
-    return null;
-  }
-  final b = MediaType.parse(a);
-  return b;
-}
-
-Future<MultipartFile> multipartFileFrom(io.File f) async => MultipartFile(
-      '',
-      f.openRead(),
-      await f.length(),
-      contentType: contentType(f),
-      filename: basename(f.path),
-    );
diff --git a/packages/graphql/lib/src/utilities/file_stub.dart b/packages/graphql/lib/src/utilities/file_stub.dart
deleted file mode 100644
index f9ea1c01c..000000000
--- a/packages/graphql/lib/src/utilities/file_stub.dart
+++ /dev/null
@@ -1,6 +0,0 @@
-import 'dart:async';
-
-import 'package:http/http.dart';
-
-FutureOr<MultipartFile> multipartFileFrom(/*io.File or html.File*/ f) =>
-    throw UnsupportedError('io or html');
diff --git a/packages/graphql/lib/src/websocket/messages.dart b/packages/graphql/lib/src/websocket/messages.dart
deleted file mode 100644
index c426b78ae..000000000
--- a/packages/graphql/lib/src/websocket/messages.dart
+++ /dev/null
@@ -1,224 +0,0 @@
-import 'dart:convert';
-
-import 'package:gql/language.dart';
-import 'package:graphql/src/link/operation.dart';
-
-/// These messages represent the structures used for Client-server communication
-/// in a GraphQL web-socket subscription. Each message is represented in a JSON
-/// format where the data type is denoted by the `type` field.
-
-/// A list of constants used for identifying message types
-class MessageTypes {
-  MessageTypes._();
-
-  // client connections
-  static const String GQL_CONNECTION_INIT = 'connection_init';
-  static const String GQL_CONNECTION_TERMINATE = 'connection_terminate';
-
-  // server connections
-  static const String GQL_CONNECTION_ACK = 'connection_ack';
-  static const String GQL_CONNECTION_ERROR = 'connection_error';
-  static const String GQL_CONNECTION_KEEP_ALIVE = 'ka';
-
-  // client operations
-  static const String GQL_START = 'start';
-  static const String GQL_STOP = 'stop';
-
-  // server operations
-  static const String GQL_DATA = 'data';
-  static const String GQL_ERROR = 'error';
-  static const String GQL_COMPLETE = 'complete';
-
-  // default tag for use in identifying issues
-  static const String GQL_UNKNOWN = 'unknown';
-}
-
-abstract class JsonSerializable {
-  Map<String, dynamic> toJson();
-
-  @override
-  String toString() => toJson().toString();
-}
-
-/// Base type for representing a server-client subscription message.
-abstract class GraphQLSocketMessage extends JsonSerializable {
-  GraphQLSocketMessage(this.type);
-
-  final String type;
-}
-
-/// After establishing a connection with the server, the client will
-/// send this message to tell the server that it is ready to begin sending
-/// new subscription queries.
-class InitOperation extends GraphQLSocketMessage {
-  InitOperation(this.payload) : super(MessageTypes.GQL_CONNECTION_INIT);
-
-  final dynamic payload;
-
-  @override
-  Map<String, dynamic> toJson() {
-    final Map<String, dynamic> jsonMap = <String, dynamic>{};
-    jsonMap['type'] = type;
-
-    if (payload != null) {
-      jsonMap['payload'] = payload;
-    }
-
-    return jsonMap;
-  }
-}
-
-/// Represent the payload used during a Start query operation.
-/// The operationName should match one of the top level query definitions
-/// defined in the query provided. Additional variables can be provided
-/// and sent to the server for processing.
-class SubscriptionRequest extends JsonSerializable {
-  SubscriptionRequest(this.operation);
-  final Operation operation;
-
-  @override
-  Map<String, dynamic> toJson() => <String, dynamic>{
-        'operationName': operation.operationName,
-        'query': printNode(operation.documentNode),
-        'variables': operation.variables,
-      };
-}
-
-/// A message to tell the server to create a subscription. The contents of the
-/// query will be defined by the payload request. The id provided will be used
-/// to tag messages such that they can be identified for this subscription
-/// instance. id values should be unique and not be re-used during the lifetime
-/// of the server.
-class StartOperation extends GraphQLSocketMessage {
-  StartOperation(this.id, this.payload) : super(MessageTypes.GQL_START);
-
-  final String id;
-  final SubscriptionRequest payload;
-
-  @override
-  Map<String, dynamic> toJson() => <String, dynamic>{
-        'type': type,
-        'id': id,
-        'payload': payload,
-      };
-}
-
-/// Tell the server to stop sending subscription data for a particular
-/// subscription instance. See [StartOperation].
-class StopOperation extends GraphQLSocketMessage {
-  StopOperation(this.id) : super(MessageTypes.GQL_STOP);
-
-  final String id;
-
-  @override
-  Map<String, dynamic> toJson() => <String, dynamic>{
-        'type': type,
-        'id': id,
-      };
-}
-
-/// The server will send this acknowledgment message after receiving the init
-/// command from the client if the init was successful.
-class ConnectionAck extends GraphQLSocketMessage {
-  ConnectionAck() : super(MessageTypes.GQL_CONNECTION_ACK);
-
-  @override
-  Map<String, dynamic> toJson() => <String, dynamic>{
-        'type': type,
-      };
-}
-
-/// The server will send this error message after receiving the init command
-/// from the client if the init was not successful.
-class ConnectionError extends GraphQLSocketMessage {
-  ConnectionError(this.payload) : super(MessageTypes.GQL_CONNECTION_ERROR);
-
-  final dynamic payload;
-
-  @override
-  Map<String, dynamic> toJson() => <String, dynamic>{
-        'type': type,
-        'payload': payload,
-      };
-}
-
-/// The server will send this message to keep the connection alive
-class ConnectionKeepAlive extends GraphQLSocketMessage {
-  ConnectionKeepAlive() : super(MessageTypes.GQL_CONNECTION_KEEP_ALIVE);
-
-  @override
-  Map<String, dynamic> toJson() => <String, dynamic>{
-        'type': type,
-      };
-}
-
-/// Data sent from the server to the client with subscription data or error
-/// payload. The user should check the errors result before processing the
-/// data value. These error are from the query resolvers.
-class SubscriptionData extends GraphQLSocketMessage {
-  SubscriptionData(this.id, this.data, this.errors)
-      : super(MessageTypes.GQL_DATA);
-
-  final String id;
-  final dynamic data;
-  final dynamic errors;
-
-  @override
-  Map<String, dynamic> toJson() => <String, dynamic>{
-        'type': type,
-        'data': data,
-        'errors': errors,
-      };
-
-  @override
-  int get hashCode => toJson().hashCode;
-
-  @override
-  bool operator ==(dynamic other) =>
-      other is SubscriptionData && jsonEncode(other) == jsonEncode(this);
-}
-
-/// Errors sent from the server to the client if the subscription operation was
-/// not successful, usually due to GraphQL validation errors.
-class SubscriptionError extends GraphQLSocketMessage {
-  SubscriptionError(this.id, this.payload) : super(MessageTypes.GQL_ERROR);
-
-  final String id;
-  final dynamic payload;
-
-  @override
-  Map<String, dynamic> toJson() => <String, dynamic>{
-        'type': type,
-        'id': id,
-        'payload': payload,
-      };
-}
-
-/// Server message to the client to indicate that no more data will be sent
-/// for a particular subscription instance.
-class SubscriptionComplete extends GraphQLSocketMessage {
-  SubscriptionComplete(this.id) : super(MessageTypes.GQL_COMPLETE);
-
-  final String id;
-
-  @override
-  Map<String, dynamic> toJson() => <String, dynamic>{
-        'type': type,
-        'id': id,
-      };
-}
-
-/// Not expected to be created. Indicates there are problems parsing the server
-/// response, or that new unsupported types have been added to the subscription
-/// implementation.
-class UnknownData extends GraphQLSocketMessage {
-  UnknownData(this.payload) : super(MessageTypes.GQL_UNKNOWN);
-
-  final dynamic payload;
-
-  @override
-  Map<String, dynamic> toJson() => <String, dynamic>{
-        'type': type,
-        'payload': payload,
-      };
-}
diff --git a/packages/graphql/lib/utilities.dart b/packages/graphql/lib/utilities.dart
deleted file mode 100644
index dab0e3aff..000000000
--- a/packages/graphql/lib/utilities.dart
+++ /dev/null
@@ -1 +0,0 @@
-export 'package:graphql/src/utilities/file.dart' show multipartFileFrom;
diff --git a/packages/graphql/pubspec.yaml b/packages/graphql/pubspec.yaml
index 73c069193..c0b3cf979 100644
--- a/packages/graphql/pubspec.yaml
+++ b/packages/graphql/pubspec.yaml
@@ -10,14 +10,10 @@ authors:
 homepage: https://github.com/zino-app/graphql-flutter/tree/master/packages/graphql
 dependencies:
   meta: ^1.1.6
-  http: ^0.12.0+4
-  mime: ^0.9.6+2
   path: ^1.6.2
-  http_parser: ^3.1.3
-  uuid_enhanced: ^3.0.2
   gql: ^0.12.0
-  rxdart: ^0.23.1
-  websocket: ^0.0.5
+  gql_exec: ^0.2.2
+  gql_link: ^0.2.3
   quiver: '>=2.0.0 <3.0.0'
 dev_dependencies:
   pedantic: ^1.8.0+1
diff --git a/packages/graphql/test/anonymous_operations_test.dart b/packages/graphql/test/anonymous_operations_test.dart
index ea65d3e36..3dbcdca6f 100644
--- a/packages/graphql/test/anonymous_operations_test.dart
+++ b/packages/graphql/test/anonymous_operations_test.dart
@@ -1,13 +1,14 @@
 import 'package:gql/language.dart';
+import 'package:gql_exec/gql_exec.dart';
+import 'package:gql_link/gql_link.dart';
 import 'package:test/test.dart';
 import 'package:mockito/mockito.dart';
-import 'package:http/http.dart' as http;
 
 import 'package:graphql/client.dart';
 
 import './helpers.dart';
 
-class MockHttpClient extends Mock implements http.Client {}
+class MockLink extends Mock implements Link {}
 
 void main() {
   const String readRepositories = r'''{
@@ -33,86 +34,77 @@ void main() {
   }
 ''';
 
-  HttpLink httpLink;
-  AuthLink authLink;
-  Link link;
+  MockLink link;
   GraphQLClient graphQLClientClient;
-  MockHttpClient mockHttpClient;
+
   group('simple json', () {
     setUp(() {
-      mockHttpClient = MockHttpClient();
-
-      httpLink = HttpLink(
-          uri: 'https://api.github.com/graphql', httpClient: mockHttpClient);
-
-      authLink = AuthLink(
-        getToken: () async => 'Bearer my-special-bearer-token',
-      );
-
-      link = authLink.concat(httpLink);
+      link = MockLink();
 
       graphQLClientClient = GraphQLClient(
         cache: getTestCache(),
         link: link,
       );
     });
+
     group('query', () {
       test('successful query', () async {
         final WatchQueryOptions _options = WatchQueryOptions(
           documentNode: parseString(readRepositories),
           variables: <String, dynamic>{},
         );
+
         when(
-          mockHttpClient.send(any),
-        ).thenAnswer((Invocation a) async {
-          return simpleResponse(body: r'''
-{
-  "data": {
-    "viewer": {
-      "repositories": {
-        "nodes": [
-          {
-            "__typename": "Repository",
-            "id": "MDEwOlJlcG9zaXRvcnkyNDgzOTQ3NA==",
-            "name": "pq",
-            "viewerHasStarred": false
-          },
-          {
-            "__typename": "Repository",
-            "id": "MDEwOlJlcG9zaXRvcnkzMjkyNDQ0Mw==",
-            "name": "go-evercookie",
-            "viewerHasStarred": false
-          },
-          {
-            "__typename": "Repository",
-            "id": "MDEwOlJlcG9zaXRvcnkzNTA0NjgyNA==",
-            "name": "watchbot",
-            "viewerHasStarred": false
-          }
-        ]
-      }
-    }
-  }
-}
-        ''');
-        });
+          link.request(any),
+        ).thenAnswer(
+          (_) => Stream.fromIterable(
+            [
+              Response(
+                data: <String, dynamic>{
+                  'viewer': {
+                    'repositories': {
+                      'nodes': [
+                        {
+                          '__typename': 'Repository',
+                          'id': 'MDEwOlJlcG9zaXRvcnkyNDgzOTQ3NA==',
+                          'name': 'pq',
+                          'viewerHasStarred': false,
+                        },
+                        {
+                          '__typename': 'Repository',
+                          'id': 'MDEwOlJlcG9zaXRvcnkzMjkyNDQ0Mw==',
+                          'name': 'go-evercookie',
+                          'viewerHasStarred': false,
+                        },
+                        {
+                          '__typename': 'Repository',
+                          'id': 'MDEwOlJlcG9zaXRvcnkzNTA0NjgyNA==',
+                          'name': 'watchbot',
+                          'viewerHasStarred': false,
+                        },
+                      ],
+                    },
+                  },
+                },
+              ),
+            ],
+          ),
+        );
+
         final QueryResult r = await graphQLClientClient.query(_options);
 
-        final http.Request capt = verify(mockHttpClient.send(captureAny))
-            .captured
-            .first as http.Request;
-        expect(capt.method, 'post');
-        expect(capt.url.toString(), 'https://api.github.com/graphql');
-        expect(
-          capt.headers,
-          <String, String>{
-            'accept': '*/*',
-            'content-type': 'application/json; charset=utf-8',
-            'Authorization': 'Bearer my-special-bearer-token',
-          },
+        verify(
+          link.request(
+            Request(
+              operation: Operation(
+                document: parseString(readRepositories),
+                operationName: null,
+              ),
+              variables: <String, dynamic>{},
+              context: Context(),
+            ),
+          ),
         );
-        expect(await capt.finalize().bytesToString(),
-            r'{"operationName":null,"variables":{},"query":"query {\n  viewer {\n    repositories(last: 42) {\n      nodes {\n        __typename\n        id\n        name\n        viewerHasStarred\n      }\n    }\n  }\n}"}');
 
         expect(r.exception, isNull);
         expect(r.data, isNotNull);
@@ -136,30 +128,41 @@ void main() {
     });
     group('mutation', () {
       test('successful mutation', () async {
-        final MutationOptions _options =
-            MutationOptions(documentNode: parseString(addStar));
-        when(mockHttpClient.send(any)).thenAnswer((Invocation a) async =>
-            simpleResponse(
-                body:
-                    '{"data":{"action":{"starrable":{"viewerHasStarred":true}}}}'));
+        final MutationOptions _options = MutationOptions(
+          documentNode: parseString(addStar),
+        );
+
+        when(
+          link.request(any),
+        ).thenAnswer(
+          (_) => Stream.fromIterable(
+            [
+              Response(
+                data: <String, dynamic>{
+                  'action': {
+                    'starrable': {
+                      'viewerHasStarred': true,
+                    },
+                  },
+                },
+              ),
+            ],
+          ),
+        );
 
         final QueryResult response = await graphQLClientClient.mutate(_options);
 
-        final http.Request request = verify(mockHttpClient.send(captureAny))
-            .captured
-            .first as http.Request;
-        expect(request.method, 'post');
-        expect(request.url.toString(), 'https://api.github.com/graphql');
-        expect(
-          request.headers,
-          <String, String>{
-            'accept': '*/*',
-            'content-type': 'application/json; charset=utf-8',
-            'Authorization': 'Bearer my-special-bearer-token',
-          },
+        verify(
+          link.request(
+            Request(
+              operation: Operation(
+                document: parseString(addStar),
+              ),
+              variables: <String, dynamic>{},
+              context: Context(),
+            ),
+          ),
         );
-        expect(await request.finalize().bytesToString(),
-            r'{"operationName":null,"variables":{},"query":"mutation {\n  action: addStar(input: {starrableId: \"some_repo\"}) {\n    starrable {\n      viewerHasStarred\n    }\n  }\n}"}');
 
         expect(response.exception, isNull);
         expect(response.data, isNotNull);
diff --git a/packages/graphql/test/graphql_client_test.dart b/packages/graphql/test/graphql_client_test.dart
index 19d67f1f2..19e983f4e 100644
--- a/packages/graphql/test/graphql_client_test.dart
+++ b/packages/graphql/test/graphql_client_test.dart
@@ -1,13 +1,14 @@
+import 'package:gql_exec/gql_exec.dart';
+import 'package:gql_link/gql_link.dart';
 import 'package:test/test.dart';
 import 'package:mockito/mockito.dart';
-import 'package:http/http.dart' as http;
 
 import 'package:graphql/client.dart';
 import 'package:gql/language.dart';
 
 import './helpers.dart';
 
-class MockHttpClient extends Mock implements http.Client {}
+class MockLink extends Mock implements Link {}
 
 void main() {
   const String readRepositories = r'''
@@ -35,88 +36,81 @@ void main() {
   }
 ''';
 
-  HttpLink httpLink;
-  AuthLink authLink;
-  Link link;
+  MockLink link;
   GraphQLClient graphQLClientClient;
-  MockHttpClient mockHttpClient;
+
   group('simple json', () {
     setUp(() {
-      mockHttpClient = MockHttpClient();
-
-      httpLink = HttpLink(
-          uri: 'https://api.github.com/graphql', httpClient: mockHttpClient);
-
-      authLink = AuthLink(
-        getToken: () async => 'Bearer my-special-bearer-token',
-      );
-
-      link = authLink.concat(httpLink);
+      link = MockLink();
 
       graphQLClientClient = GraphQLClient(
         cache: getTestCache(),
         link: link,
       );
     });
+
     group('query', () {
-      test('successful query', () async {
+      test('successful response', () async {
         final WatchQueryOptions _options = WatchQueryOptions(
           documentNode: parseString(readRepositories),
           variables: <String, dynamic>{
             'nRepositories': 42,
           },
         );
+
         when(
-          mockHttpClient.send(any),
-        ).thenAnswer((Invocation a) async {
-          return simpleResponse(body: r'''
-{
-  "data": {
-    "viewer": {
-      "repositories": {
-        "nodes": [
-          {
-            "__typename": "Repository",
-            "id": "MDEwOlJlcG9zaXRvcnkyNDgzOTQ3NA==",
-            "name": "pq",
-            "viewerHasStarred": false
-          },
-          {
-            "__typename": "Repository",
-            "id": "MDEwOlJlcG9zaXRvcnkzMjkyNDQ0Mw==",
-            "name": "go-evercookie",
-            "viewerHasStarred": false
-          },
-          {
-            "__typename": "Repository",
-            "id": "MDEwOlJlcG9zaXRvcnkzNTA0NjgyNA==",
-            "name": "watchbot",
-            "viewerHasStarred": false
-          }
-        ]
-      }
-    }
-  }
-}
-        ''');
-        });
+          link.request(any),
+        ).thenAnswer(
+          (_) => Stream.fromIterable(
+            [
+              Response(
+                data: <String, dynamic>{
+                  'viewer': {
+                    'repositories': {
+                      'nodes': [
+                        {
+                          '__typename': 'Repository',
+                          'id': 'MDEwOlJlcG9zaXRvcnkyNDgzOTQ3NA==',
+                          'name': 'pq',
+                          'viewerHasStarred': false,
+                        },
+                        {
+                          '__typename': 'Repository',
+                          'id': 'MDEwOlJlcG9zaXRvcnkzMjkyNDQ0Mw==',
+                          'name': 'go-evercookie',
+                          'viewerHasStarred': false,
+                        },
+                        {
+                          '__typename': 'Repository',
+                          'id': 'MDEwOlJlcG9zaXRvcnkzNTA0NjgyNA==',
+                          'name': 'watchbot',
+                          'viewerHasStarred': false,
+                        },
+                      ],
+                    },
+                  },
+                },
+              ),
+            ],
+          ),
+        );
+
         final QueryResult r = await graphQLClientClient.query(_options);
 
-        final http.Request capt = verify(mockHttpClient.send(captureAny))
-            .captured
-            .first as http.Request;
-        expect(capt.method, 'post');
-        expect(capt.url.toString(), 'https://api.github.com/graphql');
-        expect(
-          capt.headers,
-          <String, String>{
-            'accept': '*/*',
-            'content-type': 'application/json; charset=utf-8',
-            'Authorization': 'Bearer my-special-bearer-token',
-          },
+        verify(
+          link.request(
+            Request(
+              operation: Operation(
+                document: parseString(readRepositories),
+                operationName: 'ReadRepositories',
+              ),
+              variables: <String, dynamic>{
+                'nRepositories': 42,
+              },
+              context: Context(),
+            ),
+          ),
         );
-        expect(await capt.finalize().bytesToString(),
-            r'{"operationName":"ReadRepositories","variables":{"nRepositories":42},"query":"query ReadRepositories($nRepositories: Int!) {\n  viewer {\n    repositories(last: $nRepositories) {\n      nodes {\n        __typename\n        id\n        name\n        viewerHasStarred\n      }\n    }\n  }\n}"}');
 
         expect(r.exception, isNull);
         expect(r.data, isNotNull);
@@ -132,15 +126,23 @@ void main() {
 
       test('failed query because of an exception with null string', () async {
         final e = Exception();
-        when(mockHttpClient.send(any)).thenAnswer((_) async {
-          throw e;
-        });
+
+        when(
+          link.request(any),
+        ).thenAnswer(
+          (_) => Stream.fromFuture(Future.error(e)),
+        );
 
         final QueryResult r = await graphQLClientClient.query(
-            WatchQueryOptions(documentNode: parseString(readRepositories)));
+          WatchQueryOptions(
+            documentNode: parseString(readRepositories),
+          ),
+        );
 
-        expect((r.exception.clientException as UnhandledFailureWrapper).failure,
-            e);
+        expect(
+          (r.exception.clientException as UnhandledFailureWrapper).failure,
+          e,
+        );
 
         return;
       });
@@ -148,12 +150,17 @@ void main() {
       test('failed query because of an exception with empty string', () async {
         final e = Exception('');
 
-        when(mockHttpClient.send(any)).thenAnswer((_) async {
-          throw e;
-        });
+        when(
+          link.request(any),
+        ).thenAnswer(
+          (_) => Stream.fromFuture(Future.error(e)),
+        );
 
         final QueryResult r = await graphQLClientClient.query(
-            WatchQueryOptions(documentNode: parseString(readRepositories)));
+          WatchQueryOptions(
+            documentNode: parseString(readRepositories),
+          ),
+        );
 
         expect(
           (r.exception.clientException as UnhandledFailureWrapper).failure,
@@ -172,30 +179,42 @@ void main() {
     });
     group('mutation', () {
       test('successful mutation', () async {
-        final MutationOptions _options =
-            MutationOptions(documentNode: parseString(addStar));
-        when(mockHttpClient.send(any)).thenAnswer((Invocation a) async =>
-            simpleResponse(
-                body:
-                    '{"data":{"action":{"starrable":{"viewerHasStarred":true}}}}'));
+        final MutationOptions _options = MutationOptions(
+          documentNode: parseString(addStar),
+        );
+
+        when(
+          link.request(any),
+        ).thenAnswer(
+          (_) => Stream.fromIterable(
+            [
+              Response(
+                data: <String, dynamic>{
+                  'action': {
+                    'starrable': {
+                      'viewerHasStarred': true,
+                    },
+                  },
+                },
+              ),
+            ],
+          ),
+        );
 
         final QueryResult response = await graphQLClientClient.mutate(_options);
 
-        final http.Request request = verify(mockHttpClient.send(captureAny))
-            .captured
-            .first as http.Request;
-        expect(request.method, 'post');
-        expect(request.url.toString(), 'https://api.github.com/graphql');
-        expect(
-          request.headers,
-          <String, String>{
-            'accept': '*/*',
-            'content-type': 'application/json; charset=utf-8',
-            'Authorization': 'Bearer my-special-bearer-token',
-          },
+        verify(
+          link.request(
+            Request(
+              operation: Operation(
+                document: parseString(addStar),
+                operationName: 'AddStar',
+              ),
+              variables: <String, dynamic>{},
+              context: Context(),
+            ),
+          ),
         );
-        expect(await request.finalize().bytesToString(),
-            r'{"operationName":"AddStar","variables":{},"query":"mutation AddStar($starrableId: ID!) {\n  action: addStar(input: {starrableId: $starrableId}) {\n    starrable {\n      viewerHasStarred\n    }\n  }\n}"}');
 
         expect(response.exception, isNull);
         expect(response.data, isNotNull);
diff --git a/packages/graphql/test/helpers.dart b/packages/graphql/test/helpers.dart
index 5c51940a5..04aeca0cb 100644
--- a/packages/graphql/test/helpers.dart
+++ b/packages/graphql/test/helpers.dart
@@ -1,8 +1,4 @@
 import 'dart:async';
-import 'dart:convert';
-
-import 'package:meta/meta.dart';
-import 'package:http/http.dart' as http;
 
 import 'package:graphql/client.dart';
 
@@ -17,13 +13,3 @@ overridePrint(testFn(List<String> log)) => () {
 NormalizedInMemoryCache getTestCache() => NormalizedInMemoryCache(
       dataIdFromObject: typenameDataIdFromObject,
     );
-
-http.StreamedResponse simpleResponse({@required String body, int status}) {
-  final List<int> bytes = utf8.encode(body);
-  final Stream<List<int>> stream =
-      Stream<List<int>>.fromIterable(<List<int>>[bytes]);
-
-  final http.StreamedResponse r = http.StreamedResponse(stream, status ?? 200);
-
-  return r;
-}
diff --git a/packages/graphql/test/link/error/link_error_test.dart b/packages/graphql/test/link/error/link_error_test.dart
deleted file mode 100644
index bcf56b35e..000000000
--- a/packages/graphql/test/link/error/link_error_test.dart
+++ /dev/null
@@ -1,110 +0,0 @@
-import "dart:async";
-import "dart:convert";
-
-import 'package:gql/language.dart';
-import 'package:graphql/src/exceptions/exceptions.dart';
-import 'package:graphql/src/link/error/link_error.dart';
-import 'package:graphql/src/link/http/link_http.dart';
-import 'package:graphql/src/link/link.dart';
-import 'package:graphql/src/link/operation.dart';
-import "package:http/http.dart" as http;
-import "package:mockito/mockito.dart";
-import "package:test/test.dart";
-
-class MockClient extends Mock implements http.Client {}
-
-void main() {
-  group('error link', () {
-    MockClient client;
-    Operation query;
-    HttpLink httpLink;
-
-    setUp(() {
-      client = MockClient();
-      query = Operation(
-        documentNode: parseString('query Operation {}'),
-        operationName: 'Operation',
-      );
-      httpLink = HttpLink(
-        uri: '/graphql-test',
-        httpClient: client,
-      );
-    });
-
-    test('network error', () async {
-      bool called = false;
-
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{}')],
-            ),
-            400,
-          ),
-        ),
-      );
-
-      final errorLink = ErrorLink(errorHandler: (response) {
-        if (response.exception.clientException != null) {
-          called = true;
-        }
-      });
-
-      Exception exception;
-
-      try {
-        await execute(
-          link: errorLink.concat(httpLink),
-          operation: query,
-        ).first;
-      } on Exception catch (e) {
-        exception = e;
-      }
-
-      expect(
-        exception,
-        const TypeMatcher<ClientException>(),
-      );
-      expect(
-        called,
-        true,
-      );
-    });
-
-    test('graphql error', () async {
-      bool called = false;
-
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{"errors":[{"message":"error"}]}')],
-            ),
-            200,
-          ),
-        ),
-      );
-
-      final errorLink = ErrorLink(errorHandler: (response) {
-        if (response.exception.graphqlErrors != null) {
-          called = true;
-        }
-      });
-
-      await execute(
-        link: errorLink.concat(httpLink),
-        operation: query,
-      ).first;
-
-      expect(
-        called,
-        true,
-      );
-    });
-  });
-}
diff --git a/packages/graphql/test/link/http/link_http_test.dart b/packages/graphql/test/link/http/link_http_test.dart
deleted file mode 100644
index b6e35ba4a..000000000
--- a/packages/graphql/test/link/http/link_http_test.dart
+++ /dev/null
@@ -1,543 +0,0 @@
-import "dart:async";
-import "dart:convert";
-
-import 'package:gql/language.dart';
-import 'package:graphql/client.dart';
-import 'package:graphql/internal.dart';
-import 'package:graphql/src/link/http/link_http.dart';
-import 'package:graphql/src/link/link.dart';
-import 'package:graphql/src/link/operation.dart';
-import "package:http/http.dart" as http;
-import 'package:http_parser/http_parser.dart';
-import "package:mockito/mockito.dart";
-import "package:test/test.dart";
-
-class MockClient extends Mock implements http.Client {}
-
-void main() {
-  group('HTTP link', () {
-    MockClient client;
-    Operation query;
-    Operation subscription;
-    HttpLink link;
-
-    setUp(() {
-      client = MockClient();
-      query = Operation(
-        documentNode: parseString('query Operation {}'),
-        operationName: 'Operation',
-      );
-      subscription = Operation(
-        documentNode: parseString('subscription Operation {}'),
-        operationName: 'Operation',
-      );
-      link = HttpLink(
-        uri: '/graphql-test',
-        httpClient: client,
-      );
-    });
-
-    test('exception on subscription', () {
-      expect(
-        () => execute(link: link, operation: subscription),
-        throwsA(
-          const TypeMatcher<Exception>(),
-        ),
-      );
-    });
-
-    test('forward on subscription', () {
-      bool forwardCalled = false;
-
-      final forwardLink = Link(
-        request: (Operation op, [NextLink forward]) {
-          forwardCalled = true;
-
-          return null;
-        },
-      );
-      expect(
-        execute(
-          link: link.concat(forwardLink),
-          operation: subscription,
-        ),
-        null,
-      );
-
-      expect(
-        forwardCalled,
-        true,
-      );
-    });
-
-    test('request', () async {
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{"data":{}}')],
-            ),
-            200,
-          ),
-        ),
-      );
-
-      await execute(
-        link: link,
-        operation: query,
-      ).first;
-
-      final http.Request captured = verify(
-        client.send(captureAny),
-      ).captured.single;
-
-      expect(
-        captured.url,
-        Uri.parse('/graphql-test'),
-      );
-      expect(
-        captured.method,
-        'post',
-      );
-      expect(
-        captured.headers,
-        equals({
-          'accept': '*/*',
-          'content-type': 'application/json; charset=utf-8',
-        }),
-      );
-      expect(
-        captured.body,
-        '{"operationName":"Operation","variables":{},"query":"query Operation {\\n  \\n}"}',
-      );
-    });
-
-    test('request with link defaults', () async {
-      link = HttpLink(
-        uri: '/graphql-test',
-        httpClient: client,
-        includeExtensions: true,
-        fetchOptions: {'option-1:default': 'option-value-1:default'},
-        credentials: {'credential-1:default': 'credential-value-1:default'},
-        headers: {'header-1:default': 'header-value-1:default'},
-      );
-
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{"data":{}}')],
-            ),
-            200,
-          ),
-        ),
-      );
-
-      await execute(
-        link: link,
-        operation: query,
-      ).first;
-
-      final http.Request captured = verify(
-        client.send(captureAny),
-      ).captured.single;
-
-      expect(
-        captured.url,
-        Uri.parse('/graphql-test'),
-      );
-      expect(
-        captured.method,
-        'post',
-      );
-      expect(
-        captured.headers,
-        equals({
-          'accept': '*/*',
-          'content-type': 'application/json; charset=utf-8',
-          'header-1:default': 'header-value-1:default',
-        }),
-      );
-      expect(
-        captured.body,
-        '{"operationName":"Operation","variables":{},"extensions":null,"query":"query Operation {\\n  \\n}"}',
-      );
-    });
-
-    test('request with context', () async {
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{"data":{}}')],
-            ),
-            200,
-          ),
-        ),
-      );
-
-      query.setContext({
-        'includeExtensions': true,
-        'fetchOptions': {'option-1': 'option-value-1'},
-        'credentials': {'credential-1': 'credential-value-1'},
-        'headers': {'header-1': 'header-value-1'},
-      });
-
-      await execute(
-        link: link,
-        operation: query,
-      ).first;
-
-      final http.Request captured = verify(
-        client.send(captureAny),
-      ).captured.single;
-
-      expect(
-        captured.url,
-        Uri.parse('/graphql-test'),
-      );
-      expect(
-        captured.method,
-        'post',
-      );
-      expect(
-        captured.headers,
-        equals({
-          'accept': '*/*',
-          'content-type': 'application/json; charset=utf-8',
-          'header-1': 'header-value-1',
-        }),
-      );
-      expect(
-        captured.body,
-        '{"operationName":"Operation","variables":{},"extensions":null,"query":"query Operation {\\n  \\n}"}',
-      );
-    });
-
-    test('request with extensions', () async {
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{"data":{}}')],
-            ),
-            200,
-          ),
-        ),
-      );
-
-      final query = Operation(
-        documentNode: parseString('{}'),
-        extensions: {'extension-1': 'extension-value-1'},
-      );
-      query.setContext({
-        'includeExtensions': true,
-      });
-
-      await execute(
-        link: link,
-        operation: query,
-      ).first;
-
-      final http.Request captured = verify(
-        client.send(captureAny),
-      ).captured.single;
-
-      expect(
-        captured.body,
-        '{"operationName":null,"variables":{},"extensions":{"extension-1":"extension-value-1"},"query":"query {\\n  \\n}"}',
-      );
-    });
-
-    test('successful data response', () async {
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{"data":{}}')],
-            ),
-            200,
-          ),
-        ),
-      );
-
-      final result = await execute(
-        link: link,
-        operation: query,
-      ).first;
-
-      expect(
-        result.data,
-        equals({}),
-      );
-      expect(
-        result.errors,
-        null,
-      );
-    });
-
-    test('successful error response', () async {
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{"errors":[]}')],
-            ),
-            200,
-          ),
-        ),
-      );
-
-      final result = await execute(
-        link: link,
-        operation: query,
-      ).first;
-
-      expect(
-        result.errors,
-        equals([]),
-      );
-      expect(
-        result.data,
-        null,
-      );
-    });
-
-    test('no data and errors suceessful response', () async {
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{}')],
-            ),
-            200,
-          ),
-        ),
-      );
-
-      Exception exception;
-
-      try {
-        await execute(
-          link: link,
-          operation: query,
-        ).first;
-      } on Exception catch (e) {
-        exception = e;
-      }
-
-      expect(
-        exception,
-        const TypeMatcher<NetworkException>(),
-      );
-
-      expect(
-        (exception as NetworkException).wrappedException,
-        const TypeMatcher<http.ClientException>(),
-      );
-
-      expect(
-        exception.toString(),
-        'Failed to connect to /graphql-test: Invalid response body: {}',
-      );
-    });
-
-    test('no data and errors failed response', () async {
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{}')],
-            ),
-            400,
-          ),
-        ),
-      );
-
-      Exception exception;
-
-      try {
-        await execute(
-          link: link,
-          operation: query,
-        ).first;
-      } on Exception catch (e) {
-        exception = e;
-      }
-
-      expect(
-        exception,
-        const TypeMatcher<NetworkException>(),
-      );
-
-      expect(
-        (exception as NetworkException).wrappedException,
-        const TypeMatcher<http.ClientException>(),
-      );
-
-      expect(
-        exception.toString(),
-        'Failed to connect to /graphql-test: Network Error: 400 {}',
-      );
-    });
-
-    test('data on failed response', () async {
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{"data":{}}')],
-            ),
-            300,
-          ),
-        ),
-      );
-
-      final result = await execute(
-        link: link,
-        operation: query,
-      ).first;
-
-      expect(
-        result.data,
-        equals({}),
-      );
-      expect(
-        result.errors,
-        null,
-      );
-    });
-
-    test('non-json response', () async {
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('')],
-            ),
-            200,
-          ),
-        ),
-      );
-
-      Exception exception;
-
-      try {
-        await execute(
-          link: link,
-          operation: query,
-        ).first;
-      } on Exception catch (e) {
-        exception = e;
-      }
-
-      expect(
-        exception,
-        const TypeMatcher<ClientException>(),
-      );
-
-      expect(
-        (exception as ClientException).message,
-        "Invalid response body: ",
-      );
-    });
-
-    test('request with multipart file', () async {
-      when(
-        client.send(any),
-      ).thenAnswer(
-        (_) => Future.value(
-          http.StreamedResponse(
-            Stream.fromIterable(
-              [utf8.encode('{"data":{}}')],
-            ),
-            200,
-          ),
-        ),
-      );
-
-      final query = Operation(
-        documentNode: parseString('{}'),
-        variables: {
-          'files': [
-            http.MultipartFile.fromString(
-              'field-1',
-              'just plain text 1',
-              filename: 'sample_upload1.txt',
-              contentType: MediaType('text', 'plain'),
-            ),
-            http.MultipartFile.fromString(
-              'field-2',
-              'just plain text 2',
-              filename: 'sample_upload2.txt',
-              contentType: MediaType('text', 'plain'),
-            ),
-          ],
-        },
-      );
-
-      await execute(
-        link: link,
-        operation: query,
-      ).first;
-
-      final http.MultipartRequest captured = verify(
-        client.send(captureAny),
-      ).captured.single;
-
-      final req = await captured.finalize().bytesToString();
-
-      expect(
-        req
-            .replaceAll(
-              RegExp('--dart-http-boundary-.{51}'),
-              '--dart-http-boundary-REPLACED',
-            )
-            .replaceAll(
-              '\r\n',
-              '\n',
-            ),
-        r'''--dart-http-boundary-REPLACED
-content-disposition: form-data; name="operations"
-
-{"operationName":null,"variables":{"files":[null,null]},"query":"query {\n  \n}"}
---dart-http-boundary-REPLACED
-content-disposition: form-data; name="map"
-
-{"0":["variables.files.0"],"1":["variables.files.1"]}
---dart-http-boundary-REPLACED
-content-type: text/plain; charset=utf-8
-content-disposition: form-data; name="0"; filename="sample_upload1.txt"
-
-just plain text 1
---dart-http-boundary-REPLACED
-content-type: text/plain; charset=utf-8
-content-disposition: form-data; name="1"; filename="sample_upload2.txt"
-
-just plain text 2
---dart-http-boundary-REPLACED--
-''',
-      );
-    });
-  });
-}
diff --git a/packages/graphql/test/link/link_test.dart b/packages/graphql/test/link/link_test.dart
deleted file mode 100644
index a5373c462..000000000
--- a/packages/graphql/test/link/link_test.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-import 'package:graphql/client.dart';
-import 'package:graphql/src/link/operation.dart';
-import 'package:test/test.dart';
-
-void main() {
-  group('link', () {
-    test('multiple', () async {
-      final link1 = Link(
-        request: (Operation op, [NextLink forward]) {
-          return null;
-        },
-      );
-
-      final link2 = Link(
-        request: (Operation op, [NextLink forward]) {
-          return null;
-        },
-      );
-
-      final link3 = Link(
-        request: (Operation op, [NextLink forward]) {
-          return null;
-        },
-      );
-
-      final linksFrom = Link.from([link1, link2, link3]);
-
-      final linksConcat = link1..concat(link2)..concat(link3);
-
-      var resultConcat = await execute(link: linksConcat);
-      var resultFrom = await execute(link: linksFrom);
-
-      expect(resultConcat, resultFrom);
-    });
-  });
-}
diff --git a/packages/graphql/test/multipart_upload_io_test.dart b/packages/graphql/test/multipart_upload_io_test.dart
deleted file mode 100644
index de2e56d79..000000000
--- a/packages/graphql/test/multipart_upload_io_test.dart
+++ /dev/null
@@ -1,94 +0,0 @@
-import 'package:gql/language.dart';
-@TestOn("vm")
-import 'package:test/test.dart';
-import 'package:mockito/mockito.dart';
-import 'package:http/http.dart' as http;
-import 'dart:io' as io;
-
-import 'package:graphql/client.dart';
-
-import 'helpers.dart';
-
-class MockHttpClient extends Mock implements http.Client {}
-
-void main() {
-  HttpLink httpLink;
-  AuthLink authLink;
-  Link link;
-  GraphQLClient graphQLClientClient;
-  MockHttpClient mockHttpClient;
-
-  group(
-    'upload',
-    () {
-      const String uploadMutation = r'''
-    mutation($files: [Upload!]!) {
-      multipleUpload(files: $files) {
-        id
-        filename
-        mimetype
-        path
-      }
-    }
-    ''';
-
-      setUp(() {
-        mockHttpClient = MockHttpClient();
-
-        when(mockHttpClient.send(any)).thenAnswer((Invocation a) async {
-          return simpleResponse(body: '{"data": {}}');
-        });
-
-        httpLink = HttpLink(
-            uri: 'http://localhost:3001/graphql', httpClient: mockHttpClient);
-
-        authLink = AuthLink(
-          getToken: () async => 'Bearer my-special-bearer-token',
-        );
-
-        link = authLink.concat(httpLink);
-
-        graphQLClientClient = GraphQLClient(
-          cache: getTestCache(),
-          link: link,
-        );
-      });
-
-      test(
-        'upload with io.File instance deprecation warning',
-        overridePrint((log) async {
-          final MutationOptions _options = MutationOptions(
-            documentNode: parseString(uploadMutation),
-            variables: <String, dynamic>{
-              'files': [
-                io.File('pubspec.yaml'),
-              ],
-            },
-          );
-          final QueryResult r = await graphQLClientClient.mutate(_options);
-
-          expect(r.exception, isNull);
-          expect(r.data, isNotNull);
-          expect(log, hasLength(5));
-          final warningMessage = r'''
-⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️ DEPRECATION WARNING ⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️
-
-Please do not use `File` direcly anymore. Instead, use
-`MultipartFile`. There's also a utitlity method to help you
-`import 'package:graphql/utilities.dart' show multipartFileFrom;`
-
-⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️ DEPRECATION WARNING ⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️⚠️️️️️️️️
-    ''';
-          expect(log[0], warningMessage);
-          expect(log[1], warningMessage);
-          expect(log[2], warningMessage);
-          expect(log[3], warningMessage);
-          expect(log[4], warningMessage);
-        }),
-      );
-    },
-    onPlatform: {
-      "!vm": Skip("This test is only for VM"),
-    },
-  );
-}
diff --git a/packages/graphql/test/multipart_upload_test.dart b/packages/graphql/test/multipart_upload_test.dart
deleted file mode 100644
index 9212a5e84..000000000
--- a/packages/graphql/test/multipart_upload_test.dart
+++ /dev/null
@@ -1,202 +0,0 @@
-import 'package:gql/language.dart';
-import 'package:http_parser/http_parser.dart';
-import 'package:test/test.dart';
-import 'package:mockito/mockito.dart';
-import 'package:http/http.dart' as http;
-
-import 'package:graphql/client.dart';
-
-import './helpers.dart';
-
-class MockHttpClient extends Mock implements http.Client {}
-
-NormalizedInMemoryCache getTestCache() => NormalizedInMemoryCache(
-      dataIdFromObject: typenameDataIdFromObject,
-    );
-
-void main() {
-  HttpLink httpLink;
-  AuthLink authLink;
-  Link link;
-  GraphQLClient graphQLClientClient;
-  MockHttpClient mockHttpClient;
-
-  group('upload', () {
-    const String uploadMutation = r'''
-    mutation($files: [Upload!]!) {
-      multipleUpload(files: $files) {
-        id
-        filename
-        mimetype
-        path
-      }
-    }
-    ''';
-
-    setUp(() {
-      mockHttpClient = MockHttpClient();
-
-      httpLink = HttpLink(
-          uri: 'http://localhost:3001/graphql', httpClient: mockHttpClient);
-
-      authLink = AuthLink(
-        getToken: () async => 'Bearer my-special-bearer-token',
-      );
-
-      link = authLink.concat(httpLink);
-
-      graphQLClientClient = GraphQLClient(
-        cache: getTestCache(),
-        link: link,
-      );
-    });
-
-    test('upload success', () async {
-      Future<void> expectUploadBody(
-          http.ByteStream bodyBytesStream, String boundary) async {
-        final List<Function> expectContinuationList = (() {
-          int i = 0;
-          return <Function>[
-            // ExpectString
-            (List<int> actual, String expected) => expect(
-                String.fromCharCodes(actual.sublist(i, i += expected.length)),
-                expected),
-            // ExpectBytes
-            (List<int> actual, List<int> expected) =>
-                expect(actual.sublist(i, i += expected.length), expected),
-            // Expect final length
-            (int expectedLength) => expect(i, expectedLength),
-          ];
-        })();
-        final Function expectContinuationString = expectContinuationList[0];
-        final Function expectContinuationBytes = expectContinuationList[1];
-        final Function expectContinuationLength = expectContinuationList[2];
-        final bodyBytes = await bodyBytesStream.toBytes();
-        expectContinuationString(bodyBytes, '--');
-        expectContinuationString(bodyBytes, boundary);
-        expectContinuationString(bodyBytes,
-            '\r\ncontent-disposition: form-data; name="operations"\r\n\r\n');
-        // operationName of unamed operations is "UNNAMED/" +  document.hashCode.toString()
-        expectContinuationString(bodyBytes,
-            r'{"operationName":null,"variables":{"files":[null,null]},"query":"mutation($files: [Upload!]!) {\n  multipleUpload(files: $files) {\n    id\n    filename\n    mimetype\n    path\n  }\n}"}');
-        expectContinuationString(bodyBytes, '\r\n--');
-        expectContinuationString(bodyBytes, boundary);
-        expectContinuationString(bodyBytes,
-            '\r\ncontent-disposition: form-data; name="map"\r\n\r\n{"0":["variables.files.0"],"1":["variables.files.1"]}');
-        expectContinuationString(bodyBytes, '\r\n--');
-        expectContinuationString(bodyBytes, boundary);
-        expectContinuationString(bodyBytes,
-            '\r\ncontent-type: image/jpeg\r\ncontent-disposition: form-data; name="0"; filename="sample_upload.jpg"\r\n\r\n');
-        expectContinuationBytes(bodyBytes, [0, 1, 254, 255]);
-        expectContinuationString(bodyBytes, '\r\n--');
-        expectContinuationString(bodyBytes, boundary);
-        expectContinuationString(bodyBytes,
-            '\r\ncontent-type: text/plain; charset=utf-8\r\ncontent-disposition: form-data; name="1"; filename="sample_upload.txt"\r\n\r\n');
-        expectContinuationString(bodyBytes, 'just plain text');
-        expectContinuationString(bodyBytes, '\r\n--');
-        expectContinuationString(bodyBytes, boundary);
-        expectContinuationString(bodyBytes, '--\r\n');
-        expectContinuationLength(bodyBytes.lengthInBytes);
-      }
-
-      http.ByteStream bodyBytes;
-      when(mockHttpClient.send(any)).thenAnswer((Invocation a) async {
-        bodyBytes = (a.positionalArguments[0] as http.BaseRequest).finalize();
-        return simpleResponse(body: r'''
-{
-  "data": {
-    "multipleUpload": [
-      {
-        "id": "r1odc4PAz",
-        "filename": "sample_upload.jpg",
-        "mimetype": "image/jpeg",
-        "path": "./uploads/r1odc4PAz-sample_upload.jpg"
-      },
-      {
-        "id": "5Ea18qlMur",
-        "filename": "sample_upload.txt",
-        "mimetype": "text/plain",
-        "path": "./uploads/5Ea18qlMur-sample_upload.txt"
-      }
-    ]
-  }
-}
-        ''');
-      });
-
-      final MutationOptions _options = MutationOptions(
-        documentNode: parseString(uploadMutation),
-        variables: <String, dynamic>{
-          'files': [
-            http.MultipartFile.fromBytes(
-              '',
-              [0, 1, 254, 255],
-              filename: 'sample_upload.jpg',
-              contentType: MediaType('image', 'jpeg'),
-            ),
-            http.MultipartFile.fromString(
-              '',
-              'just plain text',
-              filename: 'sample_upload.txt',
-              contentType: MediaType('text', 'plain'),
-            ),
-          ],
-        },
-      );
-      final QueryResult r = await graphQLClientClient.mutate(_options);
-
-      expect(r.exception, isNull);
-      expect(r.data, isNotNull);
-
-      final http.MultipartRequest request =
-          verify(mockHttpClient.send(captureAny)).captured.first
-              as http.MultipartRequest;
-      expect(request.method, 'post');
-      expect(request.url.toString(), 'http://localhost:3001/graphql');
-      expect(request.headers['accept'], '*/*');
-      expect(
-          request.headers['Authorization'], 'Bearer my-special-bearer-token');
-      final List<String> contentTypeStringSplit =
-          request.headers['content-type'].split('; boundary=');
-      expect(contentTypeStringSplit[0], 'multipart/form-data');
-      await expectUploadBody(bodyBytes, contentTypeStringSplit[1]);
-
-      final List<Map<String, dynamic>> multipleUpload =
-          (r.data['multipleUpload'] as List<dynamic>)
-              .cast<Map<String, dynamic>>();
-
-      expect(multipleUpload, <Map<String, String>>[
-        <String, String>{
-          'id': 'r1odc4PAz',
-          'filename': 'sample_upload.jpg',
-          'mimetype': 'image/jpeg',
-          'path': './uploads/r1odc4PAz-sample_upload.jpg'
-        },
-        <String, String>{
-          'id': '5Ea18qlMur',
-          'filename': 'sample_upload.txt',
-          'mimetype': 'text/plain',
-          'path': './uploads/5Ea18qlMur-sample_upload.txt'
-        },
-      ]);
-    });
-
-    //test('upload fail error response', () {
-    //  const String responseBody = json.encode({
-    //    "errors":[
-    //      {
-    //        "message": r'Variable "$files" of required type "[Upload!]!" was not provided.',
-    //        "locations": [{ "line" :1, "column" :14 }],
-    //        "extensions": {
-    //          "code": "INTERNAL_SERVER_ERROR",
-    //          "exception": {
-    //             "stacktrace": [ r'GraphQLError: Variable "$files" of required type "[Upload!]!" was not provided.', ... ]
-    //          }
-    //        }
-    //      }
-    //    ]
-    //  });
-    //  const int statusCode = 400;
-    //});
-  });
-}
diff --git a/packages/graphql/test/socket_client_test.dart b/packages/graphql/test/socket_client_test.dart
deleted file mode 100644
index 1baa7cd76..000000000
--- a/packages/graphql/test/socket_client_test.dart
+++ /dev/null
@@ -1,178 +0,0 @@
-import 'dart:convert';
-import 'dart:typed_data';
-
-import 'package:gql/language.dart';
-import 'package:graphql/client.dart';
-import 'package:graphql/src/link/operation.dart';
-import 'package:graphql/src/socket_client.dart'
-    show SocketClient, SocketConnectionState;
-import 'package:graphql/src/websocket/messages.dart';
-import 'package:test/test.dart';
-
-import 'helpers.dart';
-
-void main() {
-  group('SocketClient without payload', () {
-    SocketClient socketClient;
-    setUp(overridePrint((log) {
-      socketClient = SocketClient(
-        'ws://echo.websocket.org',
-        protocols: null,
-        randomBytesForUuid: Uint8List.fromList(
-            [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
-      );
-    }));
-    tearDown(overridePrint((log) async {
-      await socketClient.dispose();
-    }));
-    test('connection', () async {
-      await expectLater(
-        socketClient.connectionState.asBroadcastStream(),
-        emitsInOrder(
-          [
-            SocketConnectionState.CONNECTING,
-            SocketConnectionState.CONNECTED,
-          ],
-        ),
-      );
-    });
-    test('subscription data', () async {
-      final payload = SubscriptionRequest(
-        Operation(documentNode: parseString('subscription {}')),
-      );
-      final waitForConnection = true;
-      final subscriptionDataStream =
-          socketClient.subscribe(payload, waitForConnection);
-      await socketClient.connectionState
-          .where((state) => state == SocketConnectionState.CONNECTED)
-          .first;
-
-      // ignore: unawaited_futures
-      socketClient.socket.stream
-          .where((message) =>
-              message ==
-              r'{"type":"start","id":"01020304-0506-4708-890a-0b0c0d0e0f10","payload":{"operationName":null,"query":"subscription {\n  \n}","variables":{}}}')
-          .first
-          .then((_) {
-        socketClient.socket.add(jsonEncode({
-          'type': 'data',
-          'id': '01020304-0506-4708-890a-0b0c0d0e0f10',
-          'payload': {
-            'data': {'foo': 'bar'},
-            'errors': ['error and data can coexist']
-          }
-        }));
-      });
-
-      await expectLater(
-        subscriptionDataStream,
-        emits(
-          SubscriptionData(
-            '01020304-0506-4708-890a-0b0c0d0e0f10',
-            {'foo': 'bar'},
-            ['error and data can coexist'],
-          ),
-        ),
-      );
-    });
-    test('resubscribe', () async {
-      final payload = SubscriptionRequest(
-        Operation(documentNode: gql('subscription {}')),
-      );
-      final waitForConnection = true;
-      final subscriptionDataStream =
-          socketClient.subscribe(payload, waitForConnection);
-
-      socketClient.onConnectionLost();
-
-      await socketClient.connectionState
-          .where((state) => state == SocketConnectionState.CONNECTED)
-          .first;
-
-      // ignore: unawaited_futures
-      socketClient.socket.stream
-          .where((message) =>
-              message ==
-              r'{"type":"start","id":"01020304-0506-4708-890a-0b0c0d0e0f10","payload":{"operationName":null,"query":"subscription {\n  \n}","variables":{}}}')
-          .first
-          .then((_) {
-        socketClient.socket.add(jsonEncode({
-          'type': 'data',
-          'id': '01020304-0506-4708-890a-0b0c0d0e0f10',
-          'payload': {
-            'data': {'foo': 'bar'},
-            'errors': ['error and data can coexist']
-          }
-        }));
-      });
-
-      await expectLater(
-        subscriptionDataStream,
-        emits(
-          SubscriptionData(
-            '01020304-0506-4708-890a-0b0c0d0e0f10',
-            {'foo': 'bar'},
-            ['error and data can coexist'],
-          ),
-        ),
-      );
-    });
-  }, tags: "integration");
-
-  group('SocketClient with const payload', () {
-    SocketClient socketClient;
-    const initPayload = {'token': 'mytoken'};
-
-    setUp(overridePrint((log) {
-      socketClient = SocketClient(
-        'ws://echo.websocket.org',
-        config: SocketClientConfig(initPayload: () => initPayload),
-      );
-    }));
-
-    tearDown(overridePrint((log) async {
-      await socketClient.dispose();
-    }));
-
-    test('connection', () async {
-      await socketClient.connectionState
-          .where((state) => state == SocketConnectionState.CONNECTED)
-          .first;
-
-      await expectLater(socketClient.socket.stream.map((s) {
-        return jsonDecode(s)['payload'];
-      }), emits(initPayload));
-    });
-  });
-
-  group('SocketClient with future payload', () {
-    SocketClient socketClient;
-    const initPayload = {'token': 'mytoken'};
-
-    setUp(overridePrint((log) {
-      socketClient = SocketClient(
-        'ws://echo.websocket.org',
-        config: SocketClientConfig(
-          initPayload: () async {
-            await Future.delayed(Duration(seconds: 3));
-            return initPayload;
-          },
-        ),
-      );
-    }));
-
-    tearDown(overridePrint((log) async {
-      await socketClient.dispose();
-    }));
-
-    test('connection', () async {
-      await socketClient.connectionState
-          .where((state) => state == SocketConnectionState.CONNECTED)
-          .first;
-
-      await expectLater(socketClient.socket.stream.map((s) {
-        return jsonDecode(s)['payload'];
-      }), emits(initPayload));
-    });
-  });
-}
diff --git a/packages/graphql/test/websocket_legacy_io_test.dart b/packages/graphql/test/websocket_legacy_io_test.dart
deleted file mode 100644
index c44317bcc..000000000
--- a/packages/graphql/test/websocket_legacy_io_test.dart
+++ /dev/null
@@ -1,96 +0,0 @@
-@TestOn('vm')
-
-import 'dart:convert';
-import 'dart:typed_data';
-
-import 'package:gql/language.dart';
-import 'package:test/test.dart';
-
-import 'package:graphql/src/link/operation.dart';
-import 'package:graphql/src/websocket/messages.dart';
-
-import 'package:graphql/legacy_socket_api/legacy_socket_client.dart';
-
-import 'helpers.dart';
-
-void main() {
-  group(
-    'SocketClient',
-    () {
-      // ignore: deprecated_member_use_from_same_package
-      SocketClient socketClient;
-      setUp(overridePrint((log) {
-        // ignore: deprecated_member_use_from_same_package
-        socketClient = SocketClient(
-          'ws://echo.websocket.org',
-          protocols: null,
-          randomBytesForUuid: Uint8List.fromList(
-              [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]),
-        );
-      }));
-      tearDown(overridePrint((log) async {
-        await socketClient.dispose();
-      }));
-      test('connection', () async {
-        await expectLater(
-          socketClient.connectionState.asBroadcastStream(),
-          emitsInOrder(
-            [
-              SocketConnectionState.CONNECTING,
-              SocketConnectionState.CONNECTED,
-            ],
-          ),
-        );
-      });
-      test('subscription data', () async {
-        final payload = SubscriptionRequest(
-          Operation(documentNode: parseString('subscription {}')),
-        );
-        final waitForConnection = true;
-        final subscriptionDataStream =
-            socketClient.subscribe(payload, waitForConnection);
-        await socketClient.connectionState
-            .where((state) => state == SocketConnectionState.CONNECTED)
-            .first;
-
-        // ignore: unawaited_futures
-        socketClient.stream
-            .where(
-              (message) =>
-                  message ==
-                  r'{"type":"start","id":"01020304-0506-4708-890a-0b0c0d0e0f10","payload":{"operationName":null,"query":"subscription {\n  \n}","variables":{}}}',
-            )
-            .first
-            .then(
-          (_) {
-            socketClient.socket.add(
-              jsonEncode({
-                'type': 'data',
-                'id': '01020304-0506-4708-890a-0b0c0d0e0f10',
-                'payload': {
-                  'data': {'foo': 'bar'},
-                  'errors': ['error and data can coexist']
-                }
-              }),
-            );
-          },
-        );
-
-        await expectLater(
-          subscriptionDataStream,
-          emits(
-            SubscriptionData(
-              '01020304-0506-4708-890a-0b0c0d0e0f10',
-              {'foo': 'bar'},
-              ['error and data can coexist'],
-            ),
-          ),
-        );
-      });
-    },
-    tags: "integration",
-    onPlatform: {
-      "!vm": Skip("This test is only for VM"),
-    },
-  );
-}
diff --git a/packages/graphql/test/websocket_legacy_test.dart b/packages/graphql/test/websocket_legacy_test.dart
deleted file mode 100644
index 042c0c190..000000000
--- a/packages/graphql/test/websocket_legacy_test.dart
+++ /dev/null
@@ -1,54 +0,0 @@
-import 'package:test/test.dart';
-
-import 'package:graphql/legacy_socket_api/legacy_socket_link.dart';
-import 'package:graphql/legacy_socket_api/legacy_socket_client.dart';
-
-import 'helpers.dart';
-
-void main() {
-  group('Link Websocket', () {
-    test('simple connection', overridePrint((List<String> log) {
-      // ignore: deprecated_member_use_from_same_package
-      WebSocketLink(
-        url: 'ws://echo.websocket.org',
-        // ignore: deprecated_member_use_from_same_package
-        headers: {'foo': 'bar'},
-      );
-      expect(log, [
-        'WARNING: Using direct websocket headers which will be removed soon, '
-            'as it is incompatable with dart:html. '
-            'If you need this direct header access, '
-            'please comment on this PR with details on your usecase: '
-            'https://github.com/zino-app/graphql-flutter/pull/323'
-      ]);
-    }));
-  });
-
-  group('LegacyInitOperation', () {
-    test('null payload', () {
-      // ignore: deprecated_member_use_from_same_package
-      final operation = LegacyInitOperation(null);
-      expect(operation.toJson(), {'type': 'connection_init'});
-    });
-    test('simple payload', () {
-      // ignore: deprecated_member_use_from_same_package
-      final operation = LegacyInitOperation(42);
-      expect(operation.toJson(), {'type': 'connection_init', 'payload': '42'});
-    });
-    test('complex payload', () {
-      // ignore: deprecated_member_use_from_same_package
-      final operation = LegacyInitOperation({
-        'value': 42,
-        'nested': {
-          'number': [3, 7],
-          'string': ['foo', 'bar']
-        }
-      });
-      expect(operation.toJson(), {
-        'type': 'connection_init',
-        'payload':
-            '{"value":42,"nested":{"number":[3,7],"string":["foo","bar"]}}'
-      });
-    });
-  });
-}
diff --git a/packages/graphql/test/websocket_test.dart b/packages/graphql/test/websocket_test.dart
deleted file mode 100644
index c70077808..000000000
--- a/packages/graphql/test/websocket_test.dart
+++ /dev/null
@@ -1,37 +0,0 @@
-import 'package:test/test.dart';
-import 'package:graphql/src/websocket/messages.dart' show InitOperation;
-
-void main() {
-  group('InitOperation', () {
-    test('null payload', () {
-      // ignore: deprecated_member_use_from_same_package
-      final operation = InitOperation(null);
-      expect(operation.toJson(), {'type': 'connection_init'});
-    });
-    test('simple payload', () {
-      // ignore: deprecated_member_use_from_same_package
-      final operation = InitOperation(42);
-      expect(operation.toJson(), {'type': 'connection_init', 'payload': 42});
-    });
-    test('complex payload', () {
-      // ignore: deprecated_member_use_from_same_package
-      final operation = InitOperation({
-        'value': 42,
-        'nested': {
-          'number': [3, 7],
-          'string': ['foo', 'bar']
-        }
-      });
-      expect(operation.toJson(), {
-        'type': 'connection_init',
-        'payload': {
-          'value': 42,
-          'nested': {
-            'number': [3, 7],
-            'string': ['foo', 'bar']
-          }
-        }
-      });
-    });
-  });
-}
diff --git a/packages/graphql_flutter/lib/src/widgets/subscription.dart b/packages/graphql_flutter/lib/src/widgets/subscription.dart
index 30a89e3bc..3030725d1 100644
--- a/packages/graphql_flutter/lib/src/widgets/subscription.dart
+++ b/packages/graphql_flutter/lib/src/widgets/subscription.dart
@@ -4,6 +4,7 @@ import 'dart:io';
 import 'package:connectivity/connectivity.dart';
 import 'package:flutter/widgets.dart';
 import 'package:gql/language.dart';
+import 'package:gql_exec/gql_exec.dart';
 import 'package:graphql/client.dart';
 import 'package:graphql/internal.dart';
 import 'package:graphql_flutter/src/widgets/graphql_provider.dart';
@@ -42,7 +43,7 @@ class _SubscriptionState<T> extends State<Subscription<T>> {
   bool _loading = true;
   T _data;
   dynamic _error;
-  StreamSubscription<FetchResult> _subscription;
+  StreamSubscription<Response> _subscription;
 
   ConnectivityResult _currentConnectivityResult;
   StreamSubscription<ConnectivityResult> _networkSubscription;
@@ -50,13 +51,15 @@ class _SubscriptionState<T> extends State<Subscription<T>> {
   void _initSubscription() {
     final GraphQLClient client = GraphQLProvider.of(context).value;
     assert(client != null);
-    final Operation operation = Operation(
-      documentNode: parseString(widget.query),
+    final Request request = Request(
+      operation: Operation(
+        document: parseString(widget.query),
+        operationName: widget.operationName,
+      ),
       variables: widget.variables,
-      operationName: widget.operationName,
     );
 
-    final Stream<FetchResult> stream = client.subscribe(operation);
+    final Stream<Response> stream = client.subscribe(request);
 
     if (_subscription == null) {
       // Set the initial value for the first time.
@@ -109,7 +112,7 @@ class _SubscriptionState<T> extends State<Subscription<T>> {
     super.dispose();
   }
 
-  void _onData(final FetchResult message) {
+  void _onData(final Response message) {
     setState(() {
       _loading = false;
       _data = message.data as T;
@@ -121,7 +124,7 @@ class _SubscriptionState<T> extends State<Subscription<T>> {
     setState(() {
       _loading = false;
       _data = null;
-      _error = (error is SubscriptionError) ? error.payload : error;
+      _error = error;
     });
   }
 
diff --git a/packages/graphql_flutter/pubspec.yaml b/packages/graphql_flutter/pubspec.yaml
index fc97d6062..aa20c4586 100644
--- a/packages/graphql_flutter/pubspec.yaml
+++ b/packages/graphql_flutter/pubspec.yaml
@@ -9,12 +9,11 @@ authors:
 homepage: https://github.com/zino-app/graphql-flutter/tree/master/packages/graphql_flutter
 dependencies:
   graphql: ^3.0.1-beta.2
+  gql_exec: ^0.2.2
   flutter:
     sdk: flutter
   meta: ^1.1.6
-  path: ^1.6.2
   path_provider: ^1.1.0
-  rxdart: ^0.23.1
   connectivity: ^0.4.4
 dev_dependencies:
   pedantic: ^1.8.0+1

From 7499323673af6ea6c9889c828fc8ff80042f1a74 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kl=C4=81vs=20Pried=C4=ABtis?= <klavs@prieditis.lv>
Date: Sun, 16 Feb 2020 21:50:40 +0200
Subject: [PATCH 2/2] feat: move to DocumentNode-only documents

BREAKING CHANGE: the deprecated string documents are no longer supported
---
 packages/graphql/README.md                    | 12 ++--
 packages/graphql/example/bin/main.dart        |  6 +-
 .../lib/src/core/observable_query.dart        |  2 +-
 .../graphql/lib/src/core/query_manager.dart   |  2 +-
 .../graphql/lib/src/core/query_options.dart   | 67 +++----------------
 .../lib/src/core/raw_operation_data.dart      | 42 ++----------
 .../test/anonymous_operations_test.dart       |  4 +-
 .../test/core/raw_operation_data_test.dart    | 26 +++----
 .../graphql/test/graphql_client_test.dart     |  8 +--
 .../lib/src/widgets/mutation.dart             |  2 -
 .../lib/src/widgets/query.dart                |  2 -
 11 files changed, 47 insertions(+), 126 deletions(-)

diff --git a/packages/graphql/README.md b/packages/graphql/README.md
index be46131c6..b9a5f3d7d 100644
--- a/packages/graphql/README.md
+++ b/packages/graphql/README.md
@@ -110,7 +110,7 @@ const String readRepositories = r'''
 
 Then create a `QueryOptions` object:
 
-> **NB:** for `documentNode` - Use our built-in help function - `gql(query)` to convert your document string to **ASTs** `documentNode`.
+> **NB:** for `document` - Use our built-in help function - `gql(query)` to convert your document string to **ASTs** `document`.
 
 In our case, we need to pass `nRepositories` variable and the document name is `readRepositories`.
 
@@ -119,7 +119,7 @@ In our case, we need to pass `nRepositories` variable and the document name is `
 const int nRepositories = 50;
 
 final QueryOptions options = QueryOptions(
-    documentNode: gql(readRepositories),
+    document: gql(readRepositories),
     variables: <String, dynamic>{
         'nRepositories': nRepositories,
     },
@@ -166,7 +166,7 @@ Then instead of the `QueryOptions`, for mutations we will `MutationOptions`, whi
 // ...
 
 final MutationOptions options = MutationOptions(
-  documentNode: gql(addStar),
+  document: gql(addStar),
   variables: <String, dynamic>{
     'starrableId': repositoryID,
   },
@@ -201,7 +201,7 @@ if (isStarred) {
 ### AST documents
 
 > We are deprecating `document` and recommend you update your application to use
-`documentNode` instead. `document` will be removed from the api in a future version.
+`document` instead. `document` will be removed from the api in a future version.
 
 For example:
 
@@ -209,7 +209,7 @@ For example:
 // ...
 
 final MutationOptions options = MutationOptions(
-  documentNode: gql(addStar),
+  document: gql(addStar),
   variables: <String, dynamic>{
     'starrableId': repositoryID,
   },
@@ -238,7 +238,7 @@ import 'package:gql/add_star.ast.g.dart' as add_star;
 // ...
 
 final MutationOptions options = MutationOptions(
-  documentNode: add_star.document,
+  document: add_star.document,
   variables: <String, dynamic>{
     'starrableId': repositoryID,
   },
diff --git a/packages/graphql/example/bin/main.dart b/packages/graphql/example/bin/main.dart
index ab184ad68..4e994cf35 100644
--- a/packages/graphql/example/bin/main.dart
+++ b/packages/graphql/example/bin/main.dart
@@ -38,7 +38,7 @@ void query() async {
   const int nRepositories = 50;
 
   final QueryOptions options = QueryOptions(
-    documentNode: gql(readRepositories),
+    document: gql(readRepositories),
     variables: <String, dynamic>{
       'nRepositories': nRepositories,
     },
@@ -70,7 +70,7 @@ void starRepository(String repositoryID) async {
   final GraphQLClient _client = client();
 
   final MutationOptions options = MutationOptions(
-    documentNode: gql(addStar),
+    document: gql(addStar),
     variables: <String, dynamic>{
       'starrableId': repositoryID,
     },
@@ -103,7 +103,7 @@ void removeStarFromRepository(String repositoryID) async {
   final GraphQLClient _client = client();
 
   final MutationOptions options = MutationOptions(
-    documentNode: gql(removeStar),
+    document: gql(removeStar),
     variables: <String, dynamic>{
       'starrableId': repositoryID,
     },
diff --git a/packages/graphql/lib/src/core/observable_query.dart b/packages/graphql/lib/src/core/observable_query.dart
index b964b1cfc..54d7ebc8a 100644
--- a/packages/graphql/lib/src/core/observable_query.dart
+++ b/packages/graphql/lib/src/core/observable_query.dart
@@ -145,7 +145,7 @@ class ObservableQuery {
     final combinedOptions = QueryOptions(
       fetchPolicy: FetchPolicy.noCache,
       errorPolicy: options.errorPolicy,
-      documentNode: fetchMoreOptions.documentNode ?? options.documentNode,
+      document: fetchMoreOptions.document ?? options.document,
       context: options.context,
       variables: {
         ...options.variables,
diff --git a/packages/graphql/lib/src/core/query_manager.dart b/packages/graphql/lib/src/core/query_manager.dart
index fdad03aa7..da7e282da 100644
--- a/packages/graphql/lib/src/core/query_manager.dart
+++ b/packages/graphql/lib/src/core/query_manager.dart
@@ -106,7 +106,7 @@ class QueryManager {
     // create a new request to execute
     final Request request = Request(
       operation: Operation(
-        document: options.documentNode,
+        document: options.document,
         operationName: options.operationName,
       ),
       variables: options.variables,
diff --git a/packages/graphql/lib/src/core/query_options.dart b/packages/graphql/lib/src/core/query_options.dart
index 6605b92a9..21a0c1f1b 100644
--- a/packages/graphql/lib/src/core/query_options.dart
+++ b/packages/graphql/lib/src/core/query_options.dart
@@ -70,6 +70,7 @@ class Policies {
         overrides?.fetch ?? fetch,
         overrides?.error ?? error,
       );
+
   operator ==(Object other) =>
       other is Policies && fetch == other.fetch && error == other.error;
 }
@@ -77,17 +78,13 @@ class Policies {
 /// Base options.
 class BaseOptions extends RawOperationData {
   BaseOptions({
-    @Deprecated('The "document" option has been deprecated, use "documentNode" instead')
-        String document,
-    DocumentNode documentNode,
+    @required DocumentNode document,
     Map<String, dynamic> variables,
     this.policies,
     this.context,
     this.optimisticResult,
   }) : super(
-          // ignore: deprecated_member_use_from_same_package
           document: document,
-          documentNode: documentNode,
           variables: variables,
         );
 
@@ -108,9 +105,7 @@ class BaseOptions extends RawOperationData {
 /// Query options.
 class QueryOptions extends BaseOptions {
   QueryOptions({
-    @Deprecated('The "document" option has been deprecated, use "documentNode" instead')
-        String document,
-    DocumentNode documentNode,
+    @required DocumentNode document,
     Map<String, dynamic> variables,
     FetchPolicy fetchPolicy,
     ErrorPolicy errorPolicy,
@@ -119,9 +114,7 @@ class QueryOptions extends BaseOptions {
     Context context,
   }) : super(
           policies: Policies(fetch: fetchPolicy, error: errorPolicy),
-          // ignore: deprecated_member_use_from_same_package
           document: document,
-          documentNode: documentNode,
           variables: variables,
           context: context,
           optimisticResult: optimisticResult,
@@ -139,9 +132,7 @@ typedef OnError = void Function(OperationException error);
 /// Mutation options
 class MutationOptions extends BaseOptions {
   MutationOptions({
-    @Deprecated('The "document" option has been deprecated, use "documentNode" instead')
-        String document,
-    DocumentNode documentNode,
+    @required DocumentNode document,
     Map<String, dynamic> variables,
     FetchPolicy fetchPolicy,
     ErrorPolicy errorPolicy,
@@ -151,9 +142,7 @@ class MutationOptions extends BaseOptions {
     this.onError,
   }) : super(
           policies: Policies(fetch: fetchPolicy, error: errorPolicy),
-          // ignore: deprecated_member_use_from_same_package
           document: document,
-          documentNode: documentNode,
           variables: variables,
           context: context,
         );
@@ -253,9 +242,7 @@ class MutationCallbacks {
 // ObservableQuery options
 class WatchQueryOptions extends QueryOptions {
   WatchQueryOptions({
-    @Deprecated('The "document" option has been deprecated, use "documentNode" instead')
-        String document,
-    DocumentNode documentNode,
+    @required DocumentNode document,
     Map<String, dynamic> variables,
     FetchPolicy fetchPolicy,
     ErrorPolicy errorPolicy,
@@ -265,9 +252,7 @@ class WatchQueryOptions extends QueryOptions {
     this.eagerlyFetchResults,
     Context context,
   }) : super(
-          // ignore: deprecated_member_use_from_same_package
           document: document,
-          documentNode: documentNode,
           variables: variables,
           fetchPolicy: fetchPolicy,
           errorPolicy: errorPolicy,
@@ -292,7 +277,7 @@ class WatchQueryOptions extends QueryOptions {
     WatchQueryOptions a,
     WatchQueryOptions b,
   ) {
-    if (a.documentNode != b.documentNode) {
+    if (a.document != b.document) {
       return true;
     }
 
@@ -313,7 +298,7 @@ class WatchQueryOptions extends QueryOptions {
   }
 
   WatchQueryOptions copy() => WatchQueryOptions(
-        documentNode: documentNode,
+        document: document,
         variables: variables,
         fetchPolicy: fetchPolicy,
         errorPolicy: errorPolicy,
@@ -334,33 +319,12 @@ typedef dynamic UpdateQuery(
 /// options for fetchmore operations
 class FetchMoreOptions {
   FetchMoreOptions({
-    @Deprecated('The "document" option has been deprecated, use "documentNode" instead')
-        String document,
-    DocumentNode documentNode,
+    @required this.document,
     this.variables = const <String, dynamic>{},
     @required this.updateQuery,
-  })  : assert(
-          // ignore: deprecated_member_use_from_same_package
-          _mutuallyExclusive(document, documentNode),
-          '"document" or "documentNode" options are mutually exclusive.',
-        ),
-        assert(updateQuery != null),
-        this.documentNode =
-            // ignore: deprecated_member_use_from_same_package
-            documentNode ?? document != null ? parseString(document) : null;
-
-  DocumentNode documentNode;
-
-  /// A string representation of [documentNode]
-  @Deprecated(
-      'The "document" option has been deprecated, use "documentNode" instead')
-  String get document => printNode(documentNode);
-
-  @Deprecated(
-      'The "document" option has been deprecated, use "documentNode" instead')
-  set document(value) {
-    documentNode = parseString(value);
-  }
+  }) : assert(updateQuery != null);
+
+  DocumentNode document;
 
   final Map<String, dynamic> variables;
 
@@ -368,12 +332,3 @@ class FetchMoreOptions {
   /// with the result data already in the cache
   UpdateQuery updateQuery;
 }
-
-bool _mutuallyExclusive(
-  Object a,
-  Object b, {
-  bool required = false,
-}) =>
-    (!required && a == null && b == null) ||
-    (a != null && b == null) ||
-    (a == null && b != null);
diff --git a/packages/graphql/lib/src/core/raw_operation_data.dart b/packages/graphql/lib/src/core/raw_operation_data.dart
index 5d003a9e8..415e0a756 100644
--- a/packages/graphql/lib/src/core/raw_operation_data.dart
+++ b/packages/graphql/lib/src/core/raw_operation_data.dart
@@ -2,50 +2,21 @@ import 'dart:collection' show SplayTreeMap;
 import 'dart:convert' show json;
 
 import 'package:gql/ast.dart';
-import 'package:gql/language.dart';
 import 'package:graphql/src/utilities/get_from_ast.dart';
+import 'package:meta/meta.dart';
 
 class RawOperationData {
   RawOperationData({
-    @Deprecated('The "document" option has been deprecated, use "documentNode" instead')
-        String document,
-    DocumentNode documentNode,
+    @required this.document,
     Map<String, dynamic> variables,
     String operationName,
-  })  : assert(
-          // ignore: deprecated_member_use_from_same_package
-          document != null || documentNode != null,
-          'Either a "document"  or "documentNode" option is required. '
-          'You must specify your GraphQL document in the query options.',
-        ),
-        // todo: Investigate why this assertion is failing
-        // assert(
-        //   (document != null && documentNode == null) ||
-        //       (document == null && documentNode != null),
-        //   '"document" or "documentNode" options are mutually exclusive.',
-        // ),
-        // ignore: deprecated_member_use_from_same_package
-        documentNode = documentNode ?? parseString(document),
-        _operationName = operationName,
+  })  : _operationName = operationName,
         variables = SplayTreeMap<String, dynamic>.of(
           variables ?? const <String, dynamic>{},
         );
 
   /// A GraphQL document that consists of a single query to be sent down to the server.
-  DocumentNode documentNode;
-
-  /// A string representation of [documentNode]
-  @Deprecated(
-    'The "document" option has been deprecated, use "documentNode" instead',
-  )
-  String get document => printNode(documentNode);
-
-  @Deprecated(
-    'The "document" option has been deprecated, use "documentNode" instead',
-  )
-  set document(value) {
-    documentNode = parseString(value);
-  }
+  DocumentNode document;
 
   /// A map going from variable name to variable value, where the variables are used
   /// within the GraphQL query.
@@ -55,7 +26,7 @@ class RawOperationData {
 
   /// The last operation name appearing in the contained document.
   String get operationName {
-    _operationName ??= getLastOperationName(documentNode);
+    _operationName ??= getLastOperationName(document);
     return _operationName;
   }
 
@@ -65,7 +36,7 @@ class RawOperationData {
   // TODO remove $document from key? A bit redundant, though that's not the worst thing
   String get _identifier {
     _documentIdentifier ??=
-        operationName ?? 'UNNAMED/' + documentNode.hashCode.toString();
+        operationName ?? 'UNNAMED/' + document.hashCode.toString();
     return _documentIdentifier;
   }
 
@@ -81,7 +52,6 @@ class RawOperationData {
     );
 
     // TODO: document is being depracated, find ways for generating key
-    // ignore: deprecated_member_use_from_same_package
     return '$document|$encodedVariables|$_identifier';
   }
 }
diff --git a/packages/graphql/test/anonymous_operations_test.dart b/packages/graphql/test/anonymous_operations_test.dart
index 3dbcdca6f..e69536cbe 100644
--- a/packages/graphql/test/anonymous_operations_test.dart
+++ b/packages/graphql/test/anonymous_operations_test.dart
@@ -50,7 +50,7 @@ void main() {
     group('query', () {
       test('successful query', () async {
         final WatchQueryOptions _options = WatchQueryOptions(
-          documentNode: parseString(readRepositories),
+          document: parseString(readRepositories),
           variables: <String, dynamic>{},
         );
 
@@ -129,7 +129,7 @@ void main() {
     group('mutation', () {
       test('successful mutation', () async {
         final MutationOptions _options = MutationOptions(
-          documentNode: parseString(addStar),
+          document: parseString(addStar),
         );
 
         when(
diff --git a/packages/graphql/test/core/raw_operation_data_test.dart b/packages/graphql/test/core/raw_operation_data_test.dart
index 05c189ca2..60fe97622 100644
--- a/packages/graphql/test/core/raw_operation_data_test.dart
+++ b/packages/graphql/test/core/raw_operation_data_test.dart
@@ -7,7 +7,7 @@ void main() {
     group('single operation', () {
       test('query without name', () {
         final opData = RawOperationData(
-          documentNode: parseString('query {}'),
+          document: parseString('query {}'),
         );
 
         expect(opData.operationName, null);
@@ -15,7 +15,7 @@ void main() {
 
       test('query with explicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString('query Operation {}'),
+          document: parseString('query Operation {}'),
           operationName: 'Operation',
         );
 
@@ -24,7 +24,7 @@ void main() {
 
       test('mutation with explicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString('mutation Operation {}'),
+          document: parseString('mutation Operation {}'),
           operationName: 'Operation',
         );
 
@@ -33,7 +33,7 @@ void main() {
 
       test('subscription with explicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString('subscription Operation {}'),
+          document: parseString('subscription Operation {}'),
           operationName: 'Operation',
         );
 
@@ -42,7 +42,7 @@ void main() {
 
       test('query with implicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString('query Operation {}'),
+          document: parseString('query Operation {}'),
         );
 
         expect(opData.operationName, 'Operation');
@@ -50,7 +50,7 @@ void main() {
 
       test('mutation with implicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString('mutation Operation {}'),
+          document: parseString('mutation Operation {}'),
         );
 
         expect(opData.operationName, 'Operation');
@@ -58,7 +58,7 @@ void main() {
 
       test('subscription with implicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString('subscription Operation {}'),
+          document: parseString('subscription Operation {}'),
         );
 
         expect(opData.operationName, 'Operation');
@@ -74,7 +74,7 @@ void main() {
 
       test('query with explicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString(document),
+          document: parseString(document),
           operationName: 'OperationQ',
         );
 
@@ -83,7 +83,7 @@ void main() {
 
       test('mutation with explicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString(document),
+          document: parseString(document),
           operationName: 'OperationM',
         );
 
@@ -92,7 +92,7 @@ void main() {
 
       test('subscription with explicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString(document),
+          document: parseString(document),
           operationName: 'OperationS',
         );
 
@@ -101,7 +101,7 @@ void main() {
 
       test('query with implicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString(document),
+          document: parseString(document),
         );
 
         expect(opData.operationName, 'OperationS');
@@ -109,7 +109,7 @@ void main() {
 
       test('mutation with implicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString(document),
+          document: parseString(document),
         );
 
         expect(opData.operationName, 'OperationS');
@@ -117,7 +117,7 @@ void main() {
 
       test('subscription with implicit name', () {
         final opData = RawOperationData(
-          documentNode: parseString(document),
+          document: parseString(document),
         );
 
         expect(opData.operationName, 'OperationS');
diff --git a/packages/graphql/test/graphql_client_test.dart b/packages/graphql/test/graphql_client_test.dart
index 19e983f4e..0d983c75a 100644
--- a/packages/graphql/test/graphql_client_test.dart
+++ b/packages/graphql/test/graphql_client_test.dart
@@ -52,7 +52,7 @@ void main() {
     group('query', () {
       test('successful response', () async {
         final WatchQueryOptions _options = WatchQueryOptions(
-          documentNode: parseString(readRepositories),
+          document: parseString(readRepositories),
           variables: <String, dynamic>{
             'nRepositories': 42,
           },
@@ -135,7 +135,7 @@ void main() {
 
         final QueryResult r = await graphQLClientClient.query(
           WatchQueryOptions(
-            documentNode: parseString(readRepositories),
+            document: parseString(readRepositories),
           ),
         );
 
@@ -158,7 +158,7 @@ void main() {
 
         final QueryResult r = await graphQLClientClient.query(
           WatchQueryOptions(
-            documentNode: parseString(readRepositories),
+            document: parseString(readRepositories),
           ),
         );
 
@@ -180,7 +180,7 @@ void main() {
     group('mutation', () {
       test('successful mutation', () async {
         final MutationOptions _options = MutationOptions(
-          documentNode: parseString(addStar),
+          document: parseString(addStar),
         );
 
         when(
diff --git a/packages/graphql_flutter/lib/src/widgets/mutation.dart b/packages/graphql_flutter/lib/src/widgets/mutation.dart
index 95aed793b..84886a101 100644
--- a/packages/graphql_flutter/lib/src/widgets/mutation.dart
+++ b/packages/graphql_flutter/lib/src/widgets/mutation.dart
@@ -39,9 +39,7 @@ class MutationState extends State<Mutation> {
 
   WatchQueryOptions get _providedOptions {
     final _options = WatchQueryOptions(
-      // ignore: deprecated_member_use
       document: widget.options.document,
-      documentNode: widget.options.documentNode,
       variables: widget.options.variables,
       fetchPolicy: widget.options.fetchPolicy,
       errorPolicy: widget.options.errorPolicy,
diff --git a/packages/graphql_flutter/lib/src/widgets/query.dart b/packages/graphql_flutter/lib/src/widgets/query.dart
index d21e4a1ca..66ad85fe9 100644
--- a/packages/graphql_flutter/lib/src/widgets/query.dart
+++ b/packages/graphql_flutter/lib/src/widgets/query.dart
@@ -39,9 +39,7 @@ class QueryState extends State<Query> {
     final QueryOptions options = widget.options;
 
     return WatchQueryOptions(
-      // ignore: deprecated_member_use
       document: options.document,
-      documentNode: options.documentNode,
       variables: options.variables,
       fetchPolicy: options.fetchPolicy,
       errorPolicy: options.errorPolicy,