Adding the Real Database
Learn about the integration of the database with our project.
We'll cover the following...
Database integration
Now we are ready to add the database to our system. First, we will update our infrastructure.
// ...Globals:Function:Runtime: nodejs12.xHandler: main.handlerEnvironment:Variables:ENVIRONMENT: !Ref EnvironmentDATABASE_NAME: !Ref ReservationsDbResources:CreateLambda:Type: AWS::Serverless::FunctionProperties:MemorySize: 512Timeout: 15CodeUri: lambdas/create/dist/create.zipPolicies:- AWSLambdaExecute- Version: "2012-10-17"Statement:- Effect: AllowAction:- "dynamodb:*"Resource:- "*"Events:Api:Type: ApiProperties:Path: /createMethod: POSTRestApiId: !Ref ServerlessRestApiRetrieveLambda:Type: AWS::Serverless::FunctionProperties:MemorySize: 512Timeout: 15CodeUri: lambdas/retrieve/dist/retrieve.zipPolicies:- AWSLambdaExecute- Version: "2012-10-17"Statement:- Effect: AllowAction:- "dynamodb:*"Resource:- "*"Events:Api:Type: ApiProperties:Path: /retrieveMethod: GETRestApiId: !Ref ServerlessRestApi// rest of the file unchanged```
Explanation
- Line 10: We now add another environment variable that injects the name of the database into the Lambdas.
- Lines 21–27 and 43–49: We give both our Lambdas permission to do anything they want with our DynamoDB databases. For better security, we can limit this to one resource (the specific database created in this file) and we can find out what DynamoDB calls we need. For example, our Create Lambda would need a
PutItem
permission.
Add the aws-sdk
to the dev dependencies of both our Lambdas:
"devDependencies": {"@types/jest": "^26.0.14","aws-sdk": "2.828.0"}
While these are provided by AWS when running a Lambda (and don’t have to be packaged with the rest of our dependencies), they’re still needed and useful for local development.
Create gateway
folder
The first thing we’ll do is create a new folder called gateway
, similar to the naming of our previous project. Inside it, we create a file, similar to the previous chapter, a very simple call to an external service.
import {DynamoDB} from "aws-sdk";import {DocumentClient} from "aws-sdk/lib/dynamodb/document_client";import PutItemInput = DocumentClient.PutItemInput;const client = new DynamoDB.DocumentClient({region: 'eu-west-1'});export const save = (params: PutItemInput) => {return client.put(params).promise();};
Note: Be careful not to create the
DocumentClient
directly. Otherwise, TypeScript won’t be able to handle theDocumentClient
type gracefully.
Now, we can rewrite our databaseTest.
import {mocked} from 'ts-jest/utils'; import {saveToDatabase} from "../src/specifics/database"; import {CreateReservationPricedRequest} from "../../../util/domain/types"; import {save} from "../src/gateway/awsCalls"; import {DocumentClient} from "aws-sdk/lib/dynamodb/document_client"; import PutItemOutput = DocumentClient.PutItemOutput; jest.mock("../src/gateway/awsCalls"); describe('id generation', () => { // stays the same }); describe('save', () => { beforeEach( () => { mocked(save as any).mockClear(); }); it('should save and then return an enriched event', async () => { const mockSave = mocked(save as any) .mockImplementation((): Promise<PutItemOutput> => { return Promise.resolve({}); }); const startDate = new Date(2020, 11, 10, 12, 0, 0); const dayLater = new Date(2020, 11, 11, 12, 0, 0); const exampleRequest: CreateReservationPricedRequest = { hotelId: '1', userId: '10', start: startDate, end: dayLater, price: 20, timestamp: startDate, }; await saveToDatabase(exampleRequest); expect(mockSave.mock.calls).toHaveLength(0); }); });
This is similar to the kind of testing we performed ...