#3 Creating My First Lambda Rest API

#3 Creating My First Lambda Rest API

In this blog were going to create the frame work of a simple Rest API and test it locally within our solution that we started in the previous two blogs about this topic. This will also introduce a new tool call Postman https://www.postman.com/ which is an application that helps you test Rest API.

So lets get started.

Download Postman Desktop App

We will use the Postman Desktop app to help us test our Visual Studio code, before we publish it to AWS Lambada.

Once you navigate in your browser to the Postman website, you will have to create an account, or login to an existing account. Once your account is created and you have logged in select Workspaces->My Workspace from the top menu bar.

My Workspaces

This will present you with a prompt, go ahead and select Download Desktop Agent.

Download Desktop Agent

Once you have downloaded the Postman app, and installed it, we will now edit the Visual Studio code.

Serverless Template

To maintain the solution so that it will still publish to our Lambda, we have to declare the end points within the serverless template as shown below. It’s important to know that each Event must have a unique name and the end point URL paths must also be unique well get into more complex paths later on.

        "Events": {
                    "GetEvent": {"Type": "Api", "Properties": {"Path": "/v1/DataModel","Method": "GET"}},
                    "PutEvent": {"Type": "Api", "Properties": {"Path": "/v1/DataModel","Method": "POST"}},
                    "PostEvent": {"Type": "Api", "Properties": {"Path": "/v1/DataModel","Method": "PATCH"}},
                    "DeleteEvent": {"Type": "Api", "Properties": {"Path": "/v1/DataModel","Method": "DELETE"}}
            }

Models

Within the Visual Studio Project add a new Project Folder called ‘Models’ and create two classes called ‘ChangeDataModelRequest’ and ‘DataModel’. These will be used to manage the data coming to and from our Rest API.

Model Classes

The first model we will create is the ‘DataModel’ that will have three attributes; FirstName, LastName, and Age.

namespace MyFirstLambdaProject.Models
{
    public class DataModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
    }
}

Then the ‘ChangeDataModelRequest’ that will contain an ‘Original’ DataModel and a ‘ToBe’ DataModel.

namespace MyFirstLambdaProject.Models
{
    public class ChangeDataModelRequest
    {
        public DataModel Original { get; set; }
        public DataModel ToBe { get; set; }
    }
}

Processor

Before we update our controller lets build out the Processor. To do this lets add a project folder called ‘Processor’ containing an Interface called ‘IDataModelProcessor’ and a class called ‘DataModelProcessor’.

Processor Interface and Class

IDataModelProcessor

Let’s start with the Interface for our Data model Processor, this will contain the definitions for the four Rest API end points GET, Post, Patch and Delete. The Get method will return a list of all Data Models, Post will post a JSON model and return the model once its successfully stored, Path will allow a Change Data Model Request to be made and return the Changed Data Model, and the Delete will allow a Data Model to be past so that it can be deleted from storage and will return a Boolean on successful completion of the delete.

using MyFirstLambdaProject.Models;

using System.Collections.Generic;

namespace MyFirstLambdaProject.Processors
{
    public interface IDataModelProcessor
    {
        IEnumerable<DataModel> GetDataModel();
        DataModel PostDataModel(DataModel iDataModel);
        DataModel PatchDataModel(ChangeDataModelRequest iChangeDataModelRequest);
        bool DeleteDataModel(DataModel iDataModel);
    }
}

DataModelProcessor

The ‘DataModelProcessor’ will implement the ‘IDataModelProcessor’. Since we will not publish this to the AWS Lambda we will ne a place to store the models while we test the Rest API end points, to do this we will create a List of DataModels. We will also create three private helper method that will help us manage the data; ContainsDataModel, GetDataModelFromDataList, and GetDataModelIndexFromDataList. These in a future blog will be modified to interact with the database.

using MyFirstLambdaProject.Models;

using System.Collections.Generic;
using System.Linq;

namespace MyFirstLambdaProject.Processors
{
    public class DataModelProcessor : IDataModelProcessor
    {
        List<DataModel> _DataList = new List<DataModel>();

        private bool ContainsDataModel(DataModel iDataModel)
        {          
            return (GetDataModelFromDataList(iDataModel) != null);
        }

        private DataModel GetDataModelFromDataList(DataModel iDataModel)
        {
            DataModel ReturnDataModel = null;
            ReturnDataModel = (from x in this._DataList
                           where x.FirstName.Equals(iDataModel.FirstName) &&
                           x.LastName.Equals(iDataModel.LastName) &&
                           x.Age == iDataModel.Age
                           select x).FirstOrDefault();
            return ReturnDataModel;
        }

        private int GetDataModelIndexFromDataList(DataModel iDataModel)
        {
            int ReturnInt = 0;
            if(this.ContainsDataModel(iDataModel) == true)
            {
                ReturnInt = this._DataList.FindIndex(
                    x => x.FirstName.Equals(iDataModel.FirstName) &&
                    x.LastName.Equals(iDataModel.LastName) &&
                    x.Age == iDataModel.Age
                    );
            }
            return ReturnInt;
        }
    }
}
Get

The Get method will simply return the private member list.

        public IEnumerable<DataModel> GetDataModel()
        {
            return this._DataList;
        }
Post

The Post method will first check to see if the private data member list contains a definition of the DataModel, if it does not then the DataModel will be added to the private data member list.

        public DataModel PostDataModel(DataModel iDataModel)
        {
            DataModel ReturnDataModel = null;
            if (this.ContainsDataModel(iDataModel) == false)
            {
                this._DataList.Add(iDataModel);
                ReturnDataModel = iDataModel;
            }
            return ReturnDataModel;
        }
Patch

The Patch method will first check to see if the private data member list contains a definition of the Original DataModel, if it does then it will be removed and the ToBe DataModel added to the private data member list,a nd the ToBe Datamodel will be returned.

        public DataModel PatchDataModel(ChangeDataModelRequest iChangeDataModelRequest)
        {
            DataModel ReturnDataModel = null;
            if (this.ContainsDataModel(iChangeDataModelRequest.Original) == true)
            {
                this._DataList.RemoveAt(this.GetDataModelIndexFromDataList(iChangeDataModelRequest.Original));
                this._DataList.Add(iChangeDataModelRequest.ToBe);
                ReturnDataModel = iChangeDataModelRequest.ToBe;
            }
            return ReturnDataModel;
        }
Delete

The Delete method will first check to see if the private data member list contains a definition of the DataModel, if it does then it will be removed, and a true Boolean result returned.

        public bool DeleteDataModel(DataModel iDataModel)
        {
            bool ReturnBoolean = false;
            if (this.ContainsDataModel(iDataModel) == true)
            {
                this._DataList.RemoveAt(this.GetDataModelIndexFromDataList(iDataModel));
                ReturnBoolean = true;
            }
            return ReturnBoolean;
        }

Controller

Now we have the processor created we can update the controller. Within the ‘ValuesController’ we will first create a ReadOnly private data member for the ‘IDataModelProcessor’, and a constructor that will be used by dependency injection which we will cover later on.

using System;

using Microsoft.AspNetCore.Mvc;

using MyFirstLambdaProject.Models;
using MyFirstLambdaProject.Processors;

namespace MyFirstLambdaProject.Controllers
{
    public class ValuesController : ControllerBase
    {
        private readonly IDataModelProcessor _IDataModelProcessor;

        public ValuesController(IDataModelProcessor iDataModelProcessor)
        {
            this._IDataModelProcessor = iDataModelProcessor;
        }
	    //End Point Definitions Go Here
    }
}

Next well create an end point in the controller for each of our Rest API, that refers to the Data Processor.

Get

        [HttpGet("/v1/DataModel")]
        public IActionResult Get()
        {
            try
            {
                return Ok(this._IDataModelProcessor.GetDataModel());
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

Post

       [HttpPost("/v1/DataModel")]
        public IActionResult Post([FromBody] DataModel DataModel)
        {
            try
            {
                return Ok(this._IDataModelProcessor.PostDataModel(DataModel));
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

Patch

        [HttpPatch("/v1/DataModel")]
        public IActionResult Patch([FromBody] ChangeDataModelRequest ChangeDataModel)
        {
            try
            {
                return Ok(this._IDataModelProcessor.PatchDataModel(ChangeDataModel));
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

Delete

        [HttpDelete("/v1/DataModel")]
        public IActionResult Delete([FromBody] DataModel DataModel)
        {
            try
            {
                return Ok(this._IDataModelProcessor.DeleteDataModel(DataModel));
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

Dependency Injection

Finally in the StartUp.cs file we need to update the ‘ConfigurationServices’ method to create a Singleton instance of our Data Model Processor.

        using MyFirstLambdaProject.Processors;

	    public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            services.AddSingleton<IDataModelProcessor, DataModelProcessor>();
        }

Now we can test our Rest API’s.

Rest API Testing

We are going to test this locally because we don’t yet have a database connection to our RDS MySQL database. Se we will get the guts working then start adding in Secrets Manager, API gateway, and RDS MySQL.

To start our app we will select the Play Button in Visual Studio, which will start a local copy of IIS Express, on a local port.

Local Debug

When IIS starts it will open a browser window where the URL is localhost with a port number. Lets’ copy this as its the root URL for testing our Rest API.

Local Host Port Number

Launch the Postman Desktop app, and create a new Get Request where the URL is a combination of the local host and the end point of the Rest API. If we run this since we have not created any Post transactions yet the list will be empty and as a result the returned result will be empty. So let’s hold off for one sec.

Postman Get Request

We will create an additional tab, this time for a Post Request, using the same URL as the Get Request. This time we will also specify the Body as a Raw JSON body as shown below. If we run this request then run the Get Request then we should see some data stored in the List.

Postman Post Request

Go ahead and create a second Post Request with the following JSON body so we have a couple of data sets to play with.

Postman Post Request

Again if we run the Get Request we can now see we have two datasets.

Postman Get Request

We will create an additional tab, this time for a Patch Request, using the same URL as the Get and Post Requests. Again it will contain JSON Body that defines a Change Request consisting of two DataModel’s. This request is allowing us to change an existing dataset by changing the age of the person.

Postman Patch Request

We will create an additional tab, this time for a Delete Request, using the same URL as the Get, Post, and Patch Requests. Also with a JSON Body, that defines a specific model within the list to delete.

Postman Delete Request

Now we have the foundation of our Lambda Rest service.

Next we will have to create a Database connection to our RDS MySQL Database, so we can read and write data to a Database Table.