Fix apollo support

This commit is contained in:
Tobe O 2019-04-18 22:02:42 -04:00
parent c58c8db65f
commit 940f6235af
9 changed files with 71 additions and 55 deletions

View file

@ -81,8 +81,9 @@ main() async {
);
// Mount GraphQL routes; we'll support HTTP and WebSockets transports.
app.get('/graphql', graphQLHttp(GraphQL(schema)));
app.get('/subscriptions', graphQLWS(GraphQL(schema)));
app.all('/graphql', graphQLHttp(GraphQL(schema)));
app.get('/subscriptions',
graphQLWS(GraphQL(schema), keepAliveInterval: Duration(seconds: 3)));
app.get('/graphiql',
graphiQL(subscriptionsEndpoint: 'ws://localhost:3000/subscriptions'));

View file

@ -26,7 +26,7 @@ String renderGraphiql(
if (subscriptionsEndpoint != null) {
fetcherName = 'subscriptionsFetcher';
subscriptionsScripts = '''
<script src="//unpkg.com/subscriptions-transport-ws@0.5.4/browser/client.js"></script>
<script src="//unpkg.com/subscriptions-transport-ws@0.8.3/browser/client.js"></script>
<script src="//unpkg.com/graphiql-subscriptions-fetcher@0.0.2/browser/client.js"></script>
''';
subscriptionsFetcher = '''

View file

@ -22,12 +22,12 @@ RequestHandler graphQLWS(GraphQL graphQL, {Duration keepAliveInterval}) {
await res.detach();
var socket = await WebSocketTransformer.upgrade(req.rawRequest,
protocolSelector: (protocols) {
if (protocols.contains('graphql-subscriptions'))
return 'graphql-subscriptions';
if (protocols.contains('graphql-ws'))
return 'graphql-ws';
else
throw AngelHttpException.badRequest(
message:
'Only the "graphql-subscriptions" protocol is allowed.');
'Only the "graphql-ws" protocol is allowed.');
});
var channel = IOWebSocketChannel(socket);
var client = stw.RemoteClient(channel.cast<String>());

View file

@ -18,6 +18,6 @@ dependencies:
dev_dependencies:
angel_serialize: ^2.0.0
logging: ^0.11.0
# dependency_overrides:
# graphql_server:
# path: ../graphql_server
dependency_overrides:
graphql_server:
path: ../graphql_server

View file

@ -1,3 +1,6 @@
# 1.0.0-rc.0
* Get the Apollo support working with the latest version of `subscriptions-transport-ws`.
# 1.0.0-beta.4
For some reason, Pub was not including `subscriptions_transport_ws.dart`.

View file

@ -3,7 +3,7 @@ import 'package:graphql_schema/graphql_schema.dart';
/// Performs introspection over a GraphQL [schema], and returns a new one, containing
/// introspective information.
///
///
/// [allTypes] should contain all types, not directly defined in the schema, that you
/// would like to have introspection available for.
GraphQLSchema reflectSchema(GraphQLSchema schema, List<GraphQLType> allTypes) {

View file

@ -8,6 +8,7 @@ abstract class Server {
final Completer _done = Completer();
StreamSubscription<OperationMessage> _sub;
bool _init = false;
Timer _timer;
Future get done => _done.future;
@ -29,10 +30,14 @@ abstract class Server {
client.sink
.add(OperationMessage(OperationMessage.gqlConnectionAck));
// if (keepAliveInterval != null) {
// client.sink.add(
// OperationMessage(OperationMessage.gqlConnectionKeepAlive));
// }
if (keepAliveInterval != null) {
client.sink.add(
OperationMessage(OperationMessage.gqlConnectionKeepAlive));
_timer ??= Timer.periodic(keepAliveInterval, (timer) {
client.sink.add(OperationMessage(
OperationMessage.gqlConnectionKeepAlive));
});
}
} catch (e) {
if (e == false)
_reportError('The connection was rejected.');
@ -66,46 +71,46 @@ abstract class Server {
query as String,
(variables as Map)?.cast<String, dynamic>(),
operationName as String);
// var c = Completer();
// if (keepAliveInterval != null) {
// Timer.periodic(keepAliveInterval, (timer) {
// if (c.isCompleted) {
// timer.cancel();
// } else {
// client.sink.add(OperationMessage(
// OperationMessage.gqlConnectionKeepAlive,
// id: msg.id));
// }
// });
// }
var data = result.data;
if (data is Stream) {
await for (var event in data) {
client.sink.add(OperationMessage(OperationMessage.gqlData,
id: msg.id,
payload: {'data': event, 'errors': result.errors}));
}
} else {
if (result.errors.isNotEmpty) {
client.sink.add(OperationMessage(OperationMessage.gqlData,
id: msg.id,
payload: {'data': data, 'errors': result.errors}));
id: msg.id, payload: {'errors': result.errors.toList()}));
} else {
if (data is Map &&
data.keys.length == 1 &&
data.containsKey('data')) {
data = data['data'];
}
if (data is Stream) {
await for (var event in data) {
if (event is Map &&
event.keys.length == 1 &&
event.containsKey('data')) {
event = event['data'];
}
client.sink.add(OperationMessage(OperationMessage.gqlData,
id: msg.id, payload: {'data': event}));
}
} else {
client.sink.add(OperationMessage(OperationMessage.gqlData,
id: msg.id, payload: {'data': data}));
}
}
// c.complete();
client.sink.add(
OperationMessage(OperationMessage.gqlComplete, id: msg.id));
} else if (msg.type == OperationMessage.gqlConnectionTerminate) {
await _sub?.cancel();
}
// TODO: https://github.com/apollographql/subscriptions-transport-ws/issues/551
// else if (msg.type == OperationMessage.gqlConnectionTerminate) {
// await _sub?.cancel();
// }
}
},
onError: _done.completeError,
onDone: () {
_done.complete();
_timer?.cancel();
});
}

View file

@ -1,21 +1,28 @@
import 'dart:async';
import 'package:graphql_schema/graphql_schema.dart';
import 'package:stream_channel/stream_channel.dart';
/// A basic message in the Apollo WebSocket protocol.
class OperationMessage {
static const String gqlConnectionInit = 'init',
gqlConnectionAck = 'init_success',
gqlConnectionKeepAlive = 'keepalive',
gqlConnectionError = 'init_fail',
gqlStart = 'subscription_start',
gqlStop = 'subscription_end',
// TODO: Does this have a replacement?
// https://github.com/apollographql/subscriptions-transport-ws/issues/551
// gqlConnectionTerminate = 'subscription_end',
gqlData = 'subscription_data',
gqlError = 'subscription_fail',
gqlComplete = 'subscription_success';
static const String gqlConnectionInit = 'connection_init',
gqlConnectionAck = 'connection_ack',
gqlConnectionKeepAlive = 'ka',
gqlConnectionError = 'connection_error',
gqlStart = 'start',
gqlStop = 'stop',
gqlConnectionTerminate = 'connection_terminate',
gqlData = 'data',
gqlError = 'error',
gqlComplete = 'complete';
static const String legacyGqlConnectionInit = 'connection_init',
legacyGqlConnectionAck = 'connection_ack',
legacyGqlConnectionKeepAlive = 'ka',
legacyGqlConnectionError = 'connection_error',
legacyGqlStart = 'start',
legacyGqlStop = 'stop',
legacyGqlConnectionTerminate = 'connection_terminate',
legacyGqlData = 'data',
legacyGqlError = 'error',
legacyGqlComplete = 'complete';
// static const String gqlConnectionInit = 'GQL_CONNECTION_INIT',
// gqlConnectionAck = 'GQL_CONNECTION_ACK',
// gqlConnectionKeepAlive = 'GQL_CONNECTION_KEEP_ALIVE',

View file

@ -1,5 +1,5 @@
name: graphql_server
version: 1.0.0-beta.4
version: 1.0.0-rc.0
author: Tobe O <thosakwe@gmail.com>
description: Base package for implementing GraphQL servers. You might prefer `package:angel_graphql`, the fastest way to implement GraphQL backends in Dart.
homepage: https://github.com/angel-dart/graphql