Skip to content

Commit

Permalink
Update serverless.yml (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
LaurenceHo committed Jun 7, 2024
1 parent 1aee489 commit ed653b0
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 91 deletions.
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ This is a fullstack photo album web app using Vue3, Quasar, Fastify and AWS (inc
function, S3, CloudFront and dynamoDB). You can use this web app to display your photos in S3 bucket and manage your photos. This app
is supposed to be used by a small group of people (e.g. family members) so it doesn't have any user management feature.

For the detailed tutorial, you can check [here](https://dev.to/laurenceho/a-fullstack-vuejs-photo-album-app-part-1-2bgd).
I've written the detailed tutorial on dev.to, you can check [here](https://dev.to/laurenceho/a-fullstack-vuejs-photo-album-app-part-1-2bgd).

### Built With

Expand All @@ -55,12 +55,12 @@ You will need the follows:

1. Google Place API key (For admin manage albums)
2. Google OAuth 2.0 Client ID (For admin access)
3. AWS user and role with appropriate permission
3. AWS user and role with admin permission for your local development and deployment
4. AWS S3 bucket (For SPA website hosting and storing photos)
5. AWS DynamoDB table (For managing album information)
6. AWS Lambda Function with API Gateway
7. AWS CloudFront (It's not necessary)
8. ImageKit account (It's not necessary)
5. AWS DynamoDB table (For managing album information, Serverless framework will create 3 table for you once you run serverless deploy)
6. AWS Lambda Function with API Gateway (Serverless framework will create these for you once you run serverless deploy)
7. AWS CloudFront (It's optional)
8. ImageKit account (It's optional)
9. Mapbox API key (For displaying map)

### Create S3 bucket
Expand Down Expand Up @@ -154,7 +154,12 @@ with your Google account and see the admin page as below:
### AWS Lambda Function

This project uses AWS Lambda Function to handle all APIs (as BFF, backend for frontend) and authentication process
once it's deployed to AWS. Please check further information in the `server` folder. [here](server/README.md)
once it's deployed to AWS. When you run serverless deploy, it will create necessary Lambda Functions, API Gateway and
DynamoDB for you.

‼️ **️Important** ‼️
Before you start local development, you will need to do serverless deploy first. Please check further
information in the `server` folder. [here](server/README.md)

## How to run locally

Expand Down
20 changes: 9 additions & 11 deletions server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ You AWS user needs to have the following permissions:
Permissions for DynamoDB and S3 are required for this project. If you want to use other AWS services, you will need to add more permissions.
3. Serverless deployment permission which involves with various AWS services such as CloudFormation, Lambda and LogGroup

I'd suggest this user has admin permission, restrict it only be used in your local environment.
I'd suggest this user has admin permission, and restrict it only be used in your local environment.

```json
{
Expand All @@ -36,12 +36,9 @@ your real information in`.env.example` and modify file name to `.env`.
### AWS DynamoDB

Replace this properties `PHOTO_ALBUMS_TABLE_NAME`, `PHOTO_ALBUM_TAGS_TABLE_NAME`, `PHOTO_USER_PERMISSION_TABLE_NAME`
and `DATA_AGGREGATIONS_TABLE_NAME` with your real information in`.env.example` and modify file name to `.env`.
When you run Fastify locally, it will use those environment variables to create table and insert mock into your
DynamoDB, so you don't have to create tables manually. You can see the initial dynamodb table in [./src/services/initialise-dynamodb-tables.ts](./src/services/initialise-dynamodb-tables.ts).

Once the tables are created, you can check them in AWS DynamoDB console. After photo album created, you will also need to
create [DynamoDB Stream](https://docs.aws.amazon.com/lambda/latest/dg/with-ddb-example.html) for data aggregation.
and `DATA_AGGREGATIONS_TABLE_NAME` with your the table name you want to use in`.env.example` and modify file name to `.env`.
When you run `npm run serverless:deploy`, it will use those environment variables to create tables, so you don't have to
create tables manually. Once the tables are created, you can check them in AWS DynamoDB console.

#### ElectroDB

Expand Down Expand Up @@ -71,6 +68,7 @@ $ npm run start:server
## Use serverless-http to wrap Fastify app

Assume you already have a Fastify app, you can use `serverless-http` to wrap it and deploy to AWS Lambda and Api Gateway.
You can find my detailed tutorial [here](https://dev.to/laurenceho/from-expressjs-to-fastify-45d4).

Firstly, install serverless-http

Expand Down Expand Up @@ -196,14 +194,14 @@ You can check your AWS Lambda function in AWS console. You should see a new Lamb

### AWS Permissions

If you deploy your Lambda function running the above command `npm run serverless:deploy`, Serverless Framework will deal
with AWS permissions for you as long as you set up the correct DynamoDB table names and S3 bucket name.
If you deploy your Lambda function and API Gateway by running the above command `npm run serverless:deploy`, Serverless
Framework will deal with AWS permissions for you as long as you set up the correct DynamoDB table names and S3 bucket name.

### Enabling binary support using the API Gateway console

Next, you need to enable binary support using the API gateway console. Otherwise, the uploaded photos will be corrupted.
I dug around in Serverless Framework doc, and I couldn't find a way to configure serverless.yml to enable binary support.
It means we have to enable it using AWS admin console.
Unfortunately, there is no way to configure serverless.yml to enable binary support. It means we have to enable it
using AWS admin console.

1. Go to API Gateway console -> Select your API -> API Settings -> Binary Media Types -> Click "Manage media types"
2. Add `image/*` and `multipart/form-data` to the list of binary media types
Expand Down
64 changes: 60 additions & 4 deletions server/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ provider:
plugins:
- serverless-plugin-typescript
- serverless-dotenv-plugin
- ./src/serverless-plugins/get-dynamodb-stream-arn.cjs

useDotenv: true

Expand All @@ -60,12 +59,68 @@ functions:
handler: src/aggregations/albums.handler
events:
- stream:
arn: ${fetchStreamARN(${env:PHOTO_ALBUMS_TABLE_NAME})}
startingPosition: LATEST
enabled: true
type: dynamodb
arn:
Fn::GetAtt: [AlbumTable, StreamArn]

resources:
Resources:
AlbumTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${env:PHOTO_ALBUMS_TABLE_NAME}
AttributeDefinitions:
- AttributeName: pk
AttributeType: S
- AttributeName: sk
AttributeType: S
KeySchema:
- AttributeName: pk
KeyType: HASH
- AttributeName: sk
KeyType: RANGE
ProvisionedThroughput:
ReadCapacityUnits: 4
WriteCapacityUnits: 4
DeletionProtectionEnabled: true
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
StreamSpecification:
StreamViewType: KEYS_ONLY
AlbumTagTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${env:PHOTO_ALBUM_TAGS_TABLE_NAME}
AttributeDefinitions:
- AttributeName: tag
AttributeType: S
KeySchema:
- AttributeName: tag
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 4
WriteCapacityUnits: 1
DeletionProtectionEnabled: true
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
UserPermissionTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${env:PHOTO_USER_PERMISSION_TABLE_NAME}
AttributeDefinitions:
- AttributeName: uid
AttributeType: S
- AttributeName: email
AttributeType: S
KeySchema:
- AttributeName: uid
KeyType: HASH
- AttributeName: email
KeyType: RANGE
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
DeletionProtectionEnabled: true
AggregationTable:
Type: AWS::DynamoDB::Table
Properties:
Expand All @@ -79,6 +134,7 @@ resources:
ProvisionedThroughput:
ReadCapacityUnits: 4
WriteCapacityUnits: 4
DeletionProtectionEnabled: true

custom:
dotenv:
Expand Down
4 changes: 0 additions & 4 deletions server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { app } from './app.js';
import { uploadObject } from './controllers/helpers.js';
import { initialiseDynamodbTables } from './services/initialise-dynamodb-tables.js';
import S3Service from './services/s3-service.js';

try {
await initialiseDynamodbTables();
console.log('Finish verifying DynamoDB tables.');

const s3Service = new S3Service();

const exists = await s3Service.checkObject({ Bucket: process.env.AWS_S3_BUCKET_NAME, Key: 'updateDatabaseAt.json' });
Expand Down
65 changes: 0 additions & 65 deletions server/src/serverless-plugins/get-dynamodb-stream-arn.cjs

This file was deleted.

0 comments on commit ed653b0

Please sign in to comment.