Exemple #1
0
        private async Task CreateFactoryOptionsAsync(
            RemoteSchemaDefinition schemaDefinition,
            IList <IConfigureRequestExecutorSetup> factoryOptions,
            CancellationToken cancellationToken)
        {
            await using ServiceProvider services =
                            new ServiceCollection()
                            .AddGraphQL(_schemaName)
                            .AddRemoteSchema(
                                schemaDefinition.Name,
                                (sp, ct) => new ValueTask <RemoteSchemaDefinition>(schemaDefinition))
                            .Services
                            .BuildServiceProvider();

            IRequestExecutorOptionsMonitor optionsMonitor =
                services.GetRequiredService <IRequestExecutorOptionsMonitor>();

            RequestExecutorSetup options =
                await optionsMonitor.GetAsync(schemaDefinition.Name, cancellationToken)
                .ConfigureAwait(false);

            factoryOptions.Add(new ConfigureRequestExecutorSetup(schemaDefinition.Name, options));

            options =
                await optionsMonitor.GetAsync(_schemaName, cancellationToken)
                .ConfigureAwait(false);

            factoryOptions.Add(new ConfigureRequestExecutorSetup(_schemaName, options));
        }
Exemple #2
0
        private string SerializeSchemaDefinition(RemoteSchemaDefinition schemaDefinition)
        {
            var dto = new SchemaDefinitionDto
            {
                Name     = schemaDefinition.Name.Value,
                Document = schemaDefinition.Document.ToString(false),
            };

            dto.ExtensionDocuments.AddRange(
                schemaDefinition.ExtensionDocuments.Select(t => t.ToString()).ToList());

            return(JsonSerializer.Serialize(dto));
        }
Exemple #3
0
        public async ValueTask PublishAsync(
            RemoteSchemaDefinition schemaDefinition,
            CancellationToken cancellationToken = default)
        {
            string key  = $"{_configurationName}.{schemaDefinition.Name}";
            string json = SerializeSchemaDefinition(schemaDefinition);

            IDatabase database = _connection.GetDatabase();
            await database.StringSetAsync(key, json).ConfigureAwait(false);

            await database.SetAddAsync(_configurationName.Value, schemaDefinition.Name.Value)
            .ConfigureAwait(false);

            ISubscriber subscriber = _connection.GetSubscriber();
            await subscriber.PublishAsync(_configurationName.Value, schemaDefinition.Name.Value)
            .ConfigureAwait(false);
        }
Exemple #4
0
        private async ValueTask <IEnumerable <RemoteSchemaDefinition> > GetSchemaDefinitionsAsync(
            CancellationToken cancellationToken)
        {
            RedisValue[] items = await _database.SetMembersAsync(_configurationName.Value)
                                 .ConfigureAwait(false);

            var schemaDefinitions = new List <RemoteSchemaDefinition>();

            foreach (var schemaName in items.Select(t => (string)t))
            {
                cancellationToken.ThrowIfCancellationRequested();

                RemoteSchemaDefinition schemaDefinition =
                    await GetRemoteSchemaDefinitionAsync(schemaName)
                    .ConfigureAwait(false);

                schemaDefinitions.Add(schemaDefinition);
            }

            return(schemaDefinitions);
        }
Exemple #5
0
        private async Task OnChangeMessageAsync(ChannelMessage message)
        {
            string schemaName = message.Message;

            RemoteSchemaDefinition schemaDefinition =
                await GetRemoteSchemaDefinitionAsync(schemaName)
                .ConfigureAwait(false);

            var factoryOptions = new List <IConfigureRequestExecutorSetup>();

            await CreateFactoryOptionsAsync(schemaDefinition, factoryOptions, default)
            .ConfigureAwait(false);

            lock (_listeners)
            {
                foreach (OnChangeListener listener in _listeners)
                {
                    foreach (IConfigureRequestExecutorSetup options in factoryOptions)
                    {
                        listener.OnChange(options);
                    }
                }
            }
        }
Exemple #6
0
        public static IRequestExecutorBuilder AddRemoteSchema(
            this IRequestExecutorBuilder builder,
            NameString schemaName,
            Func <IServiceProvider, CancellationToken, ValueTask <RemoteSchemaDefinition> > loadSchema,
            bool ignoreRootTypes = false)
        {
            if (builder is null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            if (loadSchema is null)
            {
                throw new ArgumentNullException(nameof(loadSchema));
            }

            schemaName.EnsureNotEmpty(nameof(schemaName));

            // first we add a full GraphQL schema and executor that represents the remote schema.
            // This remote schema will be used by the stitching engine to execute queries against
            // this schema and also to lookup types in order correctly convert between scalars.
            builder
            .AddGraphQL(schemaName)
            .ConfigureSchemaServices(services =>
            {
                services.TryAddSingleton(
                    sp => new HttpRequestClient(
                        sp.GetApplicationService <IHttpClientFactory>(),
                        sp.GetRequiredService <IErrorHandler>(),
                        sp.GetRequiredService <IHttpStitchingRequestInterceptor>()));

                services.TryAddSingleton <
                    IHttpStitchingRequestInterceptor,
                    HttpStitchingRequestInterceptor>();
            })
            .ConfigureSchemaAsync(
                async(services, schemaBuilder, cancellationToken) =>
            {
                // No we need to load the schema document.
                RemoteSchemaDefinition schemaDef =
                    await loadSchema(services, cancellationToken)
                    .ConfigureAwait(false);

                DocumentNode document = schemaDef.Document.RemoveBuiltInTypes();

                // We store the schema definition on the schema building context
                // and copy it to the schema once that is built.
                schemaBuilder
                .SetContextData(typeof(RemoteSchemaDefinition).FullName !, schemaDef)
                .TryAddTypeInterceptor <CopySchemaDefinitionTypeInterceptor>();

                // The document is used to create a SDL-first schema ...
                schemaBuilder.AddDocument(document);

                // ... which will fail if any resolver is actually used ...
                schemaBuilder.Use(next => context => throw new NotSupportedException());
            })
            // ... instead we are using a special request pipeline that does everything like
            // the standard pipeline except the last middleware will not start the execution
            // algorithms but delegate the request via HTTP to the downstream schema.
            .UseHttpRequestPipeline();

            // Next, we will register a request executor proxy with the stitched schema,
            // that the stitching runtime will use to send requests to the schema representing
            // the downstream service.
            builder
            .ConfigureSchemaAsync(async(services, schemaBuilder, cancellationToken) =>
            {
                IInternalRequestExecutorResolver noLockExecutorResolver =
                    services.GetRequiredService <IInternalRequestExecutorResolver>();

                IRequestExecutor executor = await noLockExecutorResolver
                                            .GetRequestExecutorNoLockAsync(schemaName, cancellationToken)
                                            .ConfigureAwait(false);

                var autoProxy = AutoUpdateRequestExecutorProxy.Create(
                    new RequestExecutorProxy(
                        services.GetRequiredService <IRequestExecutorResolver>(),
                        schemaName),
                    executor);

                schemaBuilder
                .AddRemoteExecutor(schemaName, autoProxy)
                .TryAddSchemaInterceptor <StitchingSchemaInterceptor>()
                .TryAddTypeInterceptor <StitchingTypeInterceptor>();

                var schemaDefinition =
                    (RemoteSchemaDefinition)autoProxy.Schema
                    .ContextData[typeof(RemoteSchemaDefinition).FullName !] !;

                var extensionsRewriter = new SchemaExtensionsRewriter();

                foreach (var extensionDocument in schemaDefinition.ExtensionDocuments)
                {
                    var doc = (DocumentNode)extensionsRewriter
                              .Rewrite(extensionDocument, schemaName.Value);

                    SchemaExtensionNode?schemaExtension =
                        doc.Definitions.OfType <SchemaExtensionNode>().FirstOrDefault();

                    if (schemaExtension is not null &&
                        schemaExtension.Directives.Count == 0 &&
                        schemaExtension.OperationTypes.Count == 0)
                    {
                        var definitions = doc.Definitions.ToList();
                        definitions.Remove(schemaExtension);
                        doc = doc.WithDefinitions(definitions);
                    }

                    schemaBuilder.AddTypeExtensions(doc);
                }

                schemaBuilder.AddTypeRewriter(
                    new RemoveFieldRewriter(
                        new FieldReference(
                            autoProxy.Schema.QueryType.Name,
                            SchemaDefinitionFieldNames.SchemaDefinitionField),
                        schemaName));

                schemaBuilder.AddDocumentRewriter(
                    new RemoveTypeRewriter(
                        SchemaDefinitionType.Names.SchemaDefinition,
                        schemaName));

                foreach (var schemaAction in extensionsRewriter.SchemaActions)
                {
                    switch (schemaAction.Name.Value)
                    {
                    case DirectiveNames.RemoveRootTypes:
                        schemaBuilder.AddDocumentRewriter(
                            new RemoveRootTypeRewriter(schemaName));
                        break;

                    case DirectiveNames.RemoveType:
                        schemaBuilder.AddDocumentRewriter(
                            new RemoveTypeRewriter(
                                GetArgumentValue(
                                    schemaAction,
                                    DirectiveFieldNames.RemoveType_TypeName),
                                schemaName));
                        break;

                    case DirectiveNames.RenameType:
                        schemaBuilder.AddTypeRewriter(
                            new RenameTypeRewriter(
                                GetArgumentValue(
                                    schemaAction,
                                    DirectiveFieldNames.RenameType_TypeName),
                                GetArgumentValue(
                                    schemaAction,
                                    DirectiveFieldNames.RenameType_NewTypeName),
                                schemaName));
                        break;

                    case DirectiveNames.RenameField:
                        schemaBuilder.AddTypeRewriter(
                            new RenameFieldRewriter(
                                new FieldReference(
                                    GetArgumentValue(
                                        schemaAction,
                                        DirectiveFieldNames.RenameField_TypeName),
                                    GetArgumentValue(
                                        schemaAction,
                                        DirectiveFieldNames.RenameField_FieldName)),
                                GetArgumentValue(
                                    schemaAction,
                                    DirectiveFieldNames.RenameField_NewFieldName),
                                schemaName));
                        break;
                    }
                }
            });