Skip to content

Commit

Permalink
Moving from direct integration with DynamoDB to Lambda
Browse files Browse the repository at this point in the history
Lesson learned, if you need to deal with DDB just use a function so you can handle the marshalling and unmarshalliung of DDB items
  • Loading branch information
tmclaugh committed Oct 21, 2024
1 parent bdf3163 commit d7d53ac
Show file tree
Hide file tree
Showing 10 changed files with 6,373 additions and 260 deletions.
112 changes: 40 additions & 72 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,79 +1,47 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Dev
.mypy_cache/

# pyenv / environments
.python-version
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
*.swp

# Coverage reports
coverage

# API keys and secrets
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# IDE
.settings/
.project
.pydevproject
.vscode/
*.code-workspace
.idea/

# Mac Cruft
# Dependency management
.yarn
!.yarn/patches
!.yarn/releases
!.yarn/plugins
!.yarn/sdks
!.yarn/versions
.pnp.*
node_modules

# Editors
.idea
*.iml

# OS metadata
.DS_Store
Thumbs.db

# Deploy
codepipeline-config-*.yaml
# Ignore Typescript build output
dist

# ignore yarn.lock
#yarn.lock

# IDE
.vscode
!.vscode/launch.json
!.vscode/tasks.json

# AWS SAM
.aws-sam/
.aws-sam
1 change: 1 addition & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
8 changes: 8 additions & 0 deletions jest.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"testEnvironment": "node",
"transform": {
"^.+.tsx?$": ["ts-jest",{}]
},
"modulePathIgnorePatterns": ["<rootDir>/dist/", "<rootDir>/.aws-sam"],
"collectCoverage": true
}
194 changes: 13 additions & 181 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ paths:
content:
application/json:
schema:
$ref: "#/components/schemas/EmptyResponse"
$ref: "#/components/schemas/CreateEntityResponse"
'400':
description: Client failure
content:
Expand All @@ -118,141 +118,10 @@ paths:
- serverlessOpsCognitoPool:
- Fn::Sub: https://${Hostname}/catalog.write
x-amazon-apigateway-integration:
type: AWS
type: AWS_PROXY
httpMethod: POST
uri:
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:dynamodb:action/BatchWriteItem"
credentials:
Fn::Sub: ${RestApiIamRole.Arn}
passthroughBehavior: NEVER
requestTemplates:
"application/json":
# FIXME: This doesn't handle nessted maps and arrays.
Fn::Sub: |
#set ($root=$input.path('$'))
#if ($root.namespace != '')
#set($namespace = $root.metadata.namespace)
#else
#set($namespace = "default")
#end
#set($kind = $root.kind.toLowerCase())
#set($name = $root.metadata.name)
{
"RequestItems": {
"${DdbTable}": [
{
"PutRequest": {
"Item": {
"pk": {
"S": "$namespace/$kind"
},
"sk": {
"S": "$namespace/$kind/$name"
},
"itemType": {
"S": "entity"
},
"apiVersion": {
"S": "$root.apiVersion"
},
"kind": {
"S": "$root.kind"
},
"metadata": {
"M": {
#foreach($pair in $root.metadata.entrySet())
#if( $pair.value.class.name == "java.lang.String" )
"$pair.key": {
"S": "$pair.value"
}#if($foreach.hasNext),#end
#elseif( $pair.value.class.name == "net.minidev.json.JSONArray" )
"$pair.key": {
"L": [
#foreach($item in $pair.value)
{
"S": "$item"
}#if($foreach.hasNext),#end
#end
]
}#if($foreach.hasNext),#end
#elseif( $pair.value.class.name == "java.util.LinkedHashMap" )
"$pair.key": {
"M": {
#foreach($subpair in $pair.value.entrySet())
"$subpair.key": {
"S": "$subpair.value"
}#if($foreach.hasNext),#end
#end
}
}#if($foreach.hasNext),#end
#end
#end
}
},
"spec": {
"M": {
#foreach($pair in $root.spec.entrySet())
#if( $pair.value.class.name == "java.lang.String" )
"$pair.key": {
"S": "$pair.value"
}#if($foreach.hasNext),#end
#elseif( $pair.value.class.name == "net.minidev.json.JSONArray" )
"$pair.key": {
"L": [
#foreach($item in $pair.value)
{
"S": "$item"
}#if($foreach.hasNext),#end
#end
]
}#if($foreach.hasNext),#end
#elseif( $pair.value.class.name == "java.util.LinkedHashMap" )
"$pair.key": {
"M": {
#foreach($subpair in $pair.value.entrySet())
"$subpair.key": {
"S": "$subpair.value"
}#if($foreach.hasNext),#end
#end
}
}#if($foreach.hasNext),#end
#end
#end
}
}
}
}
}
]
}
}
responses:
"2\\d{2}":
statusCode: 201
responseTemplates:
"application/json": |
{}
"4\\d{2}":
statusCode: 400
responseTemplates:
"application/json": |
{
"message": "$input.path('$.Message')"
}
"5\\d{2}":
statusCode: 500
responseTemplates:
"application/json": |
{
"message": "$input.path('$.Message')"
}
default:
statusCode: 502
responseTemplates:
"application/json": |
{
"message": "$input.path('$.Message')"
}
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${CreateEntityFunction.Arn}/invocations"

"/catalog/{namespace}/{kind}":
get:
Expand Down Expand Up @@ -408,57 +277,20 @@ paths:
- serverlessOpsCognitoPool:
- Fn::Sub: https://${Hostname}/catalog.read
x-amazon-apigateway-integration:
type: AWS
type: AWS_PROXY
httpMethod: POST
uri:
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:dynamodb:action/GetItem"
credentials:
Fn::Sub: ${RestApiIamRole.Arn}
passthroughBehavior: NEVER
requestTemplates:
"application/json":
Fn::Sub: |
{
"TableName": "${DdbTable}",
"Key": {
"pk": {
"S": "$input.params('namespace')/$input.params('kind')"
},
"sk": {
"S": "$input.params('namespace')/$input.params('kind')/$input.params('name')"
}
},
"ProjectionExpression": "apiVersion, kind, metadata, spec"
}
responses:
"2\\d{2}":
statusCode: 200
responseTemplates:
"application/json": |
$input.json('$.Item')
"4\\d{2}":
statusCode: 400
responseTemplates:
"application/json": |
{
"message": "$input.path('$.Message')"
}
"5\\d{2}":
statusCode: 500
responseTemplates:
"application/json": |
{
"message": "$input.path('$.Message')"
}
default:
statusCode: 502
responseTemplates:
"application/json": |
{
"message": "$input.path('$.Message')"
}
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetEntityFunction.Arn}/invocations"

components:
schemas:
CreateEntityResponse:
type: object
properties:
request_id:
type: string
required:
- request_id
EmptyResponse:
type: object
ErrorResponse:
Expand Down
Loading

0 comments on commit d7d53ac

Please sign in to comment.