Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

CreateSubscriptionStream.Subscribe completes immediately with AppSync #372

Closed
edom18 opened this issue Nov 9, 2021 · 3 comments
Closed

Comments

@edom18
Copy link

edom18 commented Nov 9, 2021

I'm new to GraphQL and GraphQL.Client.

I'm trying to use GraphQL.Client with AWS AppSync. I have a trouble that my subscription will complete immediatly. My code is like below.

I'll invoke below code, the subscription will complete immediatly. This means that "Completed" message will appear in console immediatly.

What was wrong?

public async void SubscribeTest()
{
    var domain = "example12345.appsync-api.us-east-2.amazonaws.com";
    var wdomain = "example12345.appsync-realtime-api.us-east-2.amazonaws.com";
    var headerStr = JsonConvert.SerializeObject(new Dictionary<string, object>
    {
        ["host"] = domain,
        ["x-api-key"] = API_KEY,
    });
    var header = Convert.ToBase64String(Encoding.UTF8.GetBytes(headerStr));
    var graphQLClient = new GraphQLHttpClient($"wss://{wdomain}/graphql?header={header}&payload=e30=", new NewtonsoftJsonSerializer());

    await graphQLClient.InitializeWebsocketConnection();

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

    var query = new GraphQLRequest
    {
        Query = @"
        subscription MySubscription {
          subscribeToHoge {
            name
            age
          }
        }",
    };

    var request = new GraphQLRequest
    {
        ["data"] = JsonConvert.SerializeObject(query),
        ["extensions"] = new
        {
            authorization = headerStr,
        }
    };

    var subscriptionStream = graphQLClient.CreateSubscriptionStream<SubscriptionResponse>(request, ex => { Debug.Log(ex); });
    _subscription = subscriptionStream.Subscribe(
        response => Debug.Log(response),
        exception => Debug.Log(exception),
        () => Debug.Log("Completed."));
}
@rose-a
Copy link
Collaborator

rose-a commented Nov 9, 2021

I've not worked with AppSync myself, but @bjorg created a sample app which might help you along:

https://github.com/bjorg/GraphQlAppSyncTest

@edom18
Copy link
Author

edom18 commented Nov 10, 2021

Thank you for your advice! I'll check it out!

@edom18
Copy link
Author

edom18 commented Dec 10, 2021

@rose-a I fixed my problem by your advice. I finally got the correct result below. (I'm using Unity)

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."));
    }
}

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants