Using Swift in the AWS Cloud can take many forms. Here we will focus on a serverless, multi-regional setup. The aim here is to demonstrate how the infrastructure elements fit together to make a distributed API. You will come away from this with a working serverless, multi-regional Swift based API served by AWS Lambda.
This project is part of a series that includes other useful elements. For more information see the Swift in the Cloud Series.
With the templates provided, you can create and extend your API to be as close to your users as possible by installing infrastructure in each region of your choosing. In real time, user requests will be routed to the region with the lowest latency from their location.
You are not limited to two (2) regions. You can add as many regions as support the underlying infrastructure as you require. NB: so far Jakarta, Hyderabad and Osaka do not support the API Gateway V2 HTTP APIs used in these templates.
To complete this setup you will need:
- An AWS account with administrative user access
- An unused domain name to setup with Route53
- Xcode 14+
- Docker 4+
- AWS CLI
This project will make use of AWS services. As the consumer of those services you are responsible for understanding what costs will be incurred. AWS Billing can be complicated. Most services have a free tier offering but you can easily blow past that if you do not understand how it works. I would suggest that at a minimum, you take a look at two options:
- Learn how to manage your AWS billing with Budgets.
- Create a billing alarm so that you are notified as your charges rack up.
You can further explore the cost structure of each service that is used in this exercise. Most should only incur charges when the API is being consumed, the exception being Route53 which charges a prorated monthly fee for hosting a domain name ($0.50 per domain at the time of writing).
Having said that, all other charges to get this example up and running should be covered by the free tier if you account qualifies.
Service | Usage | Pricing Page |
---|---|---|
Cloudformation | templates defining infrastructure | https://aws.amazon.com/cloudformation/pricing/ |
Route53 | DNS hosting | https://aws.amazon.com/route53/pricing/ |
Lambda | serverless on demand compute | https://aws.amazon.com/lambda/pricing/ |
IAM | authentication management | https://aws.amazon.com/iam/ |
Certificate Manager | SSL certificate management | https://aws.amazon.com/certificate-manager/pricing/ |
API Gateway | redundant HTTP gateway management | https://aws.amazon.com/api-gateway/pricing/ |
CloudWatch | logging and metrics management | https://aws.amazon.com/cloudwatch/pricing/ |
Two skeleton Swift projects are used to provide you with sample apps to be installed and run as each Lambda.
Lambda App | Usage | Repository |
---|---|---|
Swift Lambda Authorizer | allow/deny incoming requests | https://github.com/khinkson/SwiftLambdaAuthorizer |
Swift Lambda API | answer API requests | https://github.com/khinkson/SwiftLambdaAPI |
Before you get going, know that these instructions were used to setup a live API using the same code and templates shown here. There are more details on how to access this API after the setup instructions. As in the live sample API, the same parameters used will be used throughout the instructions below. When you see the list of parameters below, replace them with your appropriate variable where necessary. The default values in the Cloudformation templates will be the values used in the live demo
Property Name | Value | Usage |
---|---|---|
Cloudformation Role Name | SwiftCloudformationRole |
No need to change. |
Operations Stack Name | operations-stack |
No need to change. If you do, change it everywhere. |
WildcardCertificateDomainName | swiftdemo0.flew.cloud |
Replace with your own domain name. |
S3LambdaCodeSourceBucketNamePrefix | swiftdemo0 |
Final bucket name appends the region name eg: swiftdemo0-us-east-2 . |
S3LambdaSourceCodeKeyPath | SwiftLambdaAPI/lambda.zip or SwiftLambdaAAuthorizer/lambda.zip |
No need to change. |
- Log into your AWS console account as a user with administrative permissions and select
IAM
from the main services menu. - From the IAM dashboard, select
Roles
from the menu. - Click the Create Role button. On the resulting page choose trusted entity type
AWS Service
. From the use cases, chooseCloudFormation
. Hit next, and in the Add Permission table search for and selectAdministratorAccess
. - Hit next and name the role
SwiftCloudformationRole
. - Click the Create Role button.
It is usually inadvisable to give such broad access to any role or user within IAM . Ideally you should narrow that access permissions to only what is needed by the Cloudformation templates. However, there are a large number of permissions that are required to make these templates work. So for now we will start with a broad permission set.
- From the AWS Console, select
Route53
from the main services menu. - From the Route53 dashboard, select
hosted zones
from the menu. - Click the
Create hosted zone
. - Enter your domain name as a public hosted zone and complete the creation process.
- Click on the domain name to see the DNS entries. Look for the DNS entry type
NS
— it will list your name servers. - If using a 3rd party domain name provider, go to their dashboard and update the domain name with the new name servers. See your providers documentation if you require assistance. NB: These changes may take some time to propagate and become available.
Requirements:
- the Zone ID of your domain name from Route53
- choose your open or authorized subdomain for the wildcard certificate
Steps:
- Select
Cloudformation
from the main services menu. - If necessary change to the region where you want to setup the infrastructure. NB: Graviton/Arm based lambdas are not available in all regions. If you wish to run ARM only you should check here first to see if Arm CPUs are available in your regions. Once on that page, scroll down to where the pricing is listed and choose
Arm price
. Select the region to see a list of regions in which Arm is available. - Click
Create Stack
(with new Resources if asked) - With template ready, choose to upload the template using the project file 0-operations-stack.json. Hit next.
- Enter the stack name
operations-swiftdemo0-stack
. For the parameters enter the Zone ID of your domain name and the wildcard domain name to use without the astericks prefix. Eg: sayflew.cloud
is you domain, enterswiftdemo0.flew.cloud
to get*.swiftdemo0.flew.cloud
domain depending on your choice of open or authorized domain. The wildcard is used because additional domains are created for each region. Click next. - Under IAM role choose the previously created
SwiftCloudformationRole
. - Under
Stack creation options
enableTermination protection
. Click next. - Check:
I acknowledge that AWS CloudFormation might create IAM resources with custom names.
- Submit. Wait for the this stack to complete creation. The wildcard certificate is created and domain name validation occurs automatically using Route53. This may take more than a few minutes to complete.
You have already made your choice as to open or authorized API access. You can install an open access API that anyone can use or one that requires authorization. Skip the authorizer step if you want an open API. Remember to use the same domain name chosen for the wildcard certificate.
Requirements:
- Go to the SwiftLambdaAuthorizer project and follow the instructions on how to build and upload your swift lambda authorizer package.
- the name of your S3 bucket and keyPath where you uploaded the swift lambda authorizer package.
Steps:
- From Cloudformation, click
Create Stack
(with new Resources if asked) - With template ready, choose to upload the template using the project file 2.1-authorizer-stack.json. Hit next.
- Enter the stack name
authorizer-swiftdemo0-stack
. For the parameters enter the Zone ID of your domain name. Fill out the rest of the parameters listed. Click Next. - Under IAM role choose the previously created
SwiftCloudformationRole
. - Under
Stack creation options
enableTermination protection
. Click next. - Check:
I acknowledge that AWS CloudFormation might create IAM resources with custom names
. - Submit. Wait for the this stack to complete creation. This may take more than a few minutes to complete.
Requirements:
- the Zone ID of your domain name from Route53.
- the name you entered for the operations stack (
operations-swiftdemo0-stack
if you followed the instructions above). - Go to the SwiftLambdaAPI project and follow the instructions on how to build and upload your swift lambda API package.
- the name of your S3 bucket and keyPath where lambda source code package was uploaded.
- From Cloudformation, click
Create Stack
(with new Resources if asked). Choose only one (1) of the following:- Open Access Version: With template ready, choose to upload the template using the project file 2-lambda-open-access-stack.json. Hit next. OR
- Authorization Required Version: With template ready, choose to upload the template using the project file 2.1-lambda-authorization-required-stack.json. Hit next.
- For the authorization required API, enter the stack name
authorizedapi-swiftdemo0-stack
. For the open access API enter the nameopenapi-swiftdemo0-stack
. For the parameters enter the Zone ID of your domain name, choose a subdomain prefix for the wildcard API domain. For this example we will chooseopenapi
orauthapi
for the parameter APIDomainPrefix. This will result inopenapi.swiftdemo0.flew.cloud
orauthapi.swiftdemo0.flew.cloud
as our API domain. Fill out the rest of the parameters listed. Click Next. - Under IAM role choose the previously created
SwiftCloudformationRole
. - Under
Stack creation options
enableTermination protection
. Click next. - Check off:
I acknowledge that AWS CloudFormation might create IAM resources with custom names
. - Submit. Wait for the this stack to complete creation. This may take more than a few minutes to complete.
Once complete you should be able to send a request to your API domain to see if it is working. There are two domains setup for each regional API. https://openapi.swiftdemo0.flew.cloud routes you to the nearest region by latency. In this case there is only one region setup. To access a specific region follow the format — https://openapi.us-east-2.swiftdemo0.flew.cloud to access the API infrastructure in us-east-2 (Ohio). Of course replace the region and domain name appropriately to match your setup.
To create another infrastructure stack in a different region, repeat the steps starting from C. Install the Cloudformation Templates
in a new region using the same domain name and prefix parameters. You can then test the domain name latency routing or reach each specific region if necessary.
The APIs, both open and requiring authorization have been setup for anyone who wants to see what the latency is like. These are here to give you an idea of what you can expect from this setup. Both APIs were installed on a fresh AWS account following the exact instructions here. Note: if these APIs get a lot of abuse I will be forced to take them down. To get the curl timing to display, follow the instructions in this SO answer. Both APIs were warmed up first by running a few requests and the authorizer was, and is set to cache it's results for an hour. This test run was not comprehensive. Your results will vary.
A successful response looks like this and should contain the region so you know which one you were routed to:
curl "https://openapi.swiftdemo0.flew.cloud/hello"
{"created":"2023-01-11T18:49:01.386Z","description":"We said hello.","id":"2806E285-ACA9-4E3E-9045-6067334307E8","region":"us-east-2","title":"Hello"}
Region | Domain |
---|---|
closest by latency | openapi.swiftdemo0.flew.cloud |
us-east-2 (Ohio) | openapi.us-east-2.swiftdemo0.flew.cloud |
us-west-2 (Oregon) | openapi.us-west-2.swiftdemo0.flew.cloud |
eu-west-2 (London) | openapi.eu-west-2.swiftdemo0.flew.cloud |
eu-central-1 (Frankfurt) | openapi.eu-central-1.swiftdemo0.flew.cloud |
ap-southeast-1 (Singapore) | openapi.ap-southeast-1.swiftdemo0.flew.cloud |
sa-east-1 (São Paulo) | openapi.sa-east-1.swiftdemo0.flew.cloud |
ap-northeast-1 (Tokyo) | openapi.ap-northeast-1.swiftdemo0.flew.cloud |
From an EC2 instance in us-east-2 (Ohio) to the Open SwiftLambdaAPI in us-east-2 (Ohio) — approximately 37ms to get a response:
curl -w "@curl-format.txt" \
-o /dev/null \
-s "https://openapi.swiftdemo0.flew.cloud/hello"
DNS Lookup: 0.001086s
Remote Host Connect: 0.001606s
SSL Handshake: 0.010577s
Pretransfer Setup: 0.010671s
Any Redirects: 0.000000s
First Byte Transfer: 0.037326s
----------
Total: 0.037417s
Region | Domain |
---|---|
closest by latency | authapi.swiftdemo0.flew.cloud |
us-east-1 (N. Virginia) | authapi.us-east-1.swiftdemo0.flew.cloud |
us-west-1 (California) | authapi.us-west-1.swiftdemo0.flew.cloud |
eu-west-1 (Ireland) | authapi.eu-west-1.swiftdemo0.flew.cloud |
ap-south-1 (Mumbai) | authapi.ap-south-1.swiftdemo0.flew.cloud |
eu-west-3 (Paris) | authapi.eu-west-3.swiftdemo0.flew.cloud |
ap-southeast-2 (Sydney) | authapi.ap-southeast-2.swiftdemo0.flew.cloud |
ap-northeast-2 (Seoul) | authapi.ap-northeast-2.swiftdemo0.flew.cloud |
From an EC2 instance in us-east-1 (N. Virginia) to the Authorization Required SwiftLambdaAPI in us-east-1 (N. Virginia) — approximately 40ms to get a response:
curl -w "@curl-format.txt" \
-o /dev/null \
-s "https://authapi.swiftdemo0.flew.cloud/hello" \
-H 'Content-Type: application/json' \
-H 'Authorization: SKOcSFZd8pKoZ24WXYK2dSEc5Nf2eao9QOOvpPYM'
DNS Lookup: 0.001171s
Remote Host Connect: 0.002046s
SSL Handshake: 0.011209s
Pretransfer Setup: 0.011324s
Any Redirects: 0.000000s
First Byte Transfer: 0.040475s
----------
Total: 0.040564s
As mentioned above this project is part of the Swift in the Cloud Series. The next step in the series deals with DynamoDB — a multi-regional database (key value NOSQL database) that you can use in conjunction with the multi-regional lambda API.
Time will bring changes to this project. To really make this setup robust, it can be improved by adding:
- Allow templates to be reused to build multiple APIs in the same account/region
- Automated continuous integration/deployment (CI/CD) (AWS Pipeline)
- A firewall for filtering malicious traffic (AWS Web Application Firewall)
- Automated failover to reroute traffic to healthy regions (Route53 DNS Health Checks)
- Detailed metrics collection, aggregation and analysis (AWS CloudWatch)
- Possibly convert the templates to a StackSet (AWS Cloudformation)
- Overall automation via the AWS CLI
AWS Swift Multi-Region API is released under the Apache License, Version 2.0. See LICENSE for details.