This is a C# solution to provide a RESTful web API for simple airport information.
AWS Service Involved | Purpose | Free Tier Limit |
---|---|---|
DynamoDB | Store airport information | Free forever on free tier AWS, as long as storage is under 25GB and read/write requests under 200 million per month |
Elastic Beanstalk | to serve the Web API using EC2 instances | Free only for first 12 months on free tier AWS. The EC2 instances that Beanstalk uses are priced at EC2 prices, so recommend using t2.micro or t3.micro EC2 instances because it is free for first 12 months at under 750 hours of usage per month |
This guide goes through the process of setting up the AWS services required for this application.
This guide assumes that
- you're using Visual Studio 2022 on Windows
- you have .NET 6.0 installed
- you have AWS Toolkit for Visual Studio installed
- you have an AWS account (AWS Free Tier or otherwise)
- you have cloned this repo
Create a new IAM user with Administrator access
If you don't already have a IAM user with administrator access already, you should create one now.
First, login to your AWS account on the website and search for the IAM service on the top bar.
As we can see, we don't have any users yet, so click the Add Users button on the top right
Set the User name as vsuser
and tick the Access key - Programmatic access checkbox because we want to access this user with our Visual Studio AWS SDK. Then click the bottom right Next: Permissions button.
Go to the Attach existing Policies tab and tick the administratorAccess checkbox, this allows the vsuser
user to have complete access for all AWS services, including creating DynamoDB database or Elastic Beanstalk. Then click the bottom right Next: Tags button.
Leave the tags empty and click the Next: Review button.
Here we can see the user being created has user name of vsuser
, AWS access type of Programmatic access - with an access key, permissions summary managed policy of AdministratorAccess. Click Create user button.
Now the new user vsuser
has been successfully created, be sure to click the Download .csv button to save the credentials CSV file onto your local hard drive. We will use this CSV file later when we need to sign in to vsuser
through the Visual Studio 2022 AWS SDK.
Going back to the Users page, we see that the new user vsuser
has indeed been successfully created.
Visual Studio AWS Profile Sign In
Open up Visual Studio, if you have installed the AWS Toolkit for Visual Studio correctly, you should see this option in View > AWS Explorer
Click to open AWS Explorer and you should see this button (Add AWS Credentials Profile), click it.
Then fill in the correct details in the pop up window:
- Profile name, could be anything but for simplicity sake let's keep it
vsuser
- Import from CSV file and select the CSV file with the credentials you've downloaded in the Create IAM user with administrator access in the previous section
- Set the Region to your region
- click OK.
After that, the profile should be signed in to the AWS Explorer, and all the AWS services would be available through the AWS Explorer in Visual Studio.
One thing to note is that appsettings.Development.json
has the content:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AWS": {
"Profile": "vsuser",
"Region": "eu-west-2"
}
}
where
AWS.Profile
of"vsuser"
should be matching the profile name, andAWS.Region
of"eu-west-2"
should be matching your region
So if you chose a different profile name or region, be sure to adjust the appsettings.Development.json
accordingly.
Create new DynamoDB airports table
Now that the AWS Explorer has profile vsuser
connected, it's time to create a new DynamoDB table for airports.
Before we begin, notice that the Models/Airport.cs
class has the content:
using Amazon.DynamoDBv2.DataModel;
namespace AirportAPI.Models;
[DynamoDBTable("airports")]
public class Airport
{
[DynamoDBHashKey("code")]
public string? Code { get; set; }
[DynamoDBProperty("name")]
public string? Name { get; set; }
[DynamoDBProperty("city")]
public string? City { get; set; }
}
where the
[DynamoDBTable("airports")]
defines that the DynamoDB table should have the name "airports"
, so when we create the DynamoDB table, it should have the name airports.
Also notice that the hash key name is "code"
by this line in Models/Airport.cs
[DynamoDBHashKey("code")]
To create the airports table, open AWS Explorer, right click on Amazon DynamoDB and click Create Table...
A window pops up for creating new DynamoDB Table:
- set the Table Name as airports
- set the Hash Key Name as code, with Hash Key Type as String
- Click Create
Now after creating this new DynamoDB table, we can see it under the Amazon DynamoDB in the AWS Explorer
Double clicking on the airports table opens it up, and shows an empty table
Also, if open the AWS website and go to the DynamoDB page, you can see the airports table there
Test Run the Web API locally
Now that DynamoDB table airports has been created, you should now be able to run the Web API locally and test out the endpoints on swagger.
First, click on the AirportAPI button to run it in debug mode.
It should open up a new page for Swagger, listing all the endpoints.
Sending a GET request to the /api/Airport
endpoint would initially respond with empty list of airports, []
, with status code of 200
But if it responds with error message instead, then it's likely because some AWS configuration weren't set properly. It could be:
- The AWS user (say
vsuser
) didn't have permission to access DynamoDB. Go to IAM service page on AWS and add the permission to have AdministratorAccess which would certainly grant it access to DynamoDB.- The AWS user did have permission to access DynamoDB, but it was not configured correctly in
appsettings.Development.json
. Go toappsettings.Development.json
and make sure the attributes under"AWS"
were set appropriately for the user profile, it could be the"Profile"
not matching or the"Region"
not matching.- The DynamoDB table name not matching the table name of
"airports"
specified inModels/Airport.cs
.Or it could be something else entirely, try to resolve that before proceeding to next step.
Next, we could send a POST request to the /api/Airport
endpoint to create a new airport in the DynamoDB airports table.
For example, sending a POST request with request body
{
"code": "MAN",
"name": "Manchester Airport",
"city": "Manchester"
}
would create this new airport item in the airports table
Next, you can try all the endpoints, they should all work as expected.
action | endpoint | what it does |
---|---|---|
GET |
/api/Airport |
Get a list of all airports |
GET |
/api/Airport/{code} |
Get airport with matching airport code to {code} |
POST |
/api/Airport |
Create new airport, where request body should contain info (in json format) of new airport |
PUT |
/api/Airport |
Update airport, where request body should contain info (in json format) of the updated airport |
DELETE |
/api/Airport/{code} |
Delete airport with matching airport code to {code} |
Publish to AWS Elastic Beanstalk
Now that we have tested the endpoints locally, we're ready to publish this web API onto AWS Elastic Beanstalk.
On Solution Explorer, we see the AirportAPI project,
right click on the AirportAPI project and click Publish to AWS
This opens up the Publish to AWS: AirportAPI page, select ASP.NET Core App to AWS Elastic Beanstalk on Linux and click the Edit settings button
Most of the default settings are correct, just change 2 things:
- Environment Type to Load Balancer, this allows elastic beanstalk to use multiple EC2 instances to serve up the web API, where the EC2 instances will be placed in some auto scaling group to scale appropriately to traffic. Elastic beanstalk will use a Load Balancer to direct the requests to different EC2 instances.
- EC2 Instance Type to t3.micro because it is within the free tier (for 12 months) and is sufficiently powerful to support our web API.
Then click the Publish button to publish onto Elastic Beanstalk.
Then it would take a few minutes to publish the web API onto Elastic Beanstalk. Eventually the process will finish.
Click on the endpoint will open up the elastic beanstalk hosted website.
All seems to be working alright, but actually if we go to the /api/Airport
endpoint (on browser, so it would be GET
request), it actually doesn't load (500 internal server error
)
This is because the EC2 instances of Elastic Beanstalk don't have the correct permission to access the DynamoDB airports table.
We can grant them the permission to access the table by go to the IAM service > Roles
We can see one of the latest roles has Role name of AirportAPI-....
and has Trusted entities of AWS Service: ec2
. This is the role used by the EC2 instances of the Elastic Beanstalk that hosts our endpoints.
Click it and we see this role only has Permissions Policies relating to Elastic Beanstalk, this is why it doesn't have access to DynamoDB tables. We can grant it permission by clicking Add permissions > Attach policies
Then search for policies dynamodb and tick the AmazonDynamoDBFullAccess policy, and click the bottom right button Attach policies
Now that the new DynamoDB access policy is attached to the EC2 instances of Elastic Beanstalk, wait a few seconds and try the /api/Airport
again, and we should see that it works.
You can also go to /swagger
endpoint to easily test out all the endpoints, they should all work as expected. 🎉
Delete Elastic Beanstalk Instance
Now that we've successfully published our local Web API onto Elastic Beanstalk, it is time to turn it off, shut it down, before we forget about it 12 months later and start getting charged for those EC2 instances.
To delete the elastic beanstalk, go to AWS Explorer > AWS Elastic Beanstalk > AirportAPI, right click > Delete
This deletion process would take a few minutes, eventualy we can check on the AWS website > Elastic Beanstalk and see the application for AirportAPI-dev
deleted.
Feel free to also do the same deletion to the DynamoDB airports table, and the IAM roles for Elastic Beanstalk.