Error using GraphQLHttpClient for subscription

209 views Asked by At

I learn aws AppSync subscription using an example in the following references

https://github.com/graphql-dotnet/graphql-client/issues/372

using System;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using GraphQL;
using UnityEngine;
using GraphQL.Client.Http;
using GraphQL.Client.Serializer.Newtonsoft;
using Newtonsoft.Json;
using GraphQL.Client.Abstractions;
using TMPro;

public class GraphQLHelloWorld : MonoBehaviour
{
 [SerializeField] private string _host = "example12345.appsync-api.us-east-2.amazonaws.com";
[SerializeField] private string _realtimeHost = "example12345.appsync-realtime-api.us-east-2.amazonaws.com";
[SerializeField] private string _apiKey = "YOUR_API_KEY_HERE";

[SerializeField] private TMP_InputField _queryInputField;
[SerializeField] private TMP_InputField _mutationInputField;
[SerializeField] private TMP_InputField _subscriptionInputField;
    
public class EventType
{
    public string id { get; set; }
    public string name { get; set; }
    public string where { get; set; }
    public string when { get; set; }
    public string description { get; set; }
}

public class CommentType
{
    public string eventId { get; set; }
    public string commentId { get; set; }
    public string content { get; set; }
    public string createdAt { get; set; }
}

public class QueryResponse
{
    public EventType getEvent { get; set; }
}

public class CreateMutationResponse
{
    public EventType createEvent { get; set; }
}

public class CreateCommentResponse
{
    public CommentType commentOnEvent { get; set; }
}

public class SubscriptionResponse
{
    public CommentType subscribeToEventComments { get; set; }
}

private void OnDestroy()
{
    _subscription?.Dispose();
}

private class AppSyncHeader
{
    [JsonProperty("host")] public string Host { get; set; }

    [JsonProperty("x-api-key")] public string ApiKey { get; set; }

    public string ToJson()
    {
        return JsonConvert.SerializeObject(this);
    }

    public string ToBase64String()
    {
        return Convert.ToBase64String(Encoding.UTF8.GetBytes(ToJson()));
    }
}

public class AuthorizedAppSyncHttpRequest : GraphQLHttpRequest
{
    private readonly string _authorization;

    public AuthorizedAppSyncHttpRequest(GraphQLRequest request, string authorization) : base(request)
        => _authorization = authorization;

    public override HttpRequestMessage ToHttpRequestMessage(GraphQLHttpClientOptions options, IGraphQLJsonSerializer serializer)
    {
        HttpRequestMessage result = base.ToHttpRequestMessage(options, serializer);
        result.Headers.Add("X-Api-Key", _authorization);
        return result;
    }
}

private IDisposable _subscription;

public async void OnClickQuery()
{
    GraphQLHttpClient graphQLClient = new GraphQLHttpClient($"https://{_host}/graphql", new NewtonsoftJsonSerializer());
    graphQLClient.HttpClient.DefaultRequestHeaders.Add("x-api-key", _apiKey);

    GraphQLRequest query = new GraphQLRequest
    {
        Query = _queryInputField.text,
    };

    var response = await graphQLClient.SendQueryAsync<QueryResponse>(query, CancellationToken.None);

    Debug.Log($"[Query] {JsonConvert.SerializeObject(response.Data)}");
}

public async void OnClickMutation()
{
    GraphQLHttpClient graphQLClient = new GraphQLHttpClient($"https://{_host}/graphql", new NewtonsoftJsonSerializer());
    graphQLClient.HttpClient.DefaultRequestHeaders.Add("x-api-key", _apiKey);

    GraphQLRequest request = new GraphQLRequest
    {
        Query = _mutationInputField.text,
    };

    var response = await graphQLClient.SendQueryAsync<CreateCommentResponse>(request, CancellationToken.None);

    Debug.Log($"[Mutation] {JsonConvert.SerializeObject(response.Data)}");
}

public async void OnClickSubscription()
{
    GraphQLHttpClient graphQLClient = new GraphQLHttpClient($"https://{_host}/graphql", new NewtonsoftJsonSerializer());

    AppSyncHeader appSyncHeader = new AppSyncHeader
    {
        Host = _host,
        ApiKey = _apiKey,
    };

    string header = appSyncHeader.ToBase64String();

    graphQLClient.Options.WebSocketEndPoint = new Uri($"wss://{_realtimeHost}/graphql?header={header}&payload=e30=");
    graphQLClient.Options.PreprocessRequest = (req, client) =>
    {
        GraphQLHttpRequest result = new AuthorizedAppSyncHttpRequest(req, _apiKey)
        {
            ["data"] = JsonConvert.SerializeObject(req),
            ["extensions"] = new
            {
                authorization = appSyncHeader,
            }
        };
        return Task.FromResult(result);
    };

    await graphQLClient.InitializeWebsocketConnection();

    Debug.Log("Initialized a web scoket connection.");

    GraphQLRequest request = new GraphQLRequest
    {
        Query = _subscriptionInputField.text,
    };

    var subscriptionStream = graphQLClient.CreateSubscriptionStream<SubscriptionResponse>(request, ex => { Debug.Log(ex); });
    _subscription = subscriptionStream.Subscribe(
        response => Debug.Log($"[Subscription] {JsonConvert.SerializeObject(response.Data)}"),
        exception => Debug.Log(exception),
        () => Debug.Log("Completed."));
 }
}

Query and mutation seems working. However, Subscription doesn't work. It stuck in the following line:

 await graphQLClient.InitializeWebsocketConnection();

There is an exception when executing above line of code.

{"The remote party closed the WebSocket connection without completing the close handshake."}

I struggled to find a solution.

0

There are 0 answers