diff --git a/README.md b/README.md
index 7614e4b3..d1212618 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ Provides the following packages:
| GraphQL.Server.Transports.WebSockets | [](https://www.nuget.org/packages/GraphQL.Server.Transports.WebSockets/) |
| GraphQL.Server.Ui.Playground | [](https://www.nuget.org/packages/GraphQL.Server.Ui.Playground/) |
| GraphQL.Server.Ui.GraphiQL | [](https://www.nuget.org/packages/GraphQL.Server.Ui.GraphiQL/) |
+| GraphQL.Server.Ui.Altair | [](https://www.nuget.org/packages/GraphQL.Server.Ui.Altair/) |
| GraphQL.Server.Ui.Voyager | [](https://www.nuget.org/packages/GraphQL.Server.Ui.Voyager/) |
| GraphQL.Server.Authorization.AspNetCore | [](https://www.nuget.org/packages/GraphQL.Server.Authorization.AspNetCore/) |
@@ -32,6 +33,7 @@ For the WebSocket subscription protocol (depends on above) middleware:
For the UI middleware/s:
>`dotnet add package GraphQL.Server.Ui.GraphiQL`
>`dotnet add package GraphQL.Server.Ui.Playground`
+>`dotnet add package GraphQL.Server.Ui.Altair`
>`dotnet add package GraphQL.Server.Ui.Voyager`
@@ -68,6 +70,9 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
// use graphql-playground middleware at default url /ui/playground
app.UseGraphQLPlayground(new GraphQLPlaygroundOptions());
+
+ // use altair middleware at default url /ui/altair
+ app.UseGraphQLAltair(new GraphQLAltairOptions());
// use voyager middleware at default url /ui/voyager
app.UseGraphQLVoyager(new GraphQLVoyagerOptions());
diff --git a/build.cake b/build.cake
index b389c426..454dfca8 100644
--- a/build.cake
+++ b/build.cake
@@ -13,6 +13,7 @@ var projectFiles = new [] {
"./src/Transports.Subscriptions.WebSockets/Transports.Subscriptions.WebSockets.csproj",
"./src/Ui.Playground/Ui.Playground.csproj",
"./src/Ui.GraphiQL/Ui.GraphiQL.csproj",
+ "./src/Ui.Altair/Ui.Altair.csproj",
"./src/Ui.Voyager/Ui.Voyager.csproj",
"./src/Authorization.AspNetCore/Authorization.AspNetCore.csproj"
};
diff --git a/samples/Samples.Server/Samples.Server.csproj b/samples/Samples.Server/Samples.Server.csproj
index 5555fb77..2db433bd 100644
--- a/samples/Samples.Server/Samples.Server.csproj
+++ b/samples/Samples.Server/Samples.Server.csproj
@@ -22,6 +22,7 @@
+
diff --git a/samples/Samples.Server/Startup.cs b/samples/Samples.Server/Startup.cs
index f082af32..294b5e57 100644
--- a/samples/Samples.Server/Startup.cs
+++ b/samples/Samples.Server/Startup.cs
@@ -2,6 +2,7 @@
using GraphQL.Server;
using GraphQL.Server.Ui.GraphiQL;
using GraphQL.Server.Ui.Playground;
+using GraphQL.Server.Ui.Altair;
using GraphQL.Server.Ui.Voyager;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@@ -98,6 +99,16 @@ public void Configure(IApplicationBuilder app)
GraphQLEndPoint = "/graphql",
});
+ app.UseGraphQLAltair(new GraphQLAltairOptions
+ {
+ Path = "/ui/altair",
+ GraphQLEndPoint = "/graphql",
+ Headers = new Dictionary
+ {
+ ["X-api-token"] = "130fh9823bd023hd892d0j238dh",
+ }
+ });
+
app.UseGraphQLVoyager(new GraphQLVoyagerOptions
{
Path = "/ui/voyager",
diff --git a/src/Ui.Altair/AltairExtensions.cs b/src/Ui.Altair/AltairExtensions.cs
new file mode 100644
index 00000000..2d121b97
--- /dev/null
+++ b/src/Ui.Altair/AltairExtensions.cs
@@ -0,0 +1,19 @@
+using GraphQL.Server.Ui.Altair;
+
+namespace Microsoft.AspNetCore.Builder
+{
+ ///
+ /// Extension methods for
+ ///
+ public static class AltairExtensions
+ {
+ /// Adds middleware for Altair GraphQL using the specified options.
+ /// to configure an application's request pipeline.
+ /// Options to customize . If not set, then the default values will be used.
+ /// The reference to provided instance.
+ public static IApplicationBuilder UseGraphQLAltair(this IApplicationBuilder app, GraphQLAltairOptions options = null)
+ {
+ return app.UseMiddleware(options ?? new GraphQLAltairOptions());
+ }
+ }
+}
diff --git a/src/Ui.Altair/AltairMiddleware.cs b/src/Ui.Altair/AltairMiddleware.cs
new file mode 100644
index 00000000..efba6b5e
--- /dev/null
+++ b/src/Ui.Altair/AltairMiddleware.cs
@@ -0,0 +1,68 @@
+using GraphQL.Server.Ui.Altair.Internal;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GraphQL.Server.Ui.Altair
+{
+ ///
+ /// A middleware for Altair GraphQL
+ ///
+ public class AltairMiddleware
+ {
+ private readonly GraphQLAltairOptions _options;
+
+ ///
+ /// The next middleware
+ ///
+ private readonly RequestDelegate _nextMiddleware;
+
+ ///
+ /// The page model used to render Altair
+ ///
+ private AltairPageModel _pageModel;
+
+ ///
+ /// Create a new
+ ///
+ /// The next middleware
+ /// Options to customize middleware
+ public AltairMiddleware(RequestDelegate nextMiddleware, GraphQLAltairOptions options)
+ {
+ _nextMiddleware = nextMiddleware ?? throw new ArgumentNullException(nameof(nextMiddleware));
+ _options = options ?? throw new ArgumentNullException(nameof(options));
+ }
+
+ ///
+ /// Try to execute the logic of the middleware
+ ///
+ /// The HttpContext
+ public Task Invoke(HttpContext httpContext)
+ {
+ if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));
+
+ return IsAltairRequest(httpContext.Request)
+ ? InvokeAltair(httpContext.Response)
+ : _nextMiddleware(httpContext);
+ }
+
+ private bool IsAltairRequest(HttpRequest httpRequest)
+ {
+ return HttpMethods.IsGet(httpRequest.Method) && httpRequest.Path.StartsWithSegments(_options.Path);
+ }
+
+ private Task InvokeAltair(HttpResponse httpResponse)
+ {
+ httpResponse.ContentType = "text/html";
+ httpResponse.StatusCode = 200;
+
+ // Initialize page model if null
+ if (_pageModel == null)
+ _pageModel = new AltairPageModel(_options);
+
+ var data = Encoding.UTF8.GetBytes(_pageModel.Render());
+ return httpResponse.Body.WriteAsync(data, 0, data.Length);
+ }
+ }
+}
diff --git a/src/Ui.Altair/GraphQLAltairOptions.cs b/src/Ui.Altair/GraphQLAltairOptions.cs
new file mode 100644
index 00000000..36be60c6
--- /dev/null
+++ b/src/Ui.Altair/GraphQLAltairOptions.cs
@@ -0,0 +1,26 @@
+using Microsoft.AspNetCore.Http;
+using System.Collections.Generic;
+
+namespace GraphQL.Server.Ui.Altair
+{
+ ///
+ /// Options to customize
+ ///
+ public class GraphQLAltairOptions
+ {
+ ///
+ /// The Altair GraphQL EndPoint to listen
+ ///
+ public PathString Path { get; set; } = "/ui/altair";
+
+ ///
+ /// The GraphQL EndPoint
+ ///
+ public PathString GraphQLEndPoint { get; set; } = "/graphql";
+
+ ///
+ /// Altair Headers Config
+ ///
+ public Dictionary Headers { get; set; }
+ }
+}
diff --git a/src/Ui.Altair/Internal/AltairPageModel.cs b/src/Ui.Altair/Internal/AltairPageModel.cs
new file mode 100644
index 00000000..b4493a17
--- /dev/null
+++ b/src/Ui.Altair/Internal/AltairPageModel.cs
@@ -0,0 +1,40 @@
+using Newtonsoft.Json;
+using System.IO;
+using System.Text;
+
+namespace GraphQL.Server.Ui.Altair.Internal
+{
+ // https://docs.microsoft.com/en-us/aspnet/core/mvc/razor-pages/?tabs=netcore-cli
+ internal class AltairPageModel
+ {
+ private string _altairCSHtml;
+
+ private readonly GraphQLAltairOptions _options;
+
+ public AltairPageModel(GraphQLAltairOptions options)
+ {
+ _options = options;
+ }
+
+ public string Render()
+ {
+ if (_altairCSHtml == null)
+ {
+ using (var manifestResourceStream = typeof(AltairPageModel).Assembly.GetManifestResourceStream("GraphQL.Server.Ui.Altair.Internal.altair.cshtml"))
+ {
+ using (var streamReader = new StreamReader(manifestResourceStream))
+ {
+ var builder = new StringBuilder(streamReader.ReadToEnd());
+
+ builder.Replace("@Model.GraphQLEndPoint", _options.GraphQLEndPoint);
+ builder.Replace("@Model.AltairHeaders", JsonConvert.SerializeObject(_options.Headers));
+
+ _altairCSHtml = builder.ToString();
+ }
+ }
+ }
+
+ return _altairCSHtml;
+ }
+ }
+}
diff --git a/src/Ui.Altair/Internal/altair.cshtml b/src/Ui.Altair/Internal/altair.cshtml
new file mode 100644
index 00000000..7ce4624f
--- /dev/null
+++ b/src/Ui.Altair/Internal/altair.cshtml
@@ -0,0 +1,51 @@
+
+
+
+
+
+ Altair
+
+
+
+
+
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ui.Altair/Ui.Altair.csproj b/src/Ui.Altair/Ui.Altair.csproj
new file mode 100644
index 00000000..8b232b70
--- /dev/null
+++ b/src/Ui.Altair/Ui.Altair.csproj
@@ -0,0 +1,28 @@
+
+
+
+ netcoreapp3.0;netstandard2.0
+ GraphQL.Server.Ui.Altair
+ GraphQL.Server.Ui.Altair
+ Altair GraphQL extension
+ Altair GraphQL
+ GraphQL.Server.Ui.Altair
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+