Creating an API Module Client

Inherit from the ApiModuleClient class to create a remote client for your API Module.

Background

In this example, we will inherit from the ApiModuleClient class in the Scaleout.Modules.Client NuGet package to create a custom client that invokes the operations defined in the “ShoppingCart” API module created in the previous topic.

Prerequisites

  • .NET 8 SDK or higher.

  • Scaleout.Modules.Client NuGet Package.

  • A deployed API Module. This walkthrough will create a client class for the “ShoppingCart” API module project created in the previous topic.

Procedure

1. Create a client project

In a new console application project (or in any existing application/library outside of the ShoppingCart API module), add a reference to the Scaleout.Modules.Client NuGet package.

2. Create an ApiModuleClient subclass

Create a new class that inherits from the ApiModuleClient class. This class will be used to interact with the “ShoppingCart” API module.

using Scaleout.Client;
using Scaleout.Modules.Client;

namespace ApiModuleExampleClient
{
    public record CartItem(string ProductId, int Quantity, decimal Price);

    public class ShoppingCartClient : ApiModuleClient
    {
        // Constructor
        public ShoppingCartClient(string moduleName, GridConnection gridConnection) 
            : base(moduleName, gridConnection) { }


        // Invoke the AddItem API method on the ShoppingCart module.
        public Task AddItemAsync(string cartId, CartItem newItem)
        {
            byte[] itemBytes = System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(newItem);
            return InvokeAsync(cartId, "AddItem", itemBytes);
        }

        // Invoke the GetTotal API method on the ShoppingCart module.
        public async Task<decimal> GetTotalAsync(string cartId)
        {
            byte[]? resultBytes = await InvokeAsync(cartId, "GetTotal", Array.Empty<byte>());
            if (resultBytes == null || resultBytes.Length == 0)
                return 0m;

            return System.Text.Json.JsonSerializer.Deserialize<decimal>(resultBytes);
        }
    }
}

The base class constructor requires the following two parameters:

  • The name of the API module (in this case, “ShoppingCart”). The supplied name should match the name that the module uses in its Startup.cs file when it calls ModulePackage.AddApiModule(moduleName).

  • A Scaleout.Client.GridConnection instance that is used to connect to the ScaleOut StateServer cluster. Creation of the GridConnection instance is described in the next step.

The two methods (AddItemAsync and GetTotalAsync) are implemented to invoke the operations on the ShoppingCart API module. A client method typically performs the following steps:

  1. Encode any parameters as a byte array that the API module expects to receive.

  2. Call the base class’ InvokeApiMethodAsync() method, supplying the ID of the SOSS object to operate on, the name of the API method to invoke, and the byte array of parameters. The name of the API method must match the name specified in the [SossApiMethod] attribute in the API module.

  3. Handle the values returned from the API module, which will also be a byte array. You may need to decode this response into the appropriate format.

3. Use the client class

The client class you have created above can be used in any application that needs to interact with the ShoppingCart API module. The client application uses a GridConnection instance to connect to the ScaleOut StateServer cluster. See Connecting to a ScaleOut Data Grid for more information on using the GridConnection class.

using Scaleout.Client;
using ApiModuleExampleClient;

internal class Program
{
    static async Task Main(string[] args)
    {
        GridConnection conn = GridConnection.Connect("bootstrapGateways=localhost:721");

        var shoppingCartClient = new ShoppingCartClient("ShoppingCart", conn);

        await shoppingCartClient.AddItemAsync("cart1", new CartItem("item1", 2, 19.99m));
        decimal total = await shoppingCartClient.GetTotalAsync("cart1");
    }
}