From 2b22400c25f1eaf6d6e6696c79c1503f2bbd79ae Mon Sep 17 00:00:00 2001 From: Chandrasekar Vijayakumar <65659375+cvijayak@users.noreply.github.com> Date: Fri, 16 Aug 2024 15:33:18 +0530 Subject: [PATCH] Modified POST Execute API to Display Body in Swagger and Fixed Type-Casting Error in GET Execute API (#5858) * Modified POST execute API to show body in Swagger and resolved type-casting error in GET execute API Modified the POST execute API to display the body in Swagger documentation and resolved the type-casting error in the GET execute API * Added IExecutionRequest interface defines a contract for Request classes * Moved the serialization logic into request classes * Add missing import and reformat ActivityHandle property Included the Elsa.Workflows.Models import in Models.cs to fix missing reference. Removed redundant ActivityHandle assignment in EndpointBase.cs to improve clarity and reduce redundancy. --------- Co-authored-by: Sipke Schoorstra --- .../Execute/{Endpoint.cs => EndpointBase.cs} | 14 +++---- .../Execute/GetEndpoint.cs | 24 +++++++++++ .../WorkflowDefinitions/Execute/Models.cs | 42 ++++++++++++++++++- .../Execute/PostEndpoint.cs | 24 +++++++++++ 4 files changed, 94 insertions(+), 10 deletions(-) rename src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/{Endpoint.cs => EndpointBase.cs} (89%) create mode 100644 src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/GetEndpoint.cs create mode 100644 src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/PostEndpoint.cs diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/EndpointBase.cs similarity index 89% rename from src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/Endpoint.cs rename to src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/EndpointBase.cs index 2c4eb5502..bce88400e 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/EndpointBase.cs @@ -7,31 +7,29 @@ using Elsa.Workflows.Models; using Elsa.Workflows.Runtime; using Elsa.Workflows.Runtime.Messages; using Elsa.Workflows.State; -using JetBrains.Annotations; using Microsoft.AspNetCore.Http; namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.Execute; /// -/// An API endpoint that executes a given workflow definition. +/// This abstract class provides the necessary infrastructure to handle the execution of workflows, including setup of routes, permissions, +/// and processing of HTTP requests to execute workflows. /// -[PublicAPI] -internal class Execute( +internal abstract class EndpointBase( IWorkflowDefinitionService workflowDefinitionService, IWorkflowRuntime workflowRuntime, IApiSerializer apiSerializer) - : ElsaEndpoint + : ElsaEndpoint where T : IExecutionRequest, new() { /// public override void Configure() { Routes("/workflow-definitions/{definitionId}/execute"); - Verbs(FastEndpoints.Http.GET, FastEndpoints.Http.POST); ConfigurePermissions("exec:workflow-definitions"); } /// - public override async Task HandleAsync(Request request, CancellationToken cancellationToken) + public override async Task HandleAsync(T request, CancellationToken cancellationToken) { var definitionId = request.DefinitionId; var versionOptions = request.VersionOptions ?? VersionOptions.Published; @@ -48,7 +46,7 @@ internal class Execute( { WorkflowDefinitionHandle = WorkflowDefinitionHandle.ByDefinitionVersionId(workflowGraph.Workflow.Identity.Id), CorrelationId = request.CorrelationId, - Input = (IDictionary?)request.Input, + Input = request.GetInputAsDictionary(), TriggerActivityId = request.TriggerActivityId, ActivityHandle = request.ActivityHandle }; diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/GetEndpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/GetEndpoint.cs new file mode 100644 index 000000000..cbe346d1b --- /dev/null +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/GetEndpoint.cs @@ -0,0 +1,24 @@ +using Elsa.Workflows.Contracts; +using Elsa.Workflows.Management; +using Elsa.Workflows.Runtime; +using JetBrains.Annotations; + +namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.Execute; + +/// +/// An API endpoint that executes a given workflow definition through GET method. +/// +[PublicAPI] +internal class GetEndpoint( + IWorkflowDefinitionService workflowDefinitionService, + IWorkflowRuntime workflowRuntime, + IApiSerializer apiSerializer) + : EndpointBase(workflowDefinitionService, workflowRuntime, apiSerializer) +{ + /// + public override void Configure() + { + base.Configure(); + Verbs(FastEndpoints.Http.GET); + } +} \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/Models.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/Models.cs index 3ed13e160..12b31ad04 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/Models.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/Models.cs @@ -1,22 +1,60 @@ +using System.Dynamic; +using System.Text.Json; using System.Text.Json.Serialization; using Elsa.Common.Models; +using Elsa.Expressions.Helpers; using Elsa.Workflows.Models; using Elsa.Workflows.Serialization.Converters; using Elsa.Workflows.State; namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.Execute; -public class Request +public interface IExecutionRequest +{ + string DefinitionId { get; } + string? CorrelationId { get; } + string? TriggerActivityId { get; } + ActivityHandle? ActivityHandle { get; } + VersionOptions? VersionOptions { get; } + + IDictionary? GetInputAsDictionary(); +} + +public class PostRequest : IExecutionRequest { public string DefinitionId { get; set; } = default!; public string? CorrelationId { get; set; } public string? TriggerActivityId { get; set; } public ActivityHandle? ActivityHandle { get; set; } - public VersionOptions? VersionOptions { get; set; } [JsonConverter(typeof(ExpandoObjectConverterFactory))] public object? Input { get; set; } + + public IDictionary? GetInputAsDictionary() => (IDictionary?)Input; +} + +public class GetRequest : IExecutionRequest +{ + public string DefinitionId { get; set; } = default!; + public string? CorrelationId { get; set; } + public string? TriggerActivityId { get; set; } + public ActivityHandle? ActivityHandle { get; set; } + public VersionOptions? VersionOptions { get; set; } + public string? Input { get; set; } + + public IDictionary? GetInputAsDictionary() + { + var result = Input?.TryConvertTo(new ObjectConverterOptions + { + SerializerOptions = new JsonSerializerOptions + { + Converters = { new ExpandoObjectConverter() } + } + }); + + return result?.Success == true ? (IDictionary?)result.Value : null; + } } public class Response(WorkflowState workflowState) diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/PostEndpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/PostEndpoint.cs new file mode 100644 index 000000000..83ce6ad88 --- /dev/null +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Execute/PostEndpoint.cs @@ -0,0 +1,24 @@ +using Elsa.Workflows.Contracts; +using Elsa.Workflows.Management; +using Elsa.Workflows.Runtime; +using JetBrains.Annotations; + +namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.Execute; + +/// +/// An API endpoint that executes a given workflow definition through POST method. +/// +[PublicAPI] +internal class PostEndpoint( + IWorkflowDefinitionService workflowDefinitionService, + IWorkflowRuntime workflowRuntime, + IApiSerializer apiSerializer) + : EndpointBase(workflowDefinitionService, workflowRuntime, apiSerializer) +{ + /// + public override void Configure() + { + base.Configure(); + Verbs(FastEndpoints.Http.POST); + } +} \ No newline at end of file