There is a way you can automate having both APIs up and running at the same time using hotchocolate and schema stitching.
Basically I followed this tutorial offered by Ian webbington.
https://ian.bebbs.co.uk/posts/LessReSTMoreHotChocolate
Ian uses swagger schema from its API to create a graphql schema which saves us time if we think about it. It's easy to implement, however you still need to code to expose graphql endpoints.
This is what I implemented to connect all my graphql and rest APIs in just one API gateway. I'm sharing my custom implementation to have swagger schema (REST) running under hotchocolate (Graphql):
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;
}
}
}
Set up HttpContext extension:
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());
}
}
}
}
You need this to handle and pass the HTTPClient to your 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;
}
}
}
This is my graphql Schema:
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);
}
}
Finally, this is how you publish endpoints:
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;
}
}
}
More documentation about hotchocolate and schema stitching here:
https://hotchocolate.io/docs/stitching