At the end of February 2020, I set myself an objective: I had to build a “decent” set of components that can be used as a “getting started template” for future projects — named the demo cars app.
Here I am 6 months later: zero new projects, a pandemic, but … Why go back and document now? “Life Is a Journey, Not a Destination” — A famous quote will say, and after those 6 months I decided to write down my learnings, so they can be helpful for a future me and hopefully helpful to others.
Final app link : https://app-democars.cmymesh.com/
Why not using app generators like J Hipster or Spring Initializr?
Demo cars app isn’t a production-ready template that aims to achieve the same objectives as J Hipster or Spring Initializr.
Demo cars app main two objectives of this app template are:
- And have a convenient way o use those technologies in a way which I feel familiar with, we could very well start with J Hipster but the process of application appropriation.
What are the different components of the demo cars applications?
- Back end services https://github.com/craguilar/demo-cars-svc
- Lambda authentication helper service. https://github.com/craguilar/demo-cars-lambda
- UI app . https://github.com/craguilar/demo-cars-ui
Demo cars back end services
This project was created out of sample code coming from AWS CodeStar and a template of a standard Spring boot application , with few extra additions on my side . There is really nothing outstanding about this. The aspects of this app to highlight are:
- Generate Controllers and models based on a Swagger spec . There is a directory api-spec where swagger-carsdemo.yaml is located. More on this next .
- Deployment with AWS Cloud formation. These files (coming from the original AWS CodeStar template) files help application to be deployed in AWS, with minimal to no effort.
Why do I think controllers and models code generation from an API specification is important?
- One important aspect of it is that it helps us prevent doing silly mistakes like typos when creating Java pojos or controllers declarations
- It helps enforce standards in code generation, for something which tends to be a very manual effort.
- It will also be used as an input template when creating the API Gateway resource in AWS API Gateway
- It will help us automatically generate a client in the language of our preference.
How Do I add swagger resources to My Project ?
java -jar ~/bin/swagger-codegen-cli.jar generate -i api-spec/swagger-carsdemo.yaml -l spring -c config/swagger-codegen.json
Deployment with AWS CodeStar
The key files to achieve automatic AWS deployment to EC2 described below , to the original template I added an internal Network Load Balancer (NLB) LoadBalancerWebApp — which will later be used for connectivity between API Gateway and our services
- appspec.yml — this file is used by AWS CodeDeploy when deploying the web service to EC2
- buildspec.yml — this file is used by AWS CodeBuild to build the web service
- scripts/ — this directory contains scripts used by AWS CodeDeploy when installing and deploying your service on the Amazon EC2 instance
- template.yml — this file contains the description of AWS resources used by AWS CloudFormation to deploy your infrastructure
- template-configuration.json — this file contains the project ARN with placeholders used for tagging resources with the project ID
Note: When I tried to recreate the Cloud formation resources for this demo (around 17–18 October 2020), I noticed that resources were not getting created and ended up deleting and recreating a new CodeStar project. This was the easiest way as I recognize that CodeStar is definitely doing a lot of things behind the scenes which I am not fully aware .
API Gateway integration
Now, the demo-cars-svc app is not publicly exposing any endpoint that can be used in our UI , this is as per design . The reason behind this is to expose the service via an API Gateway service which will give benefits such as centralized authentication and authorization, rate limiting , CORS management , etc . so developers can focus on what they know best and stop worrying about infrastructure aspects of service .
To get started with we need to go to AWS API Gateway and use the swagger-carsdemo.yaml as an input to generate an API in AWS API Gateway,
Once we successfully imported the Api specification is time to generate a VPC Link to our app which links to the NLB created during deployment.
Finally, you will need to associate the VPC Link to your endpoints for URL you will need to use the DNS address from the created NLB . Details below.
You can use Amazon API Gateway test functionality to make sure things are working as expected , once you are comfortable with results — deploy API to a stage (see details on https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-deploy-api.html).
At this point, you should have a public NON SECURED endpoint that can be used in your UI application ( if you are not using the same domain for your UI app and your services don’t forget to enable CORS support, you can do this in the API Gateway).
Lambda authentication helper lambda
Let’s secure our endpoints!
There are multiple ways of doing this, two that seems natural are handle authentication directly in our service , or use API Gateway to help us with that .
API Gateway allows you to define authorizers that can be attached to your endpoints and used for authentication/authorization. Those authorizers could either be Lambda functions or a direct integration with Amazon Cognito ( I find Cognito a little bit difficult to use as is a very robust Access Control provider with so many different features that we don’t necessarily need).
I decided to implement a Lambda authorizer in order to give room for future implementations as this could give me flexibility in case I need to change the OAuth 2 provider for something different than Cognito, for example, OAuth2 login from Google account. Following this blog post , I was able to produce a working lambda demo-cars-lambda and deploy it manually using Lambda console.
Once the authorizer is created then you can attach to a particular API Execution (don’t forget to deploy your changes).
Your APIs should be secured using Cognito as an OAuth provider .
If you need to test your app by hitting the endpoint from Postman , you can get a token by calling your OAuth server, you can use below curl command
curl -X POST \
- user yourUser:yourSecet \
-H 'Content-Type: application/x-www-form-urlencoded'
This will give you back a token , which you will need to pass in query parameter “token” when calling your API (you might wonder why a query parameter ? The reason seems to be either at the time of building the Lambda authorizer the header option wasn’t an option or other complication that I might have got when calling it from the UI).
This project was bootstrapped with Create React App . This template uses React Bootsrap for css framework , nothing very interesting about this . Where it gets interesting is the use of AWS Amplify for the UI app deployment and authentication integration with Cognito , you will first need to install the cli
npm install aws-amplify
npm install @aws-amplify/ui
And you can follow the steps on https://docs.amplify.aws/start/q/integration/react or https://aws.amazon.com/getting-started/hands-on/build-react-app-amplify-graphql/module-three/
For demo-cars UI App , we use the pre built UI components for authentication , just be careful that when you do
amplify add auth
And to integrate with Cognito make sure the user pool id and identity pool match the same one you configured on the lamdba authorizer.
Finally, on api-exports.js, change the endpoint to the correct API Gateway endpoint and region.
Push your changes and amplify should take care of the deployment, you can go to the Amplify console, and should look like this
Putting the Pieces Together
After you have deployed your UI App , the lambda is available and the API Gateway is properly configured you can now go to the link available on Amplify console (either login or create a new user) and ..
Securing API Gateway with custom authorizer
AWS API Gateway
Acknowledge and Thanks to
- Async discussion https://blog.bitsrc.io/keep-your-promises-in-typescript-using-async-await-7bdc57041308
- Securing API Gatewat with Cognito https://medium.com/@awskarthik82/part-1-securing-aws-api-gateway-using-aws-cognito-oauth2-scopes-410e7fb4a4c0