-
-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for API browsers (Swagger, Redoc) (#591)
- Loading branch information
1 parent
79b78aa
commit 488e804
Showing
20 changed files
with
2,653 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using GenHTTP.Modules.ApiBrowsing.Common; | ||
|
||
namespace GenHTTP.Modules.ApiBrowsing; | ||
|
||
/// <summary> | ||
/// Provides graphical, JavaScript based web applications that render an Open API | ||
/// definition so that the API can be explored by users. | ||
/// </summary> | ||
public static class ApiBrowser | ||
{ | ||
|
||
/// <summary> | ||
/// Creates a handler that will provide a Swagger UI app. | ||
/// </summary> | ||
/// <returns>The newly created handler</returns> | ||
public static BrowserHandlerBuilder SwaggerUI() => new("Swagger", "Swagger UI"); | ||
|
||
/// <summary> | ||
/// Creates a handler that will provide a Redoc app. | ||
/// </summary> | ||
/// <returns>The newly created handler</returns> | ||
public static BrowserHandlerBuilder Redoc() => new("Redoc", "Redoc"); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
using Cottle; | ||
using GenHTTP.Api.Content; | ||
using GenHTTP.Api.Protocol; | ||
using GenHTTP.Modules.Basics; | ||
using GenHTTP.Modules.IO; | ||
using GenHTTP.Modules.Pages; | ||
using GenHTTP.Modules.Pages.Rendering; | ||
|
||
namespace GenHTTP.Modules.ApiBrowsing.Common; | ||
|
||
public sealed class BrowserHandler: IHandler | ||
{ | ||
|
||
#region Get-/Setters | ||
|
||
public IHandler StaticResources { get; } | ||
|
||
public TemplateRenderer Template { get; } | ||
|
||
public BrowserMetaData MetaData { get; } | ||
|
||
#endregion | ||
|
||
#region Initialization | ||
|
||
public BrowserHandler(string resourceRoot, BrowserMetaData metaData) | ||
{ | ||
StaticResources = Resources.From(ResourceTree.FromAssembly($"{resourceRoot}.Static")) | ||
.Build(); | ||
|
||
Template = Renderer.From(Resource.FromAssembly($"{resourceRoot}.Index.html").Build()); | ||
|
||
MetaData = metaData; | ||
} | ||
|
||
#endregion | ||
|
||
#region Functionality | ||
|
||
public ValueTask PrepareAsync() => ValueTask.CompletedTask; | ||
|
||
public async ValueTask<IResponse?> HandleAsync(IRequest request) | ||
{ | ||
if (!request.HasType(RequestMethod.Get, RequestMethod.Head)) | ||
{ | ||
throw new ProviderException(ResponseStatus.MethodNotAllowed, "Only GET requests are allowed by this handler", (b) => b.Header("Allow", "GET")); | ||
} | ||
|
||
if (request.Target.Ended) | ||
{ | ||
var config = new Dictionary<Value, Value> | ||
{ | ||
["title"] = MetaData.Title, | ||
["url"] = (MetaData.Url ?? "../openapi.json") | ||
}; | ||
|
||
var content = await Template.RenderAsync(config); | ||
|
||
return request.GetPage(content) | ||
.Build(); | ||
} | ||
|
||
if (request.Target.Current?.Value == "static") | ||
{ | ||
request.Target.Advance(); | ||
return await StaticResources.HandleAsync(request); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
#endregion | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using GenHTTP.Api.Content; | ||
|
||
namespace GenHTTP.Modules.ApiBrowsing.Common; | ||
|
||
public class BrowserHandlerBuilder(string resourceRoot, string title) : IHandlerBuilder<BrowserHandlerBuilder> | ||
{ | ||
private readonly List<IConcernBuilder> _Concerns = []; | ||
|
||
private string? _Url; | ||
|
||
private string _Title = title; | ||
|
||
/// <summary> | ||
/// Sets the URL of the Open API definition to be consumed (defaults to "../openapi.json"). | ||
/// Should be relative to avoid issues with CORS etc. | ||
/// </summary> | ||
/// <param name="url">The URL the application will fetch the Open API definition from</param> | ||
public BrowserHandlerBuilder Url(string url) | ||
{ | ||
_Url = url; | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Sets the title of the application that will be rendered by the browser (e.g. the title of the tab). | ||
/// </summary> | ||
/// <param name="title">The title of the application to be set</param> | ||
public BrowserHandlerBuilder Title(string title) | ||
{ | ||
_Title = title; | ||
return this; | ||
} | ||
|
||
public BrowserHandlerBuilder Add(IConcernBuilder concern) | ||
{ | ||
_Concerns.Add(concern); | ||
return this; | ||
} | ||
|
||
public IHandler Build() | ||
{ | ||
var meta = new BrowserMetaData(_Url, _Title); | ||
|
||
return Concerns.Chain(_Concerns, new BrowserHandler(resourceRoot, meta)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
namespace GenHTTP.Modules.ApiBrowsing.Common; | ||
|
||
public record BrowserMetaData(string? Url, string Title); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using GenHTTP.Modules.ApiBrowsing.Common; | ||
using GenHTTP.Modules.Layouting.Provider; | ||
|
||
namespace GenHTTP.Modules.ApiBrowsing; | ||
|
||
public static class Extensions | ||
{ | ||
|
||
/// <summary> | ||
/// Creates a Swagger UI application and registers it at the layout. | ||
/// </summary> | ||
/// <param name="layout">The layout to add the application to</param> | ||
/// <param name="segment">The path to make the application available from (defaults to "/swagger/")</param> | ||
/// <param name="url">The URL of the Open API definition to be rendered (defaults to "../openapi.json")</param> | ||
/// <param name="title">The title of the rendered application</param> | ||
/// <returns>The layout once again (builder pattern)</returns> | ||
/// <remarks> | ||
/// There is no auto-detection of Open API definitions provided by the server | ||
/// so the URL provided needs to point to the correct definition to be consumed. | ||
/// Use relative paths to avoid issues with CORS, proxies etc. | ||
/// </remarks> | ||
public static LayoutBuilder AddSwaggerUI(this LayoutBuilder layout, string segment = "swagger", string? url = null, string? title = null) | ||
=> AddBrowser(layout, ApiBrowser.SwaggerUI(), segment, url, title); | ||
|
||
/// <summary> | ||
/// Creates a Redoc application and registers it at the layout. | ||
/// </summary> | ||
/// <param name="layout">The layout to add the application to</param> | ||
/// <param name="segment">The path to make the application available from (defaults to "/redoc/")</param> | ||
/// <param name="url">The URL of the Open API definition to be rendered (defaults to "../openapi.json")</param> | ||
/// <param name="title">The title of the rendered application</param> | ||
/// <returns>The layout once again (builder pattern)</returns> | ||
/// <remarks> | ||
/// There is no auto-detection of Open API definitions provided by the server | ||
/// so the URL provided needs to point to the correct definition to be consumed. | ||
/// Use relative paths to avoid issues with CORS, proxies etc. | ||
/// </remarks> | ||
public static LayoutBuilder AddRedoc(this LayoutBuilder layout, string segment = "redoc", string? url = null, string? title = null) | ||
=> AddBrowser(layout, ApiBrowser.Redoc(), segment, url, title); | ||
|
||
private static LayoutBuilder AddBrowser(this LayoutBuilder layout, BrowserHandlerBuilder builder, string segment, string? url, string? title) | ||
{ | ||
if (url != null) | ||
{ | ||
builder.Url(url); | ||
} | ||
|
||
if (title != null) | ||
{ | ||
builder.Title(title); | ||
} | ||
|
||
return layout.Add(segment, builder); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
|
||
<TargetFrameworks>net8.0;net9.0</TargetFrameworks> | ||
|
||
<LangVersion>13.0</LangVersion> | ||
<Nullable>enable</Nullable> | ||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
|
||
<AssemblyVersion>9.4.0.0</AssemblyVersion> | ||
<FileVersion>9.4.0.0</FileVersion> | ||
<Version>9.4.0</Version> | ||
|
||
<Authors>Andreas Nägeli</Authors> | ||
<Company/> | ||
|
||
<PackageLicenseFile>LICENSE</PackageLicenseFile> | ||
<PackageProjectUrl>https://genhttp.org/</PackageProjectUrl> | ||
|
||
<Description>Serves API browsers such as Swagger UI.</Description> | ||
<PackageTags>HTTP Webserver C# Module Swagger UI API Browser Browsing</PackageTags> | ||
|
||
<PublishRepositoryUrl>true</PublishRepositoryUrl> | ||
<IncludeSymbols>true</IncludeSymbols> | ||
<SymbolPackageFormat>snupkg</SymbolPackageFormat> | ||
|
||
<GenerateDocumentationFile>true</GenerateDocumentationFile> | ||
<NoWarn>CS1591,CS1587,CS1572,CS1573</NoWarn> | ||
|
||
<PackageIcon>icon.png</PackageIcon> | ||
|
||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
|
||
<None Include="..\..\LICENSE" Pack="true" PackagePath="\"/> | ||
<None Include="..\..\Resources\icon.png" Pack="true" PackagePath="\"/> | ||
|
||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
|
||
<ProjectReference Include="..\..\API\GenHTTP.Api.csproj"/> | ||
|
||
<ProjectReference Include="..\IO\GenHTTP.Modules.IO.csproj" /> | ||
|
||
<ProjectReference Include="..\Layouting\GenHTTP.Modules.Layouting.csproj"/> | ||
|
||
<ProjectReference Include="..\Pages\GenHTTP.Modules.Pages.csproj" /> | ||
|
||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/> | ||
|
||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<None Remove="Resources\Static\swagger-ui.css" /> | ||
<None Remove="Resources\Static\swagger-ui-bundle.js" /> | ||
<None Remove="Resources\Static\swagger-ui-standalone-preset.js" /> | ||
<None Remove="Resources\Templates\Index.html" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<EmbeddedResource Include="Redoc\Index.html" /> | ||
<EmbeddedResource Include="Redoc\Static\redoc-standalone.js" /> | ||
<EmbeddedResource Include="Redoc\Static\roboto.css" /> | ||
<EmbeddedResource Include="Swagger\Index.html" /> | ||
<EmbeddedResource Include="Swagger\Static\swagger-ui-bundle.js" /> | ||
<EmbeddedResource Include="Swagger\Static\swagger-ui.css" /> | ||
<None Remove="Redoc\Resources\Index.html" /> | ||
<None Remove="Redoc\Resources\Static\redoc.standalone.js" /> | ||
<None Remove="Redoc\Resources\Static\roboto.css" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>{title}</title> | ||
<meta charset="utf-8"/> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<link href="./static/roboto.css" rel="stylesheet"> | ||
|
||
<style> | ||
body \{ | ||
margin: 0; | ||
padding: 0; | ||
\} | ||
</style> | ||
</head> | ||
<body> | ||
<redoc spec-url='{url}'></redoc> | ||
<script src="./static/redoc-standalone.js"> </script> | ||
</body> | ||
</html> |
1,826 changes: 1,826 additions & 0 deletions
1,826
Modules/ApiBrowsing/Redoc/Static/redoc-standalone.js
Large diffs are not rendered by default.
Oops, something went wrong.
Oops, something went wrong.