Skip to content

Commit 24419f0

Browse files
authored
UI customization (#652)
1 parent 70497ee commit 24419f0

22 files changed

+136
-43
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project>
22

33
<PropertyGroup>
4-
<VersionPrefix>5.0.2-preview</VersionPrefix>
4+
<VersionPrefix>5.1.0-preview</VersionPrefix>
55
<LangVersion>latest</LangVersion>
66
<PackageLicenseExpression>MIT</PackageLicenseExpression>
77
<PackageIcon>logo.64x64.png</PackageIcon>

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ For integration of GraphQL.NET validation subsystem into ASP.NET Core:
9393

9494
#### 4. UI integration
9595

96-
For the UI middleware/s:
96+
For the UI middlewares:
9797

9898
```
9999
> dotnet add package GraphQL.Server.Ui.Altair
@@ -102,6 +102,18 @@ For the UI middleware/s:
102102
> dotnet add package GraphQL.Server.Ui.Voyager
103103
```
104104

105+
```c#
106+
public void Configure(IApplicationBuilder app)
107+
{
108+
app.[Use|Map]GraphQLAltair();
109+
app.[Use|Map]GraphQLGraphiQL();
110+
app.[Use|Map]GraphQLPlayground();
111+
app.[Use|Map]GraphQLVoyager();
112+
}
113+
```
114+
115+
Also each middleware accepts options to configure its behavior and UI.
116+
105117
## Configure
106118

107119
See the sample project's [Startup.cs](samples/Samples.Server/Startup.cs) or [StartupWithRouting.cs](samples/Samples.Server/StartupWithRouting.cs) for full details.

src/Ui.Altair/AltairMiddleware.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class AltairMiddleware
1616
/// <summary>
1717
/// The page model used to render Altair.
1818
/// </summary>
19-
private AltairPageModel _pageModel;
19+
private AltairPageModel? _pageModel;
2020

2121
/// <summary>
2222
/// Create a new <see cref="AltairMiddleware"/>
@@ -41,9 +41,7 @@ public Task Invoke(HttpContext httpContext)
4141
httpContext.Response.ContentType = "text/html";
4242
httpContext.Response.StatusCode = 200;
4343

44-
// Initialize page model if null
45-
if (_pageModel == null)
46-
_pageModel = new AltairPageModel(_options);
44+
_pageModel ??= new AltairPageModel(_options);
4745

4846
byte[] data = Encoding.UTF8.GetBytes(_pageModel.Render());
4947
return httpContext.Response.Body.WriteAsync(data, 0, data.Length);

src/Ui.Altair/AltairOptions.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
using System;
12
using System.Collections.Generic;
3+
using System.IO;
24
using Microsoft.AspNetCore.Http;
35

46
namespace GraphQL.Server.Ui.Altair
@@ -21,6 +23,17 @@ public class AltairOptions
2123
/// <summary>
2224
/// Altair headers configuration.
2325
/// </summary>
24-
public Dictionary<string, string> Headers { get; set; }
26+
public Dictionary<string, string>? Headers { get; set; }
27+
28+
/// <summary>
29+
/// Gets or sets a Stream function for retrieving the Altair GraphQL UI page.
30+
/// </summary>
31+
public Func<AltairOptions, Stream> IndexStream { get; set; } = _ => typeof(AltairOptions).Assembly
32+
.GetManifestResourceStream("GraphQL.Server.Ui.Altair.Internal.altair.cshtml")!;
33+
34+
/// <summary>
35+
/// Gets or sets a delegate that is called after all transformations of the Altair GraphQL UI page.
36+
/// </summary>
37+
public Func<AltairOptions, string, string> PostConfigure { get; set; } = (options, result) => result;
2538
}
2639
}

src/Ui.Altair/Internal/AltairPageModel.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Collections.Generic;
12
using System.IO;
23
using System.Text;
34
using System.Text.Json;
@@ -7,7 +8,7 @@ namespace GraphQL.Server.Ui.Altair.Internal
78
// https://docs.microsoft.com/en-us/aspnet/core/mvc/razor-pages/?tabs=netcore-cli
89
internal sealed class AltairPageModel
910
{
10-
private string _altairCSHtml;
11+
private string? _altairCSHtml;
1112

1213
private readonly AltairOptions _options;
1314

@@ -20,15 +21,27 @@ public string Render()
2021
{
2122
if (_altairCSHtml == null)
2223
{
23-
using var manifestResourceStream = typeof(AltairPageModel).Assembly.GetManifestResourceStream("GraphQL.Server.Ui.Altair.Internal.altair.cshtml");
24+
using var manifestResourceStream = _options.IndexStream(_options);
2425
using var streamReader = new StreamReader(manifestResourceStream);
2526

27+
var headers = new Dictionary<string, object>
28+
{
29+
["Accept"] = "application/json",
30+
["Content-Type"] = "application/json",
31+
};
32+
33+
if (_options.Headers?.Count > 0)
34+
{
35+
foreach (var item in _options.Headers)
36+
headers[item.Key] = item.Value;
37+
}
38+
2639
var builder = new StringBuilder(streamReader.ReadToEnd())
2740
.Replace("@Model.GraphQLEndPoint", _options.GraphQLEndPoint)
2841
.Replace("@Model.SubscriptionsEndPoint", _options.SubscriptionsEndPoint)
29-
.Replace("@Model.Headers", JsonSerializer.Serialize<object>(_options.Headers));
42+
.Replace("@Model.Headers", JsonSerializer.Serialize<object>(headers));
3043

31-
_altairCSHtml = builder.ToString();
44+
_altairCSHtml = _options.PostConfigure(_options, builder.ToString());
3245
}
3346

3447
return _altairCSHtml;

src/Ui.Altair/Ui.Altair.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<TargetFrameworks>net5;netcoreapp3.1</TargetFrameworks>
55
<Description>GraphQL Altair integration for ASP.NET Core</Description>
66
<PackageTags>Altair;GraphQL</PackageTags>
7+
<Nullable>enable</Nullable>
78
</PropertyGroup>
89

910
<ItemGroup>

src/Ui.GraphiQL/GraphiQLMiddleware.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class GraphiQLMiddleware
1616
/// <summary>
1717
/// The page model used to render GraphiQL.
1818
/// </summary>
19-
private GraphiQLPageModel _pageModel;
19+
private GraphiQLPageModel? _pageModel;
2020

2121
/// <summary>
2222
/// Create a new <see cref="GraphiQLMiddleware"/>
@@ -42,9 +42,7 @@ public Task Invoke(HttpContext httpContext)
4242
httpContext.Response.ContentType = "text/html";
4343
httpContext.Response.StatusCode = 200;
4444

45-
// Initialize page model if null
46-
if (_pageModel == null)
47-
_pageModel = new GraphiQLPageModel(_options);
45+
_pageModel ??= new GraphiQLPageModel(_options);
4846

4947
byte[] data = Encoding.UTF8.GetBytes(_pageModel.Render());
5048
return httpContext.Response.Body.WriteAsync(data, 0, data.Length);

src/Ui.GraphiQL/GraphiQLOptions.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
using System;
12
using System.Collections.Generic;
3+
using System.IO;
24
using Microsoft.AspNetCore.Http;
35

46
namespace GraphQL.Server.Ui.GraphiQL
@@ -21,6 +23,17 @@ public class GraphiQLOptions
2123
/// <summary>
2224
/// HTTP headers with which the GraphiQL will be initialized.
2325
/// </summary>
24-
public Dictionary<string, string> Headers { get; set; }
26+
public Dictionary<string, string>? Headers { get; set; }
27+
28+
/// <summary>
29+
/// Gets or sets a Stream function for retrieving the GraphiQL UI page.
30+
/// </summary>
31+
public Func<GraphiQLOptions, Stream> IndexStream { get; set; } = _ => typeof(GraphiQLOptions).Assembly
32+
.GetManifestResourceStream("GraphQL.Server.Ui.GraphiQL.Internal.graphiql.cshtml")!;
33+
34+
/// <summary>
35+
/// Gets or sets a delegate that is called after all transformations of the GraphiQL UI page.
36+
/// </summary>
37+
public Func<GraphiQLOptions, string, string> PostConfigure { get; set; } = (options, result) => result;
2538
}
2639
}

src/Ui.GraphiQL/Internal/GraphiQLPageModel.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace GraphQL.Server.Ui.GraphiQL.Internal
88
// https://docs.microsoft.com/en-us/aspnet/core/mvc/razor-pages/?tabs=netcore-cli
99
internal sealed class GraphiQLPageModel
1010
{
11-
private string _graphiQLCSHtml;
11+
private string? _graphiQLCSHtml;
1212

1313
private readonly GraphiQLOptions _options;
1414

@@ -21,7 +21,7 @@ public string Render()
2121
{
2222
if (_graphiQLCSHtml == null)
2323
{
24-
using var manifestResourceStream = typeof(GraphiQLPageModel).Assembly.GetManifestResourceStream("GraphQL.Server.Ui.GraphiQL.Internal.graphiql.cshtml");
24+
using var manifestResourceStream = _options.IndexStream(_options);
2525
using var streamReader = new StreamReader(manifestResourceStream);
2626

2727
var headers = new Dictionary<string, object>
@@ -41,7 +41,7 @@ public string Render()
4141
.Replace("@Model.SubscriptionsEndPoint", _options.SubscriptionsEndPoint)
4242
.Replace("@Model.Headers", JsonSerializer.Serialize<object>(headers));
4343

44-
_graphiQLCSHtml = builder.ToString();
44+
_graphiQLCSHtml = _options.PostConfigure(_options, builder.ToString());
4545
}
4646

4747
return _graphiQLCSHtml;

src/Ui.GraphiQL/Ui.GraphiQL.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<TargetFrameworks>net5;netcoreapp3.1</TargetFrameworks>
55
<Description>GraphiQL integration for ASP.NET Core</Description>
66
<PackageTags>GraphiQL;GraphQL</PackageTags>
7+
<Nullable>enable</Nullable>
78
</PropertyGroup>
89

910
<ItemGroup>

0 commit comments

Comments
 (0)