【问题标题】:Serve both REST and GraphQL APIs from .NET Core application从 .NET Core 应用程序同时提供 REST 和 GraphQL API
【发布时间】:2020-09-28 00:35:21
【问题描述】:

我有一个已经在为客户服务的 .NET Core REST API 服务器。

我能否通过添加 HotChocolate 库并定义查询来配置 API 服务器以支持 GraphQL?是否可以从我的 .NET Core 服务器同时提供 GraphQL 和 REST API?

【问题讨论】:

    标签: asp.net-core graphql


    【解决方案1】:

    是的,支持 REST API(控制器)和 GraphQL 完全没问题。

    如果您不考虑库,处理 GraphQL 请求仅意味着处理传入的 POST 到 /graphql

    如果需要,您可以编写处理这些 POST 的典型 ASP.NET Core 控制器。像 Hot Chocolate 这样的框架提供了像 .UseGraphQl() 这样的中间件,这使得配置更加方便,但从概念上讲,您可以将 .UseGraphQl() 视为添加一个仅处理 /graphql 路由的控制器。您的所有其他控制器将继续正常工作!

    【讨论】:

      【解决方案2】:

      有一种方法可以让您使用 hotchocolate 和模式拼接自动同时启动和运行两个 API。

      基本上,我遵循了 Ian webbington 提供的这个教程。 https://ian.bebbs.co.uk/posts/LessReSTMoreHotChocolate

      Ian 使用其 API 中的 swagger 模式来创建一个 graphql 模式,如果我们考虑一下,这可以节省我们的时间。它很容易实现,但是您仍然需要编写代码来公开 graphql 端点。

      这是我实现的,将我的所有 graphql 和其余 API 连接到一个 API 网关中。我正在分享我的自定义实现以在 hotchocolate (Graphql) 下运行 swagger 模式 (REST):

      using System;
      using HotChocolate;
      using HotChocolate.AspNetCore;
      using HotChocolate.AspNetCore.Playground;
      using HotChocolate.AspNetCore.Voyager;
      using HotChocolate.AspNetCore.Subscriptions;
      using HotChocolate.Stitching;
      using Microsoft.AspNetCore.Builder;
      using Microsoft.AspNetCore.Http;
      using Microsoft.Extensions.DependencyInjection;
      using SmartGateway.Api.Filters;
      using SmartGateway.Api.RestServices.SmartConfig;
      
      namespace SmartGateway.Api.Extensions
      {
          public static class GraphQlExtensions
          {
              public static IServiceCollection AddGraphQlApi(this IServiceCollection services)
              {
                  services.AddHttpClient("smartauth", (sp, client) =>
                  {
                      sp.SetUpContext(client); //GRAPHQL API
                      client.BaseAddress = new Uri(AppSettings.SmartServices.SmartAuth.Endpoint);
                  });
                  services.AddHttpClient("smartlog", (sp, client) =>
                  {
                      sp.SetUpContext(client); //GRAPHQL API
                      client.BaseAddress = new Uri(AppSettings.SmartServices.SmartLog.Endpoint);
                  });
                  services.AddHttpClient("smartway", (sp, client) =>
                  {
                      sp.SetUpContext(client); //GRAPHQL API
                      client.BaseAddress = new Uri(AppSettings.SmartServices.SmartWay.Endpoint);
                  });
      
                  services.AddHttpClient<ISmartConfigSession, SmartConfigSession>((sp, client) =>
                      {
                          sp.SetUpContext(client); //REST API
                          client.BaseAddress = new Uri(AppSettings.SmartServices.SmartConfig.Endpoint);
                      }
                  );
      
                  services.AddDataLoaderRegistry();
      
                  services.AddGraphQLSubscriptions();
      
                  services.AddStitchedSchema(builder => builder
                      .AddSchemaFromHttp("smartauth")
                      .AddSchemaFromHttp("smartlog")
                      .AddSchemaFromHttp("smartway")
                      .AddSchema(new NameString("smartconfig"), SmartConfigSchema.Build())
                      .AddSchemaConfiguration(c =>
                      {
                          c.RegisterExtendedScalarTypes();
                      }));
      
                  services.AddErrorFilter<GraphQLErrorFilter>();
      
                  return services;
              }
      
              public static IApplicationBuilder UseGraphQlApi(this IApplicationBuilder app)
              {
                  app.UseWebSockets();
                  app.UseGraphQL("/graphql");
                  app.UsePlayground(new PlaygroundOptions
                  {
                      Path = "/ui/playground",
                      QueryPath = "/graphql"
                  });
                  app.UseVoyager(new PathString("/graphql"), new PathString("/ui/voyager"));
      
                  return app;
              }
          }
      }
      

      设置 HttpContext 扩展:

      using System;
      using System.Net.Http;
      using System.Net.Http.Headers;
      using Microsoft.AspNetCore.Http;
      using Microsoft.Extensions.DependencyInjection;
      
      namespace SmartGateway.Api.Extensions
      {
          public static class HttpContextExtensions
          {
              public static void SetUpContext(this IServiceProvider servicesProvider, HttpClient httpClient)
              {
                  HttpContext context = servicesProvider.GetRequiredService<IHttpContextAccessor>().HttpContext;
      
                  if (context?.Request?.Headers?.ContainsKey("Authorization") ?? false)
                  {
                      httpClient.DefaultRequestHeaders.Authorization =
                          AuthenticationHeaderValue.Parse(context.Request.Headers["Authorization"].ToString());
                  }
              }
          }
      }
      

      您需要它来处理 HTTPClient 并将其传递给您的 swagger Sdk。

      using System.Net.Http;
      
      namespace SmartGateway.Api.RestServices.SmartConfig
      {
          public interface ISmartConfigSession
          {
              HttpClient GetHttpClient();
          }
      
          public class SmartConfigSession : ISmartConfigSession
          {
              private readonly HttpClient _httpClient;
      
              public SmartConfigSession(HttpClient httpClient)
              {
                  _httpClient = httpClient;
              }
      
              public HttpClient GetHttpClient()
              {
                  return _httpClient;
              }
          }
      }
      

      这是我的 graphql 架构:

      namespace SmartGateway.Api.RestServices.SmartConfig
      {
          public static class SmartConfigSchema
          {
              public static ISchema Build()
              {
                  return SchemaBuilder.New()
                      .AddQueryType<SmartConfigQueries>()
                      .AddMutationType<SmartConfigMutations>()
                      .ModifyOptions(o => o.RemoveUnreachableTypes = true)
                      .Create();
              }
          }
      
          public class SmartConfigMutations
          {
              private readonly ISmartConfigClient _client;
      
              public SmartConfigMutations(ISmartConfigSession session)
              {
                  _client = new SmartConfigClient(AppSettings.SmartServices.SmartConfig.Endpoint, session.GetHttpClient());
              }
      
              public UserConfigMutations UserConfig => new UserConfigMutations(_client);
          }
      }
      

      最后,这是您发布端点的方式:

      using System.Threading.Tasks;
      using SmartConfig.Sdk;
      
      namespace SmartGateway.Api.RestServices.SmartConfig.UserConfigOps
      {
          public class UserConfigMutations
          {
              private readonly ISmartConfigClient _client;
      
              public UserConfigMutations(ISmartConfigClient session)
              {
                  _client = session;
              }
      
              public async Task<UserConfig> CreateUserConfig(CreateUserConfigCommand createUserConfigInput)
              {
                  var result = await _client.CreateUserConfigAsync(createUserConfigInput);
                  return result.Response;
              }
      
              public async Task<UserConfig> UpdateUserConfig(UpdateUserConfigCommand updateUserConfigInput)
              {
                  var result = await _client.UpdateUserConfigAsync(updateUserConfigInput);
                  return result.Response;
              }
          }
      }
      

      更多关于热巧克力和模式拼接的文档在这里: https://hotchocolate.io/docs/stitching

      【讨论】:

        猜你喜欢
        • 2020-09-10
        • 2021-11-23
        • 2020-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-21
        • 2019-03-09
        相关资源
        最近更新 更多