-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat(typescript/appsync-dynamodb-join): Appsync dynamodb join example (…
…#1012) * initial commit with cdk setup * added stability in readme * included .js files * excluded test from package.json * main: optimizations for data and dynamodb tables * small readme updates --------- Co-authored-by: oscarwh <[email protected]> Co-authored-by: Michael Kaiser <[email protected]>
- Loading branch information
1 parent
0e41aaa
commit d511933
Showing
17 changed files
with
1,001 additions
and
180 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
!*.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,100 @@ | ||
# AppSync GraphQL API Acting on DynamoDB | ||
# AWS CDK AppSync DynamoDB Table Joining Demo | ||
|
||
<!--BEGIN STABILITY BANNER--> | ||
--- | ||
|
||
![Stability: Experimental](https://img.shields.io/badge/stability-Experimental-important.svg?style=for-the-badge) | ||
![Stability: Stable](https://img.shields.io/badge/stability-Stable-success.svg?style=for-the-badge) | ||
|
||
> **This is an experimental example. It may not build out of the box** | ||
> | ||
> This examples is built on Construct Libraries marked "Experimental" and may not be updated for latest breaking changes. | ||
> **This is a stable example. It should successfully build out of the box** | ||
> | ||
> If build is unsuccessful, please create an [issue](https://github.com/aws-samples/aws-cdk-examples/issues/new) so that we may debug the problem | ||
> This example is built on Construct Libraries marked "Stable" and does not have any infrastructure prerequisites to build. | ||
--- | ||
|
||
<!--END STABILITY BANNER--> | ||
|
||
This an example of an AppSync GraphQL API, pointing to five resolvers doing CRUD operations on a single DynamoDB table. | ||
This project demonstrates how to use AWS CDK (Cloud Development Kit) to create an AWS AppSync API backed by DynamoDB tables. The essence of this project lies in establishing a one-to-many relationship between two tables, where one table stores information about cars, and the other stores information about defects associated with cars. This allows querying both tables together as a sort of nested query. | ||
|
||
## Build | ||
## Table of Contents | ||
- [Overview](#overview) | ||
- [Prerequisites](#prerequisites) | ||
- [Installation](#installation) | ||
- [Usage](#usage) | ||
- [Architecture](#architecture) | ||
|
||
To build this app, you need to be in this example's root folder. Then run the following: | ||
## Overview | ||
|
||
```bash | ||
npm install -g aws-cdk | ||
npm install | ||
npm run build | ||
``` | ||
This project sets up an AWS AppSync API named `carAPI` with two DynamoDB tables: `cardata-cars` and `cardata-defects`. The `cardata-cars` table stores information about cars, while the `cardata-defects` table stores information about defects associated with cars. The AppSync API provides GraphQL endpoints to query and mutate data in these tables. The essence of this project is to enable querying both tables in a nested manner, representing the one-to-many relationship between cars and defects. | ||
|
||
The data used in this project is sourced from public data of RDW (Government agency Dienst Wegverkeer, commonly known as RDW, which handles the type-approval and registration of motorized vehicles and driving licences in the Netherlands). This data used in this project is based on data freely available for use without any restrictions. | ||
|
||
This will install the necessary CDK, then this example's dependencies, and then build your TypeScript files and your CloudFormation template. | ||
## Prerequisites | ||
|
||
## Deploy | ||
Before getting started, ensure you have the following prerequisites: | ||
- Node.js installed (v18.x) | ||
- AWS CDK installed (`npm install -g aws-cdk`) | ||
- AWS CLI configured with appropriate credentials | ||
|
||
Run `cdk deploy`. This will deploy / redeploy your Stack to your AWS Account. | ||
## Installation | ||
|
||
After the deployment you will see the API's URL, which represents the url you can then use. | ||
1. Clone this repository to your local machine. | ||
2. Navigate to the project directory. | ||
3. Install dependencies by running `npm install`. | ||
|
||
## Synthesize Cloudformation Template | ||
## Usage | ||
|
||
To see the Cloudformation template generated by the CDK, run `cdk synth`, then check the output file in the "cdk.out" directory. | ||
To deploy the AWS infrastructure, run the following command: | ||
|
||
## The Component Structure | ||
```bash | ||
cdk deploy | ||
``` | ||
|
||
This Stack contains: | ||
To remove the deployed infrastructure, run: | ||
|
||
```bash | ||
cdk destroy | ||
``` | ||
|
||
The data in the DynamoDB tables can be populated using the utilities provided in `utils/index.js`. It will take a couple of seconds to push all the data to DynamoDB. Execute the following command to populate the tables: | ||
|
||
```bash | ||
npm run push-data | ||
``` | ||
|
||
Once the CDK stack is deployed and the data is ingested into the DynamoDB tables you can query it through the AWS Appsync Console. If you can go to the query tab you can execute the following GraphQL Request: | ||
|
||
```graphql | ||
query GetCar { | ||
getCar(licenseplate: "BR794ZQ3") { | ||
expirydateapk | ||
cylindervolume | ||
catalogprice | ||
defects { | ||
defectdescription | ||
defectstartdate | ||
licenseplate | ||
} | ||
firstcolor | ||
firstregistrationdate | ||
licenseplate | ||
} | ||
} | ||
``` | ||
|
||
- a __GraphQL API__ with an API Key (Use with caution, each key is only valid for 7 days.) | ||
- a __GraphQL Schema__ with Queries to get one and all items and three mutations to save, update and delete an item | ||
- a __DynamoDB table__ `items` that stores the data with a Pay Per Request Billing Mode | ||
- an __AppSync DataSource__, connecting your API to the DynamoDB table. | ||
- an __AppSync Resolver__ for a Query `getOneItem` to get one item from the DynamoDB table. | ||
- an __AppSync Resolver__ for a Query `getAllItems` to get all items from the DynamoDB table. | ||
- an __AppSync Resolver__ for a Mutation `addItem` to put an item into the DynamoDB table (the id is autogenerated, you need only a name). | ||
- an __AppSync Resolver__ for a Mutation `updateItem` to update an item in the DynamoDB table. | ||
- an __AppSync Resolver__ for a Mutation `deleteItem` to delete one item from the DynamoDB table. | ||
## Architecture | ||
|
||
![alt text](appsync-architecture.png) | ||
|
||
The AWS CDK stack defined in `cdk-appsync-demo-stack.ts` sets up the following resources: | ||
- DynamoDB tables: | ||
- `cardata-cars`: Stores information about cars. | ||
- `cardata-defects`: Stores information about defects associated with cars. | ||
- `defects-by-licenseplate` Global Secondary Index (GSI) that allows to query defects by licenseplate | ||
- AppSync API (`carAPI`): | ||
- GraphQL schema defined in `graphql/schema.graphql`. | ||
- Data sources connected to DynamoDB tables. | ||
- Resolvers to query data. | ||
- Resolvers: | ||
- `getCar.js`: Resolver function to fetch cars from the `cardata-cars` table. | ||
- `getDefects.js`: Resolver function to fetch defects associated with cars from the `cardata-defects` table. | ||
|
||
## Costs | ||
The operational expenses associated with deploying this architecture are estimated to be approximately a couple of dollars per month (based on the eu-central-1 region). Cost optimization measures can be implemented by adjusting the write capacity of DynamoDB tables and indexes to a lower setting after the execution of the `npm run push-data` command. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/usr/bin/env node | ||
import 'source-map-support/register'; | ||
import * as cdk from 'aws-cdk-lib'; | ||
import { CdkAppsyncDemoStack } from '../lib/cdk-appsync-demo-stack'; | ||
|
||
const env = { region: 'eu-central-1' }; | ||
const app = new cdk.App(); | ||
new CdkAppsyncDemoStack(app, 'CdkAppsyncDemoStack', { env } ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,63 @@ | ||
{ | ||
"app": "node index" | ||
"app": "npx ts-node --prefer-ts-exts bin/cdk-appsync-demo.ts", | ||
"watch": { | ||
"include": [ | ||
"**" | ||
], | ||
"exclude": [ | ||
"README.md", | ||
"cdk*.json", | ||
"**/*.d.ts", | ||
"**/*.js", | ||
"tsconfig.json", | ||
"package*.json", | ||
"yarn.lock", | ||
"node_modules", | ||
"test" | ||
] | ||
}, | ||
"context": { | ||
"@aws-cdk/aws-lambda:recognizeLayerVersion": true, | ||
"@aws-cdk/core:checkSecretUsage": true, | ||
"@aws-cdk/core:target-partitions": [ | ||
"aws", | ||
"aws-cn" | ||
], | ||
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, | ||
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, | ||
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, | ||
"@aws-cdk/aws-iam:minimizePolicies": true, | ||
"@aws-cdk/core:validateSnapshotRemovalPolicy": true, | ||
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, | ||
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, | ||
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, | ||
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true, | ||
"@aws-cdk/core:enablePartitionLiterals": true, | ||
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, | ||
"@aws-cdk/aws-iam:standardizedServicePrincipals": true, | ||
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, | ||
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, | ||
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, | ||
"@aws-cdk/aws-route53-patters:useCertificate": true, | ||
"@aws-cdk/customresources:installLatestAwsSdkDefault": false, | ||
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, | ||
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, | ||
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, | ||
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, | ||
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, | ||
"@aws-cdk/aws-redshift:columnId": true, | ||
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, | ||
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, | ||
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, | ||
"@aws-cdk/aws-kms:aliasNameRef": true, | ||
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, | ||
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true, | ||
"@aws-cdk/aws-efs:denyAnonymousAccess": true, | ||
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, | ||
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, | ||
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, | ||
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, | ||
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, | ||
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
[ | ||
{ | ||
"licenseplate": { | ||
"S": "87FRABCE" | ||
}, | ||
"brand": { | ||
"S": "BMW" | ||
}, | ||
"tradename": { | ||
"S": "5ER REIHE" | ||
}, | ||
"expirydateapk": { | ||
"N": "20231019" | ||
}, | ||
"firstcolor": { | ||
"S": "GREEN" | ||
}, | ||
"cylindercount": { | ||
"N": "8" | ||
}, | ||
"firstregistrationdate": { | ||
"N": "19980414" | ||
}, | ||
"length": { | ||
"N": "0" | ||
}, | ||
"width": { | ||
"N": "0" | ||
} | ||
}, | ||
{ | ||
"licenseplate": { | ||
"S": "93A5ZR2U" | ||
}, | ||
"brand": { | ||
"S": "BMW" | ||
}, | ||
"tradename": { | ||
"S": "1ER REIHE" | ||
}, | ||
"expirydateapk": { | ||
"N": "20241020" | ||
}, | ||
"firstcolor": { | ||
"S": "BLACK" | ||
}, | ||
"cylindercount": { | ||
"N": "4" | ||
}, | ||
"cylindervolume": { | ||
"N": "1596" | ||
}, | ||
"firstregistrationdate": { | ||
"N": "20041029" | ||
}, | ||
"length": { | ||
"N": "423" | ||
}, | ||
"width": { | ||
"N": "0" | ||
} | ||
}, | ||
{ | ||
"licenseplate": { | ||
"S": "104RZAFB" | ||
}, | ||
"brand": { | ||
"S": "BMW" | ||
}, | ||
"tradename": { | ||
"S": "1ER REIHE" | ||
}, | ||
"expirydateapk": { | ||
"N": "20241004" | ||
}, | ||
"firstcolor": { | ||
"S": "GREY" | ||
}, | ||
"cylindercount": { | ||
"N": "4" | ||
}, | ||
"cylindervolume": { | ||
"N": "1995" | ||
}, | ||
"firstregistrationdate": { | ||
"N": "20050415" | ||
}, | ||
"catalogprice": { | ||
"N": "32826" | ||
}, | ||
"length": { | ||
"N": "423" | ||
}, | ||
"width": { | ||
"N": "0" | ||
} | ||
}, | ||
{ | ||
"licenseplate": { | ||
"S": "BR794ZQ3" | ||
}, | ||
"brand": { | ||
"S": "BMW" | ||
}, | ||
"tradename": { | ||
"S": "5ER REIHE" | ||
}, | ||
"expirydateapk": { | ||
"N": "20231019" | ||
}, | ||
"firstcolor": { | ||
"S": "GREEN" | ||
}, | ||
"cylindercount": { | ||
"N": "8" | ||
}, | ||
"firstregistrationdate": { | ||
"N": "19980414" | ||
}, | ||
"length": { | ||
"N": "0" | ||
}, | ||
"width": { | ||
"N": "0" | ||
} | ||
} | ||
] |
Oops, something went wrong.