Migrate Infrastructure from Serverless Framework to AWS CDK#68
Migrate Infrastructure from Serverless Framework to AWS CDK#68sannidhishukla merged 35 commits intodevfrom
Conversation
| ### Project structure | ||
|
|
||
| The project code base is mainly located within the `src` folder. This folder is divided in: | ||
|
|
||
| - `functions` - containing code base and configuration for your lambda functions | ||
| - `libs` - containing shared code base between your lambdas | ||
|
|
||
| ``` | ||
| . | ||
| ├── src | ||
| │ ├── functions # Lambda configuration and source code folder | ||
| │ │ ├── rating | ||
| │ │ │ ├── handler.ts # `rating` lambda source code | ||
| │ │ │ ├── index.ts # `rating` lambda Serverless configuration | ||
| │ │ │ ├── mock.json # `rating` lambda input parameter, if any, for local invocation | ||
| │ │ │ └── schema.ts # `rating` lambda input event JSON-Schema | ||
| │ │ │ | ||
| │ │ └── index.ts # Import/export of all lambda configurations | ||
| │ │ | ||
| │ └── libs # Lambda shared code | ||
| │ └── apiGateway.ts # API Gateway specific helpers | ||
| │ └── handlerResolver.ts # Sharable library for resolving lambda handlers | ||
| │ └── lambda.ts # Lambda middleware | ||
| │ | ||
| ├── package.json | ||
| ├── serverless.ts # Serverless service file | ||
| ├── tsconfig.json # Typescript compiler configuration | ||
| ├── tsconfig.paths.json # Typescript paths | ||
| └── webpack.config.js # Webpack configuration | ||
| ``` | ||
|
|
||
| This project also contains a `scripts` folder, which contains post-processing Python scripts that help analyze the feedback data. |
There was a problem hiding this comment.
removing this for now. it will be hard to keep up-to-date. we can replace it if needed once all of the major changes forecasted for the feedback widget are complete.
| export async function getLastNComments( | ||
| sheetsClient: sheets_v4.Sheets, | ||
| n: number, | ||
| pageURL: string, | ||
| tabInfo | ||
| ): Promise<string[][]> { | ||
| const { tabName, totalRowsRange, columnMap, isDefault } = tabInfo; | ||
| try { | ||
| const totalRows = await getTotalRows(sheetsClient, totalRowsRange); | ||
| if (totalRows < 2) return []; | ||
| let accumulatedComments = []; | ||
| let commentBatchEnd = totalRows; | ||
| const rightmostColumn = Object.keys(columnMap).reduce((a, b) => | ||
| columnMap[a].index > columnMap[b].index ? a : b | ||
| ); | ||
| while (accumulatedComments.length < n && commentBatchEnd > 1) { | ||
| const commentBatchStart = Math.max(commentBatchEnd - n + 1, 2); | ||
| const result = await sheetsClient.spreadsheets.values.get({ | ||
| spreadsheetId: process.env.SHEET_ID, | ||
| range: `${tabName}!A${commentBatchStart}:${columnMap[rightmostColumn].column}${commentBatchEnd}` | ||
| }); | ||
| let commentBatch = result.data.values ?? []; | ||
| if (commentBatch.length > 0) { | ||
| if (isDefault) { | ||
| commentBatch = commentBatch.filter( | ||
| (v) => | ||
| v[columnMap.pageUrl.index].includes(pageURL) && | ||
| v[columnMap.comment.index] !== undefined | ||
| ); | ||
| } else { | ||
| commentBatch = commentBatch.filter( | ||
| (v) => !!v[columnMap.comment.index] | ||
| ); | ||
| } | ||
| accumulatedComments = commentBatch.concat(accumulatedComments); | ||
| } | ||
| commentBatchEnd = commentBatchStart - 1; | ||
| } | ||
| return accumulatedComments; | ||
| } catch (e) { | ||
| throw Error(`Google Sheets API failed to get input data: ${e.message}`); | ||
| } | ||
| } |
There was a problem hiding this comment.
removed as this was only used by the deprecated /summary endpoint
| // only used within getLastNComments function | ||
| async function getTotalRows(sheetsClient: sheets_v4.Sheets, totalRowRange) { | ||
| try { | ||
| const result = await sheetsClient.spreadsheets.values.get({ | ||
| spreadsheetId: process.env.SHEET_ID, | ||
| range: totalRowRange | ||
| }); | ||
| return parseInt(result.data.values[0][0]); | ||
| } catch (e) { | ||
| throw Error(`Google Sheets API failed to get data size: ${e.message}`); | ||
| } | ||
| } |
There was a problem hiding this comment.
removed as this was only used by the deprecated /summary endpoint
| // eslint-disable-next-line @typescript-eslint/no-var-requires | ||
| const { getSsmParam } = require('./awsUtils'); |
There was a problem hiding this comment.
not sure why but the next line breaks everything if it's switched from require to import
casewalker
left a comment
There was a problem hiding this comment.
I just wanted to do a quick CDK check, things look pretty great! Left some comments, but great work regardless!
src/functions/comment.ts
Outdated
| const { feedbackId, comment, pageURL, rating } = JSON.parse( | ||
| event.body | ||
| ) as Comment; | ||
|
|
There was a problem hiding this comment.
[boulder] Since comment is a required property, we should validate it before entering the try block by adding a guard clause that returns early if it's null or undefined. What do you think?
There was a problem hiding this comment.
just added this!
src/functions/rating.ts
Outdated
| event: APIGatewayProxyEvent | ||
| ): Promise<FeedbackResponse> => { | ||
| const { pageURL, rating } = JSON.parse(event.body) as Rating; | ||
|
|
There was a problem hiding this comment.
[boulder] Since pageURL and rating are required properties, we should validate them before entering the try block by adding a guard clause that returns early if they're null or undefined. What do you think?
AnJuHyppolite
left a comment
There was a problem hiding this comment.
Left a few comments. Great work, @sannidhishukla!
ezhangy
left a comment
There was a problem hiding this comment.
awesome job on this refactor! left some dusts, mostly on the README to clarify how to deploy the API and test it locally
README.md
Outdated
| 2. Run `npm install` (on Node 22, as listed in `.nvmrc`) to install Node dependencies | ||
| 3. Save the credentials from the `Innov-Platform-dev` AWS account to your `~/.aws/credentials` file | ||
| 4. Run the API locally | ||
| 5. In another terminal window, you can test sending commands like the following: |
There was a problem hiding this comment.
[dust] is it possible to add instructions on how to query the dev deployment (in Innov-Platform-dev) instead of from localhost:3000? i feel like being able to do so will be an important manual testing step before promoting to prod while we're still missing test coverage
There was a problem hiding this comment.
yes! i added instructions on sending requests through the lambda console to test (which is what i've been doing)
Overview
This PR contains a number of changes related to migrating the Feedback Widget's AWS infrastructure from Serverless Framework to AWS CDK and moving it into our new Platform-specific AWS accounts
summaryendpoint which would return an AI-generated summary of Feedback Widget comments. This function has not been used and its functionality can be replaced with using the NJ AI AssistantFor more in depth documentation on the changes and resources migrated over, see this document
Next Steps