For a recent client project, I wrote up my typical end-to-end workflow when implementing a feature in an AWS AppSync project in order to show developers new to the tech stack what all’s involved in the process. I’ve shared a summary of this below in case you find it useful (or have suggestions for improving it 🙂).
I’ll not go into much technical detail or share code samples, but if you have further questions on a specific item, just hit reply.
The feature in question is to allow users to update their profile, which is stored in DynamoDB. I’ve highlighted my Git commit checkpoints with the ⛳️ emoji.
- Create a new local Git branch off
mainfor the feature:
- Add a new GraphQL mutation
updateMyProfileto the AppSync GraphQL schema file
- Run codegen to generate types and operations from the schema (see GraphQL codegen for AppSync projects)
- Keep a background terminal window open with TypeScript watch always running (
tsc -w). I use VSCode’s “Split Terminal” for this.
- Spec out E2E test case stubs for happy and failure paths using Jest’s
it.todo(see Spec your tests before writing them). ⛳️
- Implement each of these E2E test cases in turn. Each test will invoke the API to verify the behaviour of the new mutation as well as creating any necessary setup data (e.g. test user in Cognito with an auth token). ⛳️
- Authenticate with AWS SSO in terminal via
aws sso login
- Deploy stack to my personal stack in the dev AWS account using Serverless Framework with stage=‘ps’ (my initials)
- Run E2E tests and verify that they fail (since resolver not yet implemented)
- Write a new Lambda function
updateUserProfilecontaining the implementation logic for the mutation resolver. (This could potentially have been a VTL template but Lambda makes it easier to implement the more complex conditional update logic required and IMHO doing writes in VTL makes it harder to ensure data integrity)
- Implement the code that writes to a DynamoDB table inside an
updatefunction inside the
user-profile.repo.tslibrary module. Call this new function from the Lambda handler. ⛳️
- Write the configuration to wire up the Lambda resolver to the new AppSync mutation (via serverless-appsync-plugin configuration. This is currently quite a verbose process as changes need to be made in 3 places, but v2 of this plugin will make this much simpler via inline data sources. ⛳️
- Configure the requisite IAM permissions to the Lambda function (to update the DynamoDB table where users are stored). ⛳️
- Re-deploy the stack to the dev AWS account.
- Run the E2E test cases to ensure they now pass.
- If there are failures, check the logs in AWS CloudWatch via the excellent Cloudash desktop app.
- Iterate on the fix-deploy-test loop until all tests pass. ⛳️
- Pull latest remote changes from
mainand rebase my local branch off this. ⛳️
- Re-run all tests to ensure they still pass.
- Push branch to GitHub and create a Pull Request.
- Read through the changed files in GitHub’s PR viewer. If there are any refactorings I notice (or things like redundant TODO comments or temporary logging statements), go through the fix-deploy-test loop again.
- Once happy, tag any reviewers in GitHub who I’d like to review the PR.
- From here on, the CI/CD workflows kick in (I use GitHub Actions for these).
Some notes on this workflow:
- For certain features that have sufficiently complex logic in my code, I would add unit tests for these (before implementing the Lambda handler or library function that contains this complex logic).
- I use the lint-staged plugin as a Git hook to automatically run ESLint and Prettier formatting before my local Git commits can proceed.
Indie Cloud Consultant helping small teams learn and build with serverless.
Learn more how I can help you here.
Join daily email list
I publish short emails like this on building software with serverless on a daily-ish basis. They’re casual, easy to digest, and sometimes thought-provoking. If daily is too much, you can also join my less frequent newsletter to get updates on new longer-form articles.