コード例 #1
0
        /// <summary>
        /// Attempts to find and remove a subscription with the given client id on the message for the target subscription.
        /// </summary>
        /// <param name="message">The message containing the subscription id to stop.</param>
        /// <returns>Task.</returns>
        private async Task ExecuteStopRequest(ApolloClientStopMessage message)
        {
            var totalRemaining = _subscriptions.Remove(message.Id, out var subFound);

            if (subFound != null)
            {
                _reservedMessageIds.ReleaseMessageId(subFound.Id);
                if (totalRemaining == 0)
                {
                    this.SubscriptionRouteRemoved?.Invoke(this, new ApolloSubscriptionFieldEventArgs(subFound.Field));
                }

                _logger?.SubscriptionStopped(subFound);

                await this
                .SendMessage(new ApolloServerCompleteMessage(subFound.Id))
                .ConfigureAwait(false);
            }
            else
            {
                var errorMessage = new ApolloServerErrorMessage(
                    $"No active subscription exists with id '{message.Id}'",
                    Constants.ErrorCodes.BAD_REQUEST,
                    lastMessage: message,
                    clientProvidedId: message.Id);

                await this
                .SendMessage(errorMessage)
                .ConfigureAwait(false);
            }
        }
コード例 #2
0
        public void ErrorMessage_WithId_SerializesWithIdParameter()
        {
            var dt     = DateTime.UtcNow;
            var server = new TestServerBuilder()
                         .AddGraphController <ApolloDataMessageController>()
                         .AddSubscriptionServer()
                         .AddGraphQL(options =>
            {
                options.ResponseOptions.TimeStampLocalizer = (time) => dt;
            })
                         .Build();

            var converter = new ApolloServerErrorMessageConverter(server.Schema);

            var message = new ApolloServerErrorMessage(
                "an error occured",
                Constants.ErrorCodes.BAD_REQUEST,
                GraphMessageSeverity.Warning,
                "prev123",
                lastMessageType: ApolloMessageType.START,
                clientProvidedId: "abc123");

            var options = new JsonSerializerOptions();

            options.Converters.Add(converter);
            var response = JsonSerializer.Serialize(message, message.GetType(), options);

            // error message should render a single IGraphMessage
            // that is normally part of the errors collection on a standard response
            var expected = @"
            {
                ""id"": ""abc123"",
                ""type"":""error"",
                ""payload"":{
                    ""message"":""an error occured"",
                    ""extensions"":{
                        ""code"":""BAD_REQUEST"",
                        ""timestamp"":""{dateString}"",
                        ""severity"":""WARNING"",
                        ""metaData"":{
                            ""lastMessage_id"":""prev123"",
                            ""lastMessage_type"":""start""
                        }
                    }
                }
            }";

            expected = expected.Replace("{dateString}", dt.ToRfc3339String());

            CommonAssertions.AreEqualJsonStrings(expected, response);
        }
コード例 #3
0
        /// <summary>
        /// Returns a generic error to the client indicating that the last message recieved was unknown or invalid.
        /// </summary>
        /// <param name="lastMessage">The last message that was received that was unprocessable.</param>
        /// <returns>Task.</returns>
        private Task UnknownMessageRecieved(ApolloMessage lastMessage)
        {
            var apolloError = new ApolloServerErrorMessage(
                "The last message recieved was unknown or could not be processed " +
                "by this server. This graph ql is configured to use Apollo's GraphQL over websockets " +
                "message schema.",
                Constants.ErrorCodes.BAD_REQUEST,
                lastMessage: lastMessage,
                clientProvidedId: lastMessage.Id);

            apolloError.Payload.MetaData.Add(
                Constants.Messaging.REFERENCE_RULE_NUMBER,
                "Unknown Message Type");

            apolloError.Payload.MetaData.Add(
                Constants.Messaging.REFERENCE_RULE_URL,
                "https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md");

            return(this.SendMessage(apolloError));
        }
コード例 #4
0
        /// <summary>
        /// Parses the message contents to generate a valid client subscription and adds it to the watched
        /// set for this instance.
        /// </summary>
        /// <param name="message">The message with the subscription details.</param>
        private async Task ExecuteStartRequest(ApolloClientStartMessage message)
        {
            // ensure the id isnt already in use
            if (!_reservedMessageIds.ReserveMessageId(message.Id))
            {
                await this
                .SendMessage(new ApolloServerErrorMessage(
                                 $"The message id {message.Id} is already reserved for an outstanding request and cannot " +
                                 "be processed against. Allow the in-progress request to complete or stop the associated subscription.",
                                 SubscriptionConstants.ErrorCodes.DUPLICATE_MESSAGE_ID,
                                 lastMessage : message,
                                 clientProvidedId : message.Id))
                .ConfigureAwait(false);

                return;
            }

            var retainMessageId = false;
            var runtime         = this.ServiceProvider.GetRequiredService(typeof(IGraphQLRuntime <TSchema>)) as IGraphQLRuntime <TSchema>;
            var request         = runtime.CreateRequest(message.Payload);
            var metricsPackage  = _enableMetrics ? runtime.CreateMetricsPackage() : null;
            var context         = new SubcriptionExecutionContext(
                this,
                request,
                message.Id,
                metricsPackage);

            var result = await runtime
                         .ExecuteRequest(context)
                         .ConfigureAwait(false);

            if (context.IsSubscriptionOperation)
            {
                retainMessageId = await this
                                  .RegisterSubscriptionOrRespond(context.Subscription as ISubscription <TSchema>)
                                  .ConfigureAwait(false);
            }
            else
            {
                // not a subscription, just send back the generated response and close out the id
                ApolloMessage responseMessage;

                // report syntax errors as error messages
                // allow others to bubble into a fully reslt (per apollo spec)
                if (result.Messages.Count == 1 &&
                    result.Messages[0].Code == Constants.ErrorCodes.SYNTAX_ERROR)
                {
                    responseMessage = new ApolloServerErrorMessage(
                        result.Messages[0],
                        message,
                        message.Id);
                }
                else
                {
                    responseMessage = new ApolloServerDataMessage(message.Id, result);
                }

                await this
                .SendMessage(responseMessage)
                .ConfigureAwait(false);

                await this
                .SendMessage(new ApolloServerCompleteMessage(message.Id))
                .ConfigureAwait(false);
            }

            if (!retainMessageId)
            {
                _reservedMessageIds.ReleaseMessageId(message.Id);
            }
        }