Skip to content

Adapter Implementation

Introduction

Adapters are an extensibility point within the AireGlu framework. They allow you to implement custom task behaviours as a code plugin, which can then be called upon within any endpoint pipeline.

Development

  1. Create a new dotnet core class library
    dotnet new classlib --framework net9.0
  2. Install the AireGlu SDK
    dotnet add package AireGlu.SDK
  3. Implement a custom adapter
csharp
using AireGlu.Public.DTO.ResolvedValues;
using AireGlu.SDK;
using System.Text.Json;

namespace Adapters
{
    [Adapter("Test")]
    public class TestAdapter : Adapter<TestResolvedValues>
    {
        public override Task<TaskResult> ExecuteFromJson(
            string valuesJson,
            IEnumerable<TaskResult> taskResults,
            string transactionId)
        {
            // Parse values from JSON
            var values = JsonSerializer.Deserialize<TestResolvedValues>(valuesJson);
            
            return Task.FromResult(new TaskResult
            {
                Success = true,
                Result = $"Test result with {values.ParameterName}"
            });
        }
    }
}

Defining Adapter Values

Adapters use a class derived from ResolvedValues to define the parameters they accept:

csharp
using AireGlu.Public.DTO;
using AireGlu.Public.DTO.ResolvedValues;

namespace Adapters
{
    public class TestResolvedValues : ResolvedValues
    {
        [AdapterField(AdapterFieldEditorType.Text, Required=true)]
        public string ParameterName { get; set; }

        [AdapterField(AdapterFieldEditorType.RichText)]
        public string Description { get; set; }
        
        [AdapterField(AdapterFieldEditorType.Select, Values = new[] {"Option1", "Option2", "Option3"})]
        public string DropdownOption { get; set; }
    }
}

This will generate UI for each custom property:

You can decorate properties with [AdapterField] attributes to specify:

  • Editor type
  • Required status
  • Friendly name
  • Primary status

adapter

Editor Types

  • Text: Single-line text input
  • TextArea: Multi-line text input
  • RichText: Formatted text editor with HTML support
  • CodeEditor: Syntax-highlighted code entry
  • Select: Dropdown menu of preset options (defined in the Values attribute)

If the attribute is omitted, the property will use the default 'Text' editor type, with the name taken from the property name, and required being false.

Building and Bundling

The SDK automatically handles building your adapter as a bundle:

bash
dotnet build -c Release

This will:

  1. Compile your adapter code
  2. Generate metadata about your adapter values
  3. Create a bundle (zip file) containing your adapter and dependencies
  4. Place the bundle in bin/Release/net9.0/Bundles/YourAdapter.zip

Dependency Management

All dependencies your adapter needs must be bundled with it. Add NuGet packages or project references to your project file:

xml
<ItemGroup>
    <!-- Reference external packages -->
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
    
    <!-- Reference internal libraries -->
    <ProjectReference Include="..\MyCompany.Common\MyCompany.Common.csproj" />
</ItemGroup>

Injection

Your adapter implementation can have dependencies injected from AireGlu using the [ImportingConstructor] attribute:

csharp
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using System.Composition;

using AireGlu.SDK;

namespace Adapters
{
    [Adapter("Slack")]
    public class SlackAdapter : Adapter<SlackResolvedValues>
    {
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly IConfiguration _configuration;

        [ImportingConstructor]
        public SlackAdapter(IHttpClientFactory httpClientFactory, IConfiguration configuration)
        {
            _httpClientFactory = httpClientFactory;
            _configuration = configuration;
        }

        public override async Task<TaskResult> ExecuteFromJson(
            string valuesJson,
            IEnumerable<TaskResult> taskResults,
            string transactionId)
        {
            var values = JsonSerializer.Deserialize<SlackResolvedValues>(valuesJson);
            
            using var client = _httpClientFactory.CreateClient();
            var result = await client.PostAsync(
                values.WebHookUrl,
                new StringContent(
                    $"{{\"text\":\"{values.Message}\"}}",
                    Encoding.UTF8,
                    "application/json"));

            return new TaskResult()
            {
                Success = result.IsSuccessStatusCode,
                Result = await result.Content.ReadAsStringAsync()
            };
        }
    }
}

The available imports include:

  • System.Net.Http.IHttpClientFactory
  • Microsoft.Extensions.Configuration.IConfiguration

Returning Different Content Types

You can return different content types from your adapter:

csharp
// Return JSON
return new TaskResult
{
    Success = true,
    Result = JsonSerializer.Serialize(data),
    ContentType = "application/json"
};

// Return HTML
return new TaskResult
{
    Success = true,
    Result = "<html><body><h1>Hello World</h1></body></html>",
    ContentType = "text/html"
};

// Return binary data as a stream
return new TaskResult
{
    Success = true,
    StreamResult = pdfStream,
    ContentType = "application/pdf"
};

Accessing Adapter Output

To access the output of an adapter via liquid:

{{ endpoint.Tasks[indexOfAdapterTask] }}

This will return:

json
{
    "Format": "XML",
    "StatusCode": 200,
    "Result": "result of mapping-task",
    "Success": true,
    "ContentType": "application/xml",
    "RedirectUrl": null,
}

Long-running Operations with Adapter Callbacks

For operations that might take longer than a typical request cycle (such as large file processing, external API integrations, or complex calculations), you can use adapter callbacks to implement asynchronous execution.

How Callbacks Work

When you configure an adapter with a callback, the adapter service:

  1. Immediately returns an "ACCEPTED" response with a unique execution ID
  2. Continues executing the adapter in the background
  3. Invokes your specified callback endpoint when the operation completes

Implementing a callback handler

Your callback endpoint will receive the adapter's execution results when the operation completes. The input type of the callback endpoint must be AdapterCallback:

json
{
  "executionId": "7f8d9e10-a2b3-4c5d-6e7f-8g9h0i1j2k3l",
  "status": "COMPLETED",
  "result": "Operation completed successfully",
  "success": true,
  "statusCode": 200
}

Select the callback endpoint and endpoint environment or version from the drop downs. If this is ommitted the adapter will function in "synchronous mode".

adapter callback

Callback Retry

The adapter service includes built-in retry logic for callbacks where the status code is 5XX:

  1. If the callback endpoint is unavailable or returns an error, the service will retry
  2. Retries follow an exponential backoff pattern (increasing delays between attempts)
  3. Default configuration: 3 retry attempts with backoff starting at 1 second Each retry includes metadata about the attempt count

Publishing

To make your adapter available in your AireGlu environment:

  • Build your adapter in Release mode
  • Upload the generated bundle to the aireglu-adapters AWS S3 bucket
  • Configure tenant and user access to the adapter

For enterprise environments, you may need to submit the adapter for approval through our light-touch governance process. Contact support@airelogic.com to initiate this process.

Best Practices

  • Keep your adapter focused on a single responsibility
  • Include all dependencies in your project file
  • Use proper error handling and return appropriate status codes
  • Implement logging for troubleshooting
  • Test thoroughly before deployment
  • Consider performance implications for long-running operations