Table of Contents
#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.
This will present you with a prompt, go ahead and select 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.
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’.
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.
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.
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.
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.
Go ahead and create a second Post Request with the following JSON body so we have a couple of data sets to play with.
Again if we run the Get Request we can now see we have two datasets.
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.
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.
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.