-
Notifications
You must be signed in to change notification settings - Fork 33
Add OpenAPI Documentation Extension for HTTP Workflow Triggers #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
9a9c5db
Add OpenAPI functionality for HTTP triggers in Elsa workflows
933031e
Refactor HTTP OpenAPI functionality: streamline service registration,β¦
15d5ea8
Refactor HTTP OpenAPI extension methods: update method signatures andβ¦
889c8f3
Update src/modules/http/Elsa.Http.OpenApi/Services/WorkflowEndpointExβ¦
sfmskywalker File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
15 changes: 15 additions & 0 deletions
15
src/modules/http/Elsa.Http.OpenApi/Contracts/IElsaVersionProvider.cs
This file contains hidden or 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,15 @@ | ||
| using System.Reflection; | ||
|
|
||
| namespace Elsa.Http.OpenApi.Contracts; | ||
|
|
||
| /// <summary> | ||
| /// Service for retrieving Elsa package version information. | ||
| /// </summary> | ||
| public interface IElsaVersionProvider | ||
| { | ||
| /// <summary> | ||
| /// Gets the Elsa package version. | ||
| /// </summary> | ||
| /// <returns>The package version string.</returns> | ||
| string GetVersion(); | ||
| } |
16 changes: 16 additions & 0 deletions
16
src/modules/http/Elsa.Http.OpenApi/Contracts/IOpenApiGenerator.cs
This file contains hidden or 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,16 @@ | ||
| using Elsa.Http.OpenApi.Models; | ||
|
|
||
| namespace Elsa.Http.OpenApi.Contracts; | ||
|
|
||
| /// <summary> | ||
| /// Contract for generating OpenAPI JSON documentation. | ||
| /// </summary> | ||
| public interface IOpenApiGenerator | ||
| { | ||
| /// <summary> | ||
| /// Generates OpenAPI JSON documentation from a list of endpoint definitions. | ||
| /// </summary> | ||
| /// <param name="endpoints">The list of endpoint definitions.</param> | ||
| /// <returns>OpenAPI JSON string.</returns> | ||
| string GenerateOpenApiJson(List<EndpointDefinition> endpoints); | ||
| } |
16 changes: 16 additions & 0 deletions
16
src/modules/http/Elsa.Http.OpenApi/Contracts/IWorkflowEndpointExtractor.cs
This file contains hidden or 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,16 @@ | ||
| using Elsa.Http.OpenApi.Models; | ||
|
|
||
| namespace Elsa.Http.OpenApi.Contracts; | ||
|
|
||
| /// <summary> | ||
| /// Contract for extracting workflow HTTP endpoints for OpenAPI documentation. | ||
| /// </summary> | ||
| public interface IWorkflowEndpointExtractor | ||
| { | ||
| /// <summary> | ||
| /// Extracts all HTTP endpoints from workflows. | ||
| /// </summary> | ||
| /// <param name="cancellationToken">The cancellation token.</param> | ||
| /// <returns>A list of endpoint definitions.</returns> | ||
| Task<List<EndpointDefinition>> ExtractEndpointsAsync(CancellationToken cancellationToken = default); | ||
| } |
37 changes: 37 additions & 0 deletions
37
src/modules/http/Elsa.Http.OpenApi/Elsa.Http.OpenApi.csproj
This file contains hidden or 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,37 @@ | ||
| <Project Sdk="Microsoft.NET.Sdk"> | ||
|
|
||
| <PropertyGroup> | ||
| <Description> | ||
| Provides OpenAPI functionality for HTTP triggers in Elsa workflows. | ||
| </Description> | ||
| <PackageTags>elsa extension module, http, openapi</PackageTags> | ||
| </PropertyGroup> | ||
|
|
||
| <ItemGroup> | ||
| <PackageReference Include="Microsoft.Extensions.DependencyInjection" /> | ||
| <PackageReference Include="Microsoft.Extensions.Http" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup Label="Elsa" Condition="'$(UseProjectReferences)' != 'true'"> | ||
| <PackageReference Include="Elsa.Workflows.Runtime" /> | ||
| <PackageReference Include="Elsa.Workflows.Management" /> | ||
| <PackageReference Include="Elsa.Http" /> | ||
| <PackageReference Include="Elsa.Common" /> | ||
| <PackageReference Include="Elsa.Scheduling" /> | ||
| <PackageReference Include="Elsa.Api.Common" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup Label="Elsa" Condition="'$(UseProjectReferences)' == 'true'"> | ||
| <ProjectReference Include="..\..\..\..\..\elsa-core\src\modules\Elsa.Workflows.Runtime\Elsa.Workflows.Runtime.csproj" /> | ||
| <ProjectReference Include="..\..\..\..\..\elsa-core\src\modules\Elsa.Workflows.Management\Elsa.Workflows.Management.csproj" /> | ||
| <ProjectReference Include="..\..\..\..\..\elsa-core\src\modules\Elsa.Http\Elsa.Http.csproj" /> | ||
| <ProjectReference Include="..\..\..\..\..\elsa-core\src\common\Elsa.Common\Elsa.Common.csproj" /> | ||
| <ProjectReference Include="..\..\..\..\..\elsa-core\src\modules\Elsa.Scheduling\Elsa.Scheduling.csproj" /> | ||
| <ProjectReference Include="..\..\..\..\..\elsa-core\src\common\Elsa.Api.Common\Elsa.Api.Common.csproj" /> | ||
| </ItemGroup> | ||
|
|
||
| <ItemGroup> | ||
| <None Remove="README.md" /> | ||
| </ItemGroup> | ||
|
|
||
| </Project> |
50 changes: 50 additions & 0 deletions
50
src/modules/http/Elsa.Http.OpenApi/Extensions/EndpointRouteBuilderExtensions.cs
This file contains hidden or 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,50 @@ | ||
| using Elsa.Http.OpenApi.Contracts; | ||
| using Elsa.Http.OpenApi.Services; | ||
| using Microsoft.AspNetCore.Builder; | ||
| using Microsoft.AspNetCore.Http; | ||
| using Microsoft.AspNetCore.Mvc; | ||
| using Microsoft.AspNetCore.Routing; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
|
|
||
| namespace Elsa.Http.OpenApi.Extensions; | ||
|
|
||
| /// <summary> | ||
| /// Extension methods for mapping OpenAPI endpoints. | ||
| /// </summary> | ||
| public static class EndpointRouteBuilderExtensions | ||
| { | ||
| /// <summary> | ||
| /// Maps OpenAPI endpoints for workflow documentation. | ||
| /// </summary> | ||
| /// <param name="app">The endpoint route builder.</param> | ||
| /// <returns>The endpoint route builder for chaining.</returns> | ||
| public static IEndpointRouteBuilder MapWorkflowOpenApi(this IEndpointRouteBuilder app) | ||
| { | ||
| // OpenAPI JSON endpoint | ||
| app.MapGet("/openapi.json", async ([FromServices] IWorkflowEndpointExtractor extractor, [FromServices] IOpenApiGenerator generator) => | ||
| { | ||
| var endpoints = await extractor.ExtractEndpointsAsync(); | ||
| var openApiJson = generator.GenerateOpenApiJson(endpoints); | ||
| return Results.Content(openApiJson, "application/json"); | ||
| }); | ||
|
|
||
| // ReDoc UI endpoint | ||
| app.MapGet("/documentation", () => | ||
| { | ||
| var html = @" | ||
| <!DOCTYPE html> | ||
| <html> | ||
| <head> | ||
| <title>API Documentation</title> | ||
| </head> | ||
| <body> | ||
| <redoc spec-url=""/openapi.json""></redoc> | ||
| <script src=""https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js""> </script> | ||
| </body> | ||
| </html>"; | ||
| return Results.Content(html, "text/html"); | ||
| }); | ||
|
|
||
| return app; | ||
| } | ||
| } | ||
22 changes: 22 additions & 0 deletions
22
src/modules/http/Elsa.Http.OpenApi/Extensions/ModuleExtensions.cs
This file contains hidden or 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,22 @@ | ||
| using Elsa.Extensions; | ||
| using Elsa.Features.Services; | ||
| using Elsa.Http.Features; | ||
| using Elsa.Http.OpenApi.Features; | ||
|
|
||
| // ReSharper disable once CheckNamespace | ||
| namespace Elsa.Extensions; | ||
|
|
||
| /// <summary> | ||
| /// Provides extensions to install the HTTP OpenAPI feature. | ||
| /// </summary> | ||
| public static class ModuleExtensions | ||
| { | ||
| /// <summary> | ||
| /// Install the <see cref="HttpOpenApiFeature"/> feature as part of the HTTP feature configuration. | ||
| /// </summary> | ||
| public static HttpFeature UseOpenApi(this HttpFeature feature, Action<HttpOpenApiFeature>? configure = default) | ||
| { | ||
| feature.Module.Configure(configure); | ||
| return feature; | ||
| } | ||
| } |
25 changes: 25 additions & 0 deletions
25
src/modules/http/Elsa.Http.OpenApi/Extensions/ServiceCollectionExtensions.cs
This file contains hidden or 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,25 @@ | ||
| using Elsa.Http.OpenApi.Contracts; | ||
| using Elsa.Http.OpenApi.Services; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
|
|
||
| namespace Elsa.Http.OpenApi.Extensions; | ||
|
|
||
| /// <summary> | ||
| /// Extension methods for configuring HTTP OpenAPI services. | ||
| /// </summary> | ||
| public static class ServiceCollectionExtensions | ||
| { | ||
| /// <summary> | ||
| /// Adds HTTP OpenAPI services to the service collection. | ||
| /// </summary> | ||
| /// <param name="services">The service collection.</param> | ||
| /// <returns>The service collection for chaining.</returns> | ||
| public static IServiceCollection AddElsaHttpOpenApi(this IServiceCollection services) | ||
| { | ||
| services.AddScoped<IWorkflowEndpointExtractor, WorkflowEndpointExtractor>(); | ||
| services.AddSingleton<IElsaVersionProvider, ElsaVersionProvider>(); | ||
| services.AddSingleton<IOpenApiGenerator, OpenApiGenerator>(); | ||
|
|
||
| return services; | ||
| } | ||
| } |
25 changes: 25 additions & 0 deletions
25
src/modules/http/Elsa.Http.OpenApi/Features/HttpOpenApiFeature.cs
This file contains hidden or 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,25 @@ | ||
| using Elsa.Features.Abstractions; | ||
| using Elsa.Features.Attributes; | ||
| using Elsa.Features.Services; | ||
| using Elsa.Http.Features; | ||
| using Elsa.Http.OpenApi.Extensions; | ||
|
|
||
| namespace Elsa.Http.OpenApi.Features; | ||
|
|
||
| /// <summary> | ||
| /// Feature for HTTP OpenAPI functionality. | ||
| /// </summary> | ||
| [DependsOn(typeof(HttpFeature))] | ||
| public class HttpOpenApiFeature : FeatureBase | ||
| { | ||
| /// <inheritdoc /> | ||
| public HttpOpenApiFeature(IModule module) : base(module) | ||
| { | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public override void Apply() | ||
| { | ||
| Services.AddElsaHttpOpenApi(); | ||
| } | ||
| } |
This file contains hidden or 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 @@ | ||
| ο»Ώ<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> | ||
| <ConfigureAwait /> | ||
| </Weavers> |
18 changes: 18 additions & 0 deletions
18
src/modules/http/Elsa.Http.OpenApi/Models/EndpointDefinition.cs
This file contains hidden or 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,18 @@ | ||
| namespace Elsa.Http.OpenApi.Models; | ||
|
|
||
| /// <summary> | ||
| /// Represents an HTTP endpoint definition extracted from a workflow. | ||
| /// </summary> | ||
| /// <param name="Path">The HTTP path of the endpoint.</param> | ||
| /// <param name="Method">The HTTP method (GET, POST, etc.).</param> | ||
| /// <param name="Summary">Optional summary description of the endpoint.</param> | ||
| /// <param name="WorkflowDefinitionId">The workflow definition ID that contains this endpoint.</param> | ||
| /// <param name="WorkflowDefinitionName">The name of the workflow definition.</param> | ||
| /// <param name="WorkflowVersion">The version of the workflow definition.</param> | ||
| public record EndpointDefinition( | ||
| string Path, | ||
| string Method, | ||
| string? Summary = null, | ||
| string? WorkflowDefinitionId = null, | ||
| string? WorkflowDefinitionName = null, | ||
| int? WorkflowVersion = null); |
Empty file.
44 changes: 44 additions & 0 deletions
44
src/modules/http/Elsa.Http.OpenApi/Services/ElsaVersionProvider.cs
This file contains hidden or 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,44 @@ | ||
| using System.Linq; | ||
| using System.Reflection; | ||
| using Elsa.Http.OpenApi.Contracts; | ||
|
|
||
| namespace Elsa.Http.OpenApi.Services; | ||
|
|
||
| /// <summary> | ||
| /// Service for retrieving Elsa package version information by examining loaded assemblies. | ||
| /// </summary> | ||
| public class ElsaVersionProvider : IElsaVersionProvider | ||
| { | ||
| /// <summary> | ||
| /// Gets the Elsa package version by examining loaded assemblies. | ||
| /// </summary> | ||
| /// <returns>The package version string.</returns> | ||
| public string GetVersion() | ||
| { | ||
| // Try to get version from Elsa.Workflows.Core assembly first | ||
| var elsaCoreAssembly = AppDomain.CurrentDomain.GetAssemblies() | ||
| .FirstOrDefault(a => a.GetName().Name == "Elsa.Workflows.Core"); | ||
|
|
||
| if (elsaCoreAssembly != null) | ||
| { | ||
| var versionAttribute = elsaCoreAssembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>(); | ||
| return RemoveAutoGeneratedPostfix(versionAttribute); | ||
| } | ||
|
|
||
| // Fallback to any Elsa assembly | ||
| var elsaAssembly = AppDomain.CurrentDomain.GetAssemblies() | ||
| .FirstOrDefault(a => a.GetName().Name?.StartsWith("Elsa.") == true); | ||
|
|
||
| if (elsaAssembly != null) | ||
| { | ||
| var versionAttribute = elsaAssembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>(); | ||
| return RemoveAutoGeneratedPostfix(versionAttribute); | ||
| } | ||
|
|
||
| // Final fallback | ||
| return "1.0.0"; | ||
| } | ||
|
|
||
| private static string RemoveAutoGeneratedPostfix(AssemblyInformationalVersionAttribute? versionAttribute) => | ||
| versionAttribute?.InformationalVersion.Split("+")[0] ?? "1.0.0"; | ||
sfmskywalker marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
85 changes: 85 additions & 0 deletions
85
src/modules/http/Elsa.Http.OpenApi/Services/OpenApiGenerator.cs
This file contains hidden or 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,85 @@ | ||
| using Elsa.Http.OpenApi.Contracts; | ||
| using Elsa.Http.OpenApi.Models; | ||
| using System.Text.Json; | ||
|
|
||
| namespace Elsa.Http.OpenApi.Services; | ||
|
|
||
| /// <summary> | ||
| /// Service for generating OpenAPI JSON documentation from workflow endpoints. | ||
| /// </summary> | ||
| public class OpenApiGenerator : IOpenApiGenerator | ||
| { | ||
| private readonly IElsaVersionProvider _versionProvider; | ||
|
|
||
| public OpenApiGenerator(IElsaVersionProvider versionProvider) | ||
| { | ||
| _versionProvider = versionProvider; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Generates OpenAPI JSON documentation from a list of endpoint definitions. | ||
| /// </summary> | ||
| /// <param name="endpoints">The list of endpoint definitions.</param> | ||
| /// <returns>OpenAPI JSON string.</returns> | ||
| public string GenerateOpenApiJson(List<EndpointDefinition> endpoints) | ||
| { | ||
| var openApiDoc = new | ||
| { | ||
| openapi = "3.0.0", | ||
| info = new | ||
| { | ||
| title = "Elsa Workflow HTTP Endpoints", | ||
| version = _versionProvider.GetVersion(), | ||
| description = "HTTP endpoints exposed by Elsa workflows" | ||
| }, | ||
| paths = GeneratePaths(endpoints) | ||
| }; | ||
|
|
||
| return JsonSerializer.Serialize(openApiDoc, new JsonSerializerOptions | ||
| { | ||
| WriteIndented = true, | ||
| PropertyNamingPolicy = JsonNamingPolicy.CamelCase | ||
| }); | ||
| } | ||
|
|
||
| private object GeneratePaths(List<EndpointDefinition> endpoints) | ||
| { | ||
| var paths = new Dictionary<string, object>(); | ||
|
|
||
| foreach (var endpoint in endpoints) | ||
| { | ||
| if (!paths.ContainsKey(endpoint.Path)) | ||
| { | ||
| paths[endpoint.Path] = new Dictionary<string, object>(); | ||
| } | ||
|
|
||
| var pathItem = (Dictionary<string, object>)paths[endpoint.Path]; | ||
|
|
||
| // Create description with workflow definition ID if available | ||
| var description = endpoint.WorkflowDefinitionId != null | ||
| ? $"Workflow endpoint from '{endpoint.WorkflowDefinitionName}' (ID: {endpoint.WorkflowDefinitionId})" | ||
| : $"Workflow endpoint for {endpoint.Method.ToUpperInvariant()} {endpoint.Path}"; | ||
|
|
||
| // Use workflow name as tag, fallback to "Workflows" | ||
| var tags = endpoint.WorkflowDefinitionName != null | ||
| ? new[] { endpoint.WorkflowDefinitionName } | ||
| : new[] { "Workflows" }; | ||
|
|
||
| pathItem[endpoint.Method.ToLowerInvariant()] = new | ||
| { | ||
| summary = $"{endpoint.Method.ToUpperInvariant()} {endpoint.Path}", | ||
| description = description, | ||
| responses = new | ||
| { | ||
| @default = new | ||
| { | ||
| description = "Response from workflow execution" | ||
| } | ||
| }, | ||
| tags = tags | ||
| }; | ||
| } | ||
|
|
||
| return paths; | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.