In this repo we create a table named Product with ID placed the "partition key". We will use the technologies below to create a demo application:
- Terraform to provision DynamoDB table.
- Terraform backend will be in aws:s3 and lock will be kept in the DynamoDB table. So, you need to create s3 bucket for the backend and lock table beforehand.
- Spring Data DynamoDB for DynamoDB repository module.
- Spring has no officially spring data module for DynamoDB and suggests using this External Library in Spring doc.
- Spring Actuator for component and application health status.
- Spring Web for Restful API for CRUD operations.
- Swagger for Rest API documentation.
- JWT Token for API endpoints.
- Docker for containerizing our distribution package.
- Storage Deploy
- Build and push Docker
- Run the application in Local
- Call API endpoints
- Swagger Documentation
- Storage Destroy
In this section we will deploy the storage by using Terraform. We proviosion a DynamoDB table with the following configuration:
resource "aws_dynamodb_table" "product" {
name = "product"
billing_mode = "PAY_PER_REQUEST"
hash_key = "id"
attribute {
name = "id"
type = "S"
}
tags = {
Name = "product"
Environment = "staging"
}
}
To build the storage, we need to run the following command and let the Product table provisioned:
sh deploy/storage/deploy.sh
To build and push the Docker image, we need to run the following command:
sh deploy/backend/api/image/deploy.sh
To run the application, we need to run the following command:
docker run -p 8080:8080 \
-e JWT_SECRET=${JWT_SECRET} \
-e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \
-e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_CESS_KEY} \
docker.io/soyvural/spring-data-dynamodb
- Authenticate and get a JWT token:
- User role can only call "GET /products" and "GET /products/{id}" endpoints.
- So, let's get a JWT token for the admin user and access every endpoint.
curl --location --request POST 'http://localhost:8080/authenticate' --header 'Content-Type: application/json' \
--data-raw '{
"username": "admin",
"password": "pwd"
}''
Response:
{
"token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY0NDg0MDE5NSwiZXhwIjoxNjQ0OTI2NTk1LCJpc3MiOiJjb20ubXZzIn0.D3jONpGmivO_ZrI141LgfC35Hyje_bMW_1D5kzf4_G-xtIH9F4I-FaiyLskZG_tjPUEvQ5O2Xbu-RF2GR3mM7A",
"expiresIn": "Tue Feb 15 12:03:15 UTC 2022"
}
- Call "GET /products" and "GET products/{id}" endpoint:
- We can get all products by calling "GET /products" endpoint.
curl --location --request GET 'http://localhost:8080/api/v1/products' \
--header 'Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY0NDgzMDM3MSwiZXhwIjoxNjQ0OTE2NzcxLCJpc3MiOiJjb20ubXZzIn0.n0DI9SMhYzFKCg7K4atg1iaTEfqR1Td8SEbULin-ybeFsNzd9pScoGjAwKypaV-BRhq1Vr2PiLSg7_KMDgb50w'
Response:
[
{
"id": "869d9b64-6159-4b5b-9fc3-944c6407ad38",
"name": "Iphone 13",
"category": "Mobile Phone",
"price": 134.0
},
{
"id": "de5d47f1-460a-4217-b862-f1b3a9a1fc05",
"name": "Iphone 13",
"category": "Mobile Phone",
"price": 1302.16
}
]
curl --location --request GET 'http://localhost:8080/api/v1/products/de5d47f1-460a-4217-b862-f1b3a9a1fc05' \
--header 'Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY0NDgzMDM3MSwiZXhwIjoxNjQ0OTE2NzcxLCJpc3MiOiJjb20ubXZzIn0.n0DI9SMhYzFKCg7K4atg1iaTEfqR1Td8SEbULin-ybeFsNzd9pScoGjAwKypaV-BRhq1Vr2PiLSg7_KMDgb50w' \
--data-raw ''
Response:
{
"id": "de5d47f1-460a-4217-b862-f1b3a9a1fc05",
"name": "Iphone 13",
"category": "Mobile Phone",
"price": 1302.16
}
- Call "DELETE products/{id}" endpoint:
curl --location --request DELETE 'http://localhost:8080/api/v1/products/7c4d88b0-fb2f-45fe-885f-5a8117972d11' \
--header 'Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY0NDgzMDM3MSwiZXhwIjoxNjQ0OTE2NzcxLCJpc3MiOiJjb20ubXZzIn0.n0DI9SMhYzFKCg7K4atg1iaTEfqR1Td8SEbULin-ybeFsNzd9pScoGjAwKypaV-BRhq1Vr2PiLSg7_KMDgb50w' \
--data-raw ''
Invalid Product Example:
curl --location --request DELETE 'http://localhost:8080/api/v1/products/7c4d88b0-fb2f-45fe-885f-5a81179' \
> --header 'Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiIsImlhdCI6MTY0NDgzMDM3MSwiZXhwIjoxNjQ0OTE2NzcxLCJpc3MiOiJjb20ubXZzIn0.n0DI9SMhYzFKCg7K4atg1iaTEfqR1Td8SEbULin-ybeFsNzd9pScoGjAwKypaV-BRhq1Vr2PiLSg7_KMDgb50w' \
> --data-raw ''
{"timestamp":"2022-02-14T12:21:29.159+00:00","message":"Not found","details":"uri=/api/v1/products/7c4d88b0-fb2f-45fe-885f-5a81179"}
You can populate for put as well.
To access REST API documentation you can use: http://localhost:8080/swagger-ui/
- To access product-api-v1 version 1.0 documentation by using http://localhost:8080/v2/api-docs?group=product-api-v1.0
To destroy the storage, we need to run the following command:
sh deploy/storage/destroy.sh