DEV Community

Cover image for Creating a Basic Serverless Feature Flag Service using CDK and C#
John Hatton
John Hatton

Posted on • Updated on

Creating a Basic Serverless Feature Flag Service using CDK and C#

In this blog I am going to go through and discuss a Serverless application on AWS defined using CDK written in C#.

So What is serverless? well it's a way to build and run applications and services without having to manage infrastructure and resources as AWS takes care of this.

The aim of this simple application is to showcase to developers who are new or unfamiliar with AWS and AWS serverless what they can achieve, as well as how infrastructure can be written as code using AWS Cloud Development Kit. The application uses Amazon API Gateway to handle the requests. Uses AWS Lambda as the compute service to process the requests and Amazon DynamoDB as the storage.
This was also an interesting challenge to use CDK using C# as I had predominately been using typescript.

I thought would start with a fairly simple idea of a feature flag service that I'm sure many of us have either wished we had used, used a 3rd party product or used a simple database to enable/disable features.

The idea of this service is to store whether a flag is enabled or disabled.

As this application is to demonstrate how you could use serverless services to achieve this, the flags are only boolean values and there are only 4 endpoints with basic validation and has no authentication.

The actions on the api are Create, Delete, Get and Update.
Using CDK, an Amazon API gateway is deployed which these 4 actions. These are all using lambda proxy integrations with each lambda being responsible for one of the following:

  • Inserting
    • This Lambda will first query DynamoDB to check if this feature flag already exists, if the flag exists an error is returned. If the flag does not exist then the flag is saved into DynamoDB and a success is returned
  • Deleting
    • This Lambda will query to check if the flag exists and if it does not it will return an error, if the flag does exist it will attempt to delete this entry and return whether it was successful or not.
  • Retrieving
    • This lambda will query to find the requested flag, if it exists the flag name and value is returned. If the flag does not exist and error is returned instead.
  • Updating
    • This lambda will query to check the flag exists and then attempt to update the value if it does, if the flag does not exist an error is returned.

As DynamoDB is serverless it can auto scale to match the demands of the service and will charge per request when using On Demand.

As with DynamoDB, Lambda is also a serverless service and therefore will only charge per request.

Below is an overview of the architecture for the application

Overview of the architecture of the application

Next I am going to go over some of the infrastructure that has been written using CDK.

Firstly I want to go over the code needed to define a DynamoDB Table.

var tableProps = new TableProps
{
    PartitionKey = new Attribute { Name = "name", Type = AttributeType.STRING },
    BillingMode = BillingMode.PAY_PER_REQUEST,
    RemovalPolicy = Amazon.CDK.RemovalPolicy.DESTROY
};

FlagTable = new Table(this, "flags", tableProps); s ", tableProps);
Enter fullscreen mode Exit fullscreen mode

As you can see very little code is needed to actually create a table. This piece of code is defining a table that has a partition key of name that is a string. It is also setting billing mode as pay per request and it is setting the removal policy to destroy, as this is just a prototype, you may want to change this if you plan to production this.

In the snippet below you can see how simple it is to create a lambda.

var lambda = new Function(this, id, new FunctionProps
{
    Runtime = Runtime.DOTNET_6,
    Architecture = Architecture.ARM_64,
    Code = Code.FromAsset("./src/Lambdas/AwsFeatureFlagService.Lambda.Flag/bin/Release/net6.0/linux-arm64/publish"),
    Handler = $"AwsFeatureFlagService.Lambda.Flag::AwsFeatureFlagService.Lambda.Flag.{functionClass}::FunctionHandler",
    Environment = new Dictionary<string, string>
                {
                    { "FlagTableName", FlagTable.TableName }
                },
    Timeout = Amazon.CDK.Duration.Seconds(10)
});

FlagTable.GrantReadWriteData(lambda);
return lambda;
Enter fullscreen mode Exit fullscreen mode

In this case I have made a generic method that will construct a lambda based on the name passed in. This is also setting an environment variable of FlagTableName that is used by the four Lambda to set the correct table to interact with. It is also setting a timeout of 10 seconds on the lambda which can be be increased if the table was to grow in size.

One of my favourite parts about CDK is how easy it is to grant permissions to the services you are using.

Taken from the snippet above, you can see it only takes 1 line of code to achieve this to grant the right permissions on the lambda.
FlagTable.GrantReadWriteData(lambda);

The final snippet is how little code is needed to define API Gateway for this app:

var api = new RestApi(this, "feature-flag-api", new RestApiProps
{
    BinaryMediaTypes = new[] { "*/*" },
    MinimumCompressionSize = 0,
});

var rootPath = api.Root.AddResource("feature-flag");
var flagPath = rootPath.AddResource("{flagName}");

var integration = new LambdaIntegration(lambda);

category.AddMethod("GET", integration, new MethodOptions
{
    RequestParameters = new Dictionary<string, bool>
                {
                    { "method.request.path.flagName", true },
                },
    MethodResponses = new MethodResponse[]
    {
                    new MethodResponse
                    {
                        StatusCode = "200",
                        ResponseParameters = new Dictionary<string, bool>
                        {
                            { "method.response.header.Content-Type", true }
                        }
                    }
    },
    RequestValidator = requestValidator
});
Enter fullscreen mode Exit fullscreen mode

The code above is defining a rest api with a root path used for creating a flag and example here of adding a GET action. Similar code is written for the other 3 actions. This code is also creating a Lambda proxy integration which means the full request is forwarded to the lambda.

Overall I found creating this quite fun, and enjoyed how writing just a bit of code can result in infrastructure being defined without the hassle of needing to define using cloud formation or even creating it myself. Being familiar with both typescript and C# I found the experience to be largely the same and a similar experience to if I had written it in typescript.

As Part 2 I plan to extend this further and include many more serverless services as well bring some Devops teachings into this as a way of getting more familiar with serverless and a more hands on experience seeing it in action which can help towards learning for the developer associate and Devops Professional certifications.

Please take a look at the GitHub Repo for more information and to try it out.

Top comments (0)