Implemented post patch and put call body to be able to parse from model
Some checks failed
Build / build (push) Has been cancelled

This commit is contained in:
Ankitkumar Satapara
2026-04-22 18:02:06 +05:30
parent 9a9202e373
commit 5c61fa1e53
6 changed files with 142 additions and 5 deletions

View File

@@ -27,5 +27,12 @@ namespace Nodify.Calculator
get => _responseModelClassName;
set => SetProperty(ref _responseModelClassName, value);
}
private string _requestBodyModelClassName = string.Empty;
public string RequestBodyModelClassName
{
get => _requestBodyModelClassName;
set => SetProperty(ref _requestBodyModelClassName, value);
}
}
}

View File

@@ -26,6 +26,7 @@ namespace Nodify.Calculator.Models
// API node properties
public string OPType { get; set; } = string.Empty;
public string ResponseModelClassName { get; set; } = string.Empty;
public string RequestBodyModelClassName { get; set; } = string.Empty;
// System node properties
public string SystemOp { get; set; } = string.Empty;

View File

@@ -10,6 +10,7 @@ namespace Nodify.Calculator.Models
public List<string> InputNames { get; set; } = new List<string>();
public string SwaggerFileName { get; set; } = string.Empty;
public string ResponseModelClassName { get; set; } = string.Empty;
public string RequestBodyModelClassName { get; set; } = string.Empty;
public string SwaggerGroup { get; set; } = string.Empty;
}
}

View File

@@ -76,7 +76,8 @@ namespace Nodify.Calculator.NodeHandlers
{
Title = info.Title,
OperationType = (info.OPType ?? "GET").ToUpper(),
ResponseModelClassName = info.ResponseModelClassName ?? string.Empty
ResponseModelClassName = info.ResponseModelClassName ?? string.Empty,
RequestBodyModelClassName = info.RequestBodyModelClassName ?? string.Empty
};
// Flow connectors
@@ -109,7 +110,35 @@ namespace Nodify.Calculator.NodeHandlers
});
}
// Data inputs
// Request body input (for POST/PUT/PATCH)
var httpMethod = (info.OPType ?? "").ToUpper();
if (httpMethod == "POST" || httpMethod == "PUT" || httpMethod == "PATCH")
{
if (!string.IsNullOrEmpty(info.RequestBodyModelClassName))
{
var bc = info.RequestBodyModelClassName;
bool isList = bc.StartsWith("List<") && bc.EndsWith(">");
op.Input.Add(new ConnectorViewModel
{
Title = $"Body ({bc})",
Shape = isList ? ConnectorShape.Grid : ConnectorShape.Square,
ConnectorColor = isList ? Color.MediumSpringGreen : Color.MediumPurple,
DataType = bc
});
}
else
{
op.Input.Add(new ConnectorViewModel
{
Title = "Body",
Shape = ConnectorShape.Circle,
ConnectorColor = Color.LimeGreen,
DataType = "object"
});
}
}
// Other data inputs (query/path params)
foreach (var label in info.Input)
{
op.Input.Add(new ConnectorViewModel { Title = label, ConnectorColor = Color.LimeGreen });
@@ -124,12 +153,16 @@ namespace Nodify.Calculator.NodeHandlers
Title = data.Title,
OPType = data.OPType?.ToLower() ?? "get",
Type = OperationType.API,
ResponseModelClassName = data.ResponseModelClassName ?? string.Empty
ResponseModelClassName = data.ResponseModelClassName ?? string.Empty,
RequestBodyModelClassName = data.RequestBodyModelClassName ?? string.Empty
};
// Restore only query/path param inputs (skip flow triangles and body connectors)
foreach (var ic in data.InputConnectors)
{
if (ic.Shape != "Triangle")
info.Input.Add(ic.Title);
if (ic.Shape == "Triangle") continue;
if (ic.Shape == "Square" || ic.Shape == "Grid") continue; // body model connector
if ((ic.Title ?? "").StartsWith("Body")) continue;
info.Input.Add(ic.Title);
}
return Create(info);
}
@@ -141,6 +174,7 @@ namespace Nodify.Calculator.NodeHandlers
{
data.OPType = api.OperationType;
data.ResponseModelClassName = api.ResponseModelClassName;
data.RequestBodyModelClassName = api.RequestBodyModelClassName;
}
}
}

View File

@@ -36,6 +36,7 @@ namespace Nodify.Calculator
public List<FunctionParameterInfo> FunctionInputs { get; set; } = new List<FunctionParameterInfo>();
public List<FunctionParameterInfo> FunctionOutputs { get; set; } = new List<FunctionParameterInfo>();
public string ResponseModelClassName { get; set; } = string.Empty;
public string RequestBodyModelClassName { get; set; } = string.Empty;
public string SwaggerGroup { get; set; } = string.Empty;
}
}

View File

@@ -417,12 +417,24 @@ namespace Nodify.Calculator
var addedParams = new HashSet<string>();
foreach (var parameter in method.Value.Parameters)
{
// Skip body parameters — they are handled by ExtractRequestBodyModel
if (parameter.Kind == NSwag.OpenApiParameterKind.Body)
continue;
if (addedParams.Add(parameter.Name))
{
ovmodel.Input.Add(parameter.Name);
}
}
// Extract request body model for POST/PUT/PATCH
var httpMethodLower = method.Key.ToLower();
if (httpMethodLower == "post" || httpMethodLower == "put" || httpMethodLower == "patch")
{
var bodyModelName = ExtractRequestBodyModel(method.Value, path.Key, method.Key, createdModels);
ovmodel.RequestBodyModelClassName = bodyModelName;
}
// Extract response model from 200/201 response schema
var responseModelName = ExtractResponseModel(method.Value, path.Key, method.Key, createdModels);
ovmodel.ResponseModelClassName = responseModelName;
@@ -516,6 +528,85 @@ namespace Nodify.Calculator
return string.Empty;
}
private string ExtractRequestBodyModel(NSwag.OpenApiOperation operation, string path, string httpMethod, HashSet<string> createdModels)
{
try
{
NJsonSchema.JsonSchema bodySchema = null;
// OpenAPI 3.0: operation.RequestBody.Content
if (operation.RequestBody?.Content != null && operation.RequestBody.Content.Count > 0)
{
if (operation.RequestBody.Content.TryGetValue("application/json", out var jsonContent))
bodySchema = jsonContent.Schema;
else
bodySchema = operation.RequestBody.Content.Values.FirstOrDefault()?.Schema;
}
// OpenAPI 2.0 (Swagger): body parameter with In == Body
if (bodySchema == null)
{
var bodyParam = operation.Parameters.FirstOrDefault(
p => p.Kind == NSwag.OpenApiParameterKind.Body);
if (bodyParam != null)
bodySchema = bodyParam.Schema ?? bodyParam.ActualSchema;
}
if (bodySchema == null) return string.Empty;
var actualSchema = bodySchema.ActualSchema ?? bodySchema;
// Resolve arrays
var targetSchema = actualSchema;
bool isList = false;
if (actualSchema.Type == NJsonSchema.JsonObjectType.Array && actualSchema.Item != null)
{
targetSchema = actualSchema.Item.ActualSchema ?? actualSchema.Item;
isList = true;
}
targetSchema = targetSchema.ActualSchema ?? targetSchema;
// Derive class name
var className = !string.IsNullOrEmpty(targetSchema.Title)
? targetSchema.Title
: DeriveRequestClassName(path, httpMethod);
className = SanitizeClassName(className);
var props = targetSchema.ActualProperties;
if (string.IsNullOrEmpty(className) || props == null || props.Count == 0)
return string.Empty;
// Generate model file if not already done
if (createdModels.Add(className))
{
GenerateModelFromSchema(className, targetSchema);
var modelInfo = new OperationInfoViewModel
{
Title = className,
IsModelNode = true,
Type = OperationType.System,
sysOp = SystemOperations.GET_SET,
ClassName = className
};
AddNewModel(modelInfo);
}
return isList ? $"List<{className}>" : className;
}
catch { /* Best-effort */ }
return string.Empty;
}
private static string DeriveRequestClassName(string path, string httpMethod)
{
var segments = path.Split('/', StringSplitOptions.RemoveEmptyEntries)
.Where(s => !s.StartsWith("{"))
.Select(s => Executor.ToPascalCase(s));
return $"{Executor.ToPascalCase(httpMethod)}{string.Join("", segments)}Request";
}
private void GenerateModelFromSchema(string className, NJsonSchema.JsonSchema schema)
{
var customModelDir = Path.Combine(ProjectManager.ProjectDirectory, "CustomModels");
@@ -613,6 +704,7 @@ namespace Nodify.Calculator
InputNames = new List<string>(node.Input),
SwaggerFileName = swaggerFileName,
ResponseModelClassName = node.ResponseModelClassName ?? string.Empty,
RequestBodyModelClassName = node.RequestBodyModelClassName ?? string.Empty,
SwaggerGroup = node.SwaggerGroup ?? string.Empty
});
}
@@ -645,6 +737,7 @@ namespace Nodify.Calculator
}
ovmodel.ResponseModelClassName = saved.ResponseModelClassName ?? string.Empty;
ovmodel.RequestBodyModelClassName = saved.RequestBodyModelClassName ?? string.Empty;
ovmodel.Output.Add("");
SwaggerOperations.Add(ovmodel);
}