I have a flutter frontend where I use graphql_flutter to connect to an AWS AppSync graphql API. Queries and Mutations work exactly as expected. I am also able to establish a WebSocket connection for a subscription, but when I(graphql_flutter) send the start message:
{
"type": "start",
"id": "061bf284-c738-4a83-96e9-c8cf4b17369e",
"payload": {
"data": "{\"query\":\"subscription TransportChanged {\n transportChange {\n id\n __typename\n }\n __typename\n}\",\"variables\":{}}",
"extensions": {
"authorization": {
"Authorization": "base64encodedAuthorizationHeader",
"host": "actual_api.appsync-api.eu-central-1.amazonaws.com"
}
}
}
}
~
to subscribe I receive
{
"id": "061bf284-c738-4a83-96e9-c8cf4b17369e",
"type": "error",
"payload": {
"errors": [
{
"errorType": "DuplicatedOperationError",
"message": "Duplicated operation with id 061bf284-c738-4a83-96e9-c8cf4b17369e"
}
]
}
}
and then
{
"id": "061bf284-c738-4a83-96e9-c8cf4b17369e",
"type": "start_ack"
}
But I don't receive any events over the connection. I have tried out to connect to the subscription through the AWS AppSync QueryConsole and it works, so it must be something with my local setup.
Graphql is configured like this to work with the AppSync API:
var authSession = context.read<AppUser>().getAuthSessionFromState();
final String? authenticationToken =
context.watch<AppUser>().authenticationToken;
Link link;
final HttpLink httpLink = HttpLink(
graphqlUrl,
);
if (authenticationToken != null && authenticationToken.isNotEmpty) {
final AuthLink authLink = AuthLink(
getToken: () async => authenticationToken,
headerKey: 'Authorization');
graphQLClientIsAuthenticated = true;
currentToken = authenticationToken;
_tokenExpiry = authSession?.userPoolTokens?.idToken.claims.expiration;
String toBase64(Map data) => base64.encode(utf8.encode(jsonEncode(data)));
final authHeader = {
"Authorization": authenticationToken,
"host": graphqlHost,
};
final encodedHeader = toBase64(authHeader);
final WebSocketLink wsLink = WebSocketLink(
"$graphqlRealTimeUrl?header=$encodedHeader&payload=e30=",
config: SocketClientConfig(
serializer: AppSyncRequest(
authHeader: authHeader),
inactivityTimeout: const Duration(seconds: 60),
),
);
link = Link.split((request) => request.isSubscription,
authLink.concat(wsLink), authLink.concat(httpLink));
} else {
link = httpLink;
}
The AppSyncRequest
looks like this:
import 'dart:convert';
import 'package:gql/language.dart' show printNode;
import 'package:graphql_flutter/graphql_flutter.dart';
class AppSyncRequest extends RequestSerializer {
final Map<String, dynamic> authHeader;
const AppSyncRequest({
required this.authHeader,
});
@override
Map<String, dynamic> serializeRequest(Request request) => {
"data": jsonEncode({
"query": printNode(request.operation.document),
"variables": request.variables.isEmpty?null: request.variables,
}),
"extensions": {
"authorization": this.authHeader,
}
};
}
I have seen another question about DuplicatedOperationError that was solved by the owner as being a network issue. AWS AppSync - Duplicated Operation Error - subscriptions not working This is not the case for me.