ApiCallActivity
Category: Common Steps Namespace: CMS.Plugin.FlowManagement.Domain.FlowBusiness.Activitys Base Class: ActionActivity Module: FlowManagement.Domain
Overview
ApiCallActivity (Call API) is a node used to call external API interfaces in the process. It inherits from ActionActivity and supports calling API interfaces configured in system interconnection, writing the API response result to the process context. This node supports synchronous and asynchronous call modes, allowing flexible extraction of required data fields from the API response.
ApiCallActivity is an important bridge for integrating the process with external systems. Through it, data interaction with systems such as ERP, MES, WMS, etc., can be achieved, acquiring external data or triggering external operations.
Business Scenarios
Applicable Scenarios
- Data Query: Query product information, work order information, inventory information, etc., from external systems.
- Data Synchronization: Synchronize process data to external systems.
- Business Trigger: Trigger business operations in external systems (such as creating orders, sending notifications).
- System Integration: Data interaction with third-party systems.
- Service Call: Call microservice interfaces to get business data.
Role in the System
ApiCallActivity plays the role of a system integrator in the LMES process system:
- Calls API interfaces configured in system interconnection.
- Handles API requests and responses.
- Parses JSON response data.
- Writes response data to process context.
- Handles API call exceptions.
Collaboration with Other Nodes
- BusinessActivity: Prepares request parameters before API call and processes response data after API call.
- ActionActivity: As an action node, execution timing can be configured.
- Other API Nodes: Can chain multiple API calls to implement complex integration scenarios.
Configuration Description
Basic Configuration
| Property Name | Type | Required | Default | Description |
|---|---|---|---|---|
| ApiId | string | Yes | - | API ID, calls the API interface in interconnection |
| Wait | bool | No | true | Whether to wait for execution to end |
| Authorization | string | No | - | Authorization information (Request Token) |
| Response | HttpParameterModels | No | Empty Collection | Response parameter configuration |
| Action | ActionType | No | Execute | Execution timing (Inherited from ActionActivity) |
| IsSynchronous | bool | No | true | Whether to execute synchronously (Inherited from ActionActivity) |
Configuration Details
ApiId
Description: API ID, specifying the API interface to call. The API must be pre-configured in the system interconnection module.
Value Range: String, corresponding to the API ID configured in system interconnection.
Notes:
- Ensure the specified API exists in the system.
- The API must be enabled and configured correctly.
- API ID can be dynamically specified via process context.
Wait
Description: Whether to wait for the API execution to complete. When set to true, the process waits for the API call to finish and gets the response; when set to false, the process continues immediately without waiting for the API response.
Value Range: true or false
Notes:
- Wait=true (Default): Suitable for scenarios where API response data is needed.
- Wait=false: Suitable for scenarios where only triggering the API call is needed, and the response is not cared about (e.g., sending notifications).
- Asynchronous calls (Wait=false) can improve process execution efficiency but cannot get response data.
Authorization
Description: Authorization information used for API request authentication. Usually a Bearer Token or other authentication token.
Value Range: String, format depends on the API's authentication method.
Notes:
- If the API requires authentication, correct authorization information must be provided.
- Can be dynamically obtained from process context.
- Supports multiple authentication methods (Bearer, Basic, ApiKey, etc.).
Response
Description: Response parameter configuration, defining how to extract data from the API response and write it to the process context.
Configuration Structure: HttpParameterModels<HttpResponseParameterModel>
Response Parameter Model:
- ParameterName: Field path in response data (supports dot-separated nested paths).
- WriteParameterName: Key name written to process context.
- Description: Parameter description.
- DataType: Data type (String, Int, Bool, DateTime, etc.).
Notes:
- Supports extracting nested fields from JSON response (e.g., "data.user.name").
- If the response is an array, it automatically takes the first element.
- Error logs are recorded when data type conversion fails.
Action
Description: Execution timing, inherited from ActionActivity. Determines at which stage of the process lifecycle the API call is executed.
Value Range:
- QueryEnter: On query enter
- Enter: On enter
- Execute: On execute (Default)
- QueryExit: On query exit
- Exit: On exit
Notes:
- Use default value Execute for most cases.
- If API needs to be called before entering the node, use QueryEnter or Enter.
Process Context
Input Parameters
| Parameter Name | Type | Description |
|---|---|---|
| ApiId | string | API ID can be dynamically obtained from process context |
| Authorization | string | Authorization info can be dynamically obtained from process context |
| API Request Parameters | any | Request parameters defined in API configuration |
Output Parameters
| Parameter Name | Type | Description |
|---|---|---|
{NodeName}_StatusCode | int | HTTP status code of API response |
{NodeName}_Response | object | Complete content of API response (JSON string) |
| Custom Parameters | any | Extracted fields defined in Response configuration |
Data Flow Description
-
Before Request:
- Read API request parameters from process context.
- Prepare authorization information.
-
API Call:
- Call API via IInternalApi service.
- Wait for response (if Wait=true).
-
Response Handling:
- Write HTTP status code to
{NodeName}_StatusCode(NodeName is the value of the node's Name property). - Write complete response to
{NodeName}_Response. - Extract fields according to Response configuration and write to process context.
- Write HTTP status code to
Business Logic Description
Processing Flow
The execution flow of ApiCallActivity is as follows:
-
Initialization:
- Set default status code to 200 (OK).
- Get IInternalApi service.
- Record API call parameter logs.
-
Call API:
- Create InvokeRequest object, set ApiID.
- Call
internalApi.CallApiAsyncmethod. - Pass Authorization information.
-
Wait for Response (if Wait=true):
- Wait for API call to complete.
- Get response result (ClientModeAPIHandleResult).
- Record API URL and response content logs.
-
Handle Response:
- Write status code to process context.
- Write complete response to process context.
- Parse JSON response (if Response parameters are configured).
-
Extract Fields:
- Iterate through parameters in Response configuration.
- Use dot-separated path to extract nested fields.
- Perform data type conversion.
- Write extracted values to process context.
-
Exception Handling:
- Catch HttpRequestException.
- Extract HTTP status code.
- Record error logs.
Flowchart
[Prepare Parameters]
↓
[Call IInternalApi]
↓
[Send HTTP Request]
↓
[Wait for Response] (if Wait=true)
↓
[Parse JSON Response]
↓
[Extract Fields]
↓
[Write to Process Context]
↓
[Continue Execution]
JSON Response Parsing
ApiCallActivity supports extracting nested fields from JSON responses:
Example Response:
{
"code": 200,
"message": "success",
"data": {
"user": {
"id": 1001,
"name": "John Doe",
},
"products": [
{
"id": "P001",
"name": "Product A"
}
]
}
}
Field Extraction Configuration:
code→ Extract root level fielddata.user.name→ Extract nested fielddata.products→ Extract array (takes first element)
Dependent Services
| Service Interface | Usage | Description |
|---|---|---|
| IInternalApi | API Call Service | Responsible for actual HTTP request and response handling |
| Flow.ServiceProvider | Service Provider | Getting dependency injected services |
| Flow.Logger | Logger | Recording API call logs |
Exception Handling
| Exception Type | Handling Method | Description |
|---|---|---|
| HttpRequestException | Record error log, set status code | HTTP request failed |
| ApiResponseStatusException | Record error log, set status code | API returned error status code |
| JSON Parse Exception | Ignore, do not handle | Response is not in JSON format |
Exception Handling Mechanism:
- HTTP exceptions are caught, and status codes are written to process context.
- JSON parsing failure does not interrupt the process, it just stops field extraction.
- API call success can be determined by checking the status code.
Logging
ApiCallActivity records the following key logs:
- Before Call:
ApiId={ApiId}, Wait={Wait} - After Call:
ApiId={ApiId}, Url={result.Url} - Response Content:
ApiId={ApiId}, Result={result.ResponseBody} - Status Code:
ApiId={ApiId}, StatusCode={statusCode} - Exception: Complete exception stack information
Usage Examples
Basic Example
{
"Type": "ApiCallActivity",
"Name": "Query Product Info",
"Alias": "QueryProduct",
"ApiId": "GetProductInfo",
"Wait": true,
"Action": "Execute"
}
Advanced Example: Extract Response Fields
{
"Type": "ApiCallActivity",
"Name": "Query User Info",
"Alias": "QueryUser",
"ApiId": "GetUserInfo",
"Wait": true,
"Authorization": "Bearer {AccessToken}",
"Response": [
{
"ParameterName": "data.user.id",
"WriteParameterName": "UserId_Value",
"Description": "User ID",
"DataType": "Int"
},
{
"ParameterName": "data.user.name",
"WriteParameterName": "UserName_Value",
"Description": "User Name",
"DataType": "String"
},
{
"ParameterName": "data.user.email",
"WriteParameterName": "UserEmail_Value",
"Description": "User Email",
"DataType": "String"
}
]
}
Complete Process Example: Chaining Multiple API Calls
{
"Name": "Order Processing Flow",
"Activities": [
{
"Type": "BusinessActivity",
"Name": "Prepare Order No",
"Alias": "PrepareOrderNo"
},
{
"Type": "ApiCallActivity",
"Name": "Query Order Info",
"Alias": "QueryOrder",
"ApiId": "GetOrderInfo",
"Wait": true,
"Response": [
{
"ParameterName": "data.customerId",
"WriteParameterName": "CustomerId_Value",
"DataType": "Int"
},
{
"ParameterName": "data.productId",
"WriteParameterName": "ProductId_Value",
"DataType": "String"
}
]
},
{
"Type": "ApiCallActivity",
"Name": "Query Customer Info",
"Alias": "QueryCustomer",
"ApiId": "GetCustomerInfo",
"Wait": true,
"Response": [
{
"ParameterName": "data.customerName",
"WriteParameterName": "CustomerName_Value",
"DataType": "String"
},
{
"ParameterName": "data.address",
"WriteParameterName": "CustomerAddress_Value",
"DataType": "String"
}
]
},
{
"Type": "ApiCallActivity",
"Name": "Query Product Info",
"Alias": "QueryProduct",
"ApiId": "GetProductInfo",
"Wait": true,
"Response": [
{
"ParameterName": "data.productName",
"WriteParameterName": "ProductName_Value",
"DataType": "String"
},
{
"ParameterName": "data.price",
"WriteParameterName": "ProductPrice_Value",
"DataType": "Decimal"
}
]
},
{
"Type": "BusinessActivity",
"Name": "Process Order",
"Alias": "ProcessOrder"
}
]
}
Asynchronous Call Example
{
"Type": "ApiCallActivity",
"Name": "Send Notification",
"Alias": "SendNotification",
"ApiId": "SendEmail",
"Wait": false,
"Action": "Exit"
}
Handling API Response Example
// Check API call result in subsequent node
[Serializable]
[Design("Process API Response", "Check and process API call result", Sort = 1)]
[Category("Custom")]
public class ProcessApiResponseActivity : BusinessActivity
{
public override async Task ProcessAsync(ProcessflowEventArgs args)
{
// Get status code
var statusCode = (int)Flow.DataItems["QueryProduct_StatusCode"];
if (statusCode == 200)
{
// API call successful, process response data
var productName = Flow.DataItems["ProductName_Value"]?.ToString();
var productPrice = Flow.DataItems["ProductPrice_Value"];
Flow.Logger.LogMessage($"Product Info: {productName}, Price: {productPrice}", Name);
// Continue business processing
Flow.DataItems["ProcessResult_Value"] = "Success";
}
else
{
// API call failed, record error
var response = Flow.DataItems["QueryProduct_Response"]?.ToString();
Flow.Logger.LogErrorMessage($"API call failed: StatusCode={statusCode}, Response={response}");
Flow.DataItems["ProcessResult_Value"] = "Failed";
throw new BusinessException(Name, $"API call failed: {statusCode}");
}
await base.ProcessAsync(args);
}
}
Extension Development Guide
Inheritance Hierarchy
Activity (SYC.Flow.Kernel)
└── BusinessActivity
└── ActionActivity
└── ApiCallActivity
Overridable Methods
| Method Name | Usage | When to Override |
|---|---|---|
| ExecuteActionAsync | Execute API call | Need custom API call logic |
| ProcessAsync | Core business logic | Need processing before/after API call |
Custom API Call Node Example
[Serializable]
[Design("Enhanced API Call", "API call node with retry and timeout", Sort = 1)]
[Category("Custom")]
public class EnhancedApiCallActivity : ApiCallActivity
{
[Design("Retry Count", "Retry count when API call fails", Sort = 10)]
[Category("API Config")]
[DataMember]
public int RetryCount { get; set; } = 3;
[Design("Timeout", "API call timeout (seconds)", Sort = 11)]
[Category("API Config")]
[DataMember]
public int TimeoutSeconds { get; set; } = 30;
protected override async Task ExecuteActionAsync(ProcessflowEventArgs args)
{
int attempt = 0;
Exception lastException = null;
while (attempt < RetryCount)
{
attempt++;
try
{
Flow.Logger.LogMessage($"API call attempt {attempt}/{RetryCount}", Name);
// Set timeout
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(TimeoutSeconds));
// Call base method
await base.ExecuteActionAsync(args);
// Check status code
var statusCode = (int)Flow.DataItems[$"{Name}_StatusCode"];
if (statusCode >= 200 && statusCode < 300)
{
Flow.Logger.LogMessage($"API call successful: StatusCode={statusCode}", Name);
return; // Success, exit
}
Flow.Logger.LogWarningMessage($"API returned error status code: {statusCode}", Name);
lastException = new Exception($"API returned error status code: {statusCode}");
}
catch (OperationCanceledException)
{
Flow.Logger.LogWarningMessage($"API call timeout: {TimeoutSeconds}s", Name);
lastException = new Exception($"API call timeout: {TimeoutSeconds}s");
}
catch (Exception ex)
{
Flow.Logger.LogExceptionMessage(ex, Name);
lastException = ex;
}
if (attempt < RetryCount)
{
// Wait and retry
var delay = attempt * 1000; // Incremental delay
Flow.Logger.LogMessage($"Waiting {delay}ms before retry", Name);
await Task.Delay(delay);
}
}
// All retries failed
throw new BusinessException(Name, $"API call failed after {RetryCount} retries", lastException);
}
}
Notes
- ⚠️ API Configuration: API must be configured in the system interconnection module before it can be used in the process.
- ⚠️ Status Code Check: Check the status code after the call to ensure the API call was successful.
- ⚠️ Asynchronous Call: When Wait=false, response data cannot be obtained, suitable only for triggering operations.
- ⚠️ JSON Format: Response parameter extraction only supports JSON format responses.
- ⚠️ Authorization: If API requires authentication, correct Authorization must be provided.
- ⚠️ Timeout Handling: Long-running APIs may block the process, consider setting timeouts.
- ⚠️ Exception Handling: API call failure does not interrupt the process, need to check status code.
- 💡 Best Practices:
- Check status codes after API calls to handle failures.
- Use Response configuration to extract required fields, avoiding manual JSON parsing.
- Add logs for API calls to facilitate troubleshooting.
- Consider using retry mechanisms to improve call success rate.
- Sensitive information (like Tokens) should be dynamically obtained from configuration or process context.
- Use Wait parameter reasonably to balance performance and data needs.
Related Nodes
- ActionActivity: Base class for API call nodes.
- ApiConnectActivity: API connection test node.
- MethodCallActivity: C# method call node.
- ScriptCallActivity: Script call node.
FAQ
Q1: How to configure API interface?
A: Configure in System Interconnection module:
- Enter System Interconnection management interface.
- Create new API configuration.
- Set API URL, request method, headers, parameters, etc.
- Save and enable API.
- Record API ID, use in process.
Q2: How to extract nested fields from API response?
A: Use dot-separated path:
{
"Response": [
{
"ParameterName": "data.user.name",
"WriteParameterName": "UserName_Value"
}
]
}
This will extract the value from data.user.name path in the response.
Q3: How to handle API call failure?
A: Check status code in subsequent node:
var statusCode = (int)Flow.DataItems["ApiNode_StatusCode"];
if (statusCode != 200)
{
// Handle failure
throw new BusinessException("API call failed");
}
Q4: How to pass dynamic parameters to API?
A: API request parameters are configured in System Interconnection, and can reference process context values:
- In API config, parameter value uses
{ParameterName}format. - The process automatically retrieves corresponding values from process context.
Q5: How to know if API call succeeded when Wait=false?
A: When Wait=false, response cannot be obtained, and result is unknown. This mode is only suitable for:
- Sending notifications (don't care about result).
- Triggering async tasks (result obtained via other means).
If result is needed, Wait=true must be used.
Q6: How to handle array data returned by API?
A: ApiCallActivity automatically takes the first element of the array. If the whole array needs processing:
- Do not configure Response parameters.
- Manually parse JSON data in
{NodeName}_Responsein subsequent nodes.
Q7: How to add custom request headers?
A: Add request headers in API configuration in System Interconnection, not in the process node.
Update History
| Date | Version | Description |
|---|---|---|
| 2025-11-28 | 1.0 | Initial version |
Last updated: 2025-11-28