I am trying to deploy a DynamoDB stream as a lambda function using AppSync and Serverless. The deployment goes well, without any error. But when I trigger the lambda creating a new instance in my DynamoDB table, it fails throwing this error:
{
"errorType": "Runtime.ImportModuleError",
"errorMessage": "Error: Cannot find module 'onCreateRadonData'\nRequire stack:\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js",
"stack": [
"Runtime.ImportModuleError: Error: Cannot find module 'onCreateRadonData'",
"Require stack:",
"- /var/runtime/UserFunction.js",
"- /var/runtime/index.js",
" at _loadUserApp (/var/runtime/UserFunction.js:100:13)",
" at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)",
" at Object.<anonymous> (/var/runtime/index.js:43:30)",
" at Module._compile (internal/modules/cjs/loader.js:999:30)",
" at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)",
" at Module.load (internal/modules/cjs/loader.js:863:32)",
" at Function.Module._load (internal/modules/cjs/loader.js:708:14)",
" at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)",
" at internal/main/run_main_module.js:17:47"
]
}
It is strange because, usually, I see this happens when importing some modules/dependencies in a bad way. But the function mentioned in the error onCreateRadonData is the name of the lambda itself, and in the deployment process, it is clearly shown that the deployment of the function went well, so I do not know what is going on...
The serverless.yaml file:
service: aws
plugins:
- serverless-appsync-plugin
- serverless-offline
provider:
name: aws
runtime: nodejs12.x
region: eu-west-1
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:Scan
- dynamodb:Query
- dynamodb:PutItem
Resource:
- !GetAtt RadonDataTable.Arn
- !Join [ '', [ !GetAtt RadonDataTable.Arn, '/*' ] ]
- Effect: Allow
Action:
- appsync:GraphQL
Resource:
- !GetAtt GraphQlApi.Arn
- !Join [ '/', [ !GetAtt GraphQlApi.Arn, 'types', 'Mutation', 'fields', 'createRadonData' ] ]
custom:
appSync:
name: ${self:service}
authenticationType: AWS_IAM
mappingTemplates:
- dataSource: RadonData
type: Query
field: listRadonData
request: Query.listRadonData.request.vtl
response: Query.listRadonData.response.vtl
- dataSource: None
type: Mutation
field: createRadonData
request: Mutation.createRadonData.request.vtl
response: Mutation.createRadonData.response.vtl
schema: src/schema.graphql
dataSources:
- type: NONE
name: None
- type: AMAZON_DYNAMODB
name: RadonData
description: 'DynamoDB Radon Data table'
config:
tableName: !Ref RadonDataTable
functions:
handleDynamoDbStream:
maximumRetryAttempts: 1
maximumRecordAgeInSeconds: 1
handler: src/handlers/onCreateRadonData.handler
environment:
APP_SYNC_API_URL: !GetAtt GraphQlApi.GraphQLUrl
events:
- stream:
type: dynamodb
arn: !GetAtt RadonDataTable.StreamArn
resources:
Resources:
RadonDataTable:
Type: AWS::DynamoDB::Table
Properties:
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
StreamSpecification:
StreamViewType: NEW_IMAGE
And the lambda function onCreateRadonData.ts:
export const handler = (event) => {
console.log('Hello from lambda')
return;
}
NOTE: I've also tried the exports.handler = (event) ... way, but I throws the same error.
The code structure goes like this:
- src/handlers/onCreateRadonData.ts
- mapping-templates/files with mapping templates.vtl
- serverless.yml
- package.json
As You can see I have only one file named onCreateRadonData.ts inside the handlers folder in src. Thats all, the rest of the files are in the root directory.
Any ideas of what I am doing wrong? thank You all!
Okey guys I got it. Since I am using typescript I have to import the serverless-typescript plugin to convert all the ts files to js.
Related
I am trying to deploy a serverless app on AWS cloud formation but I am getting a regular expression pattern error
Error:
CREATE_FAILED: UsersDynamoDBTable (AWS::DynamoDB::Table)
1 validation error detected:Value 'users-table-dev'' at 'tableName' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z0-9_.-]+** (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: 9OBFJ6RG2SKVIE58UTVAMNV7V7VV4KQNSO5AEMVJF66Q9ASUAAJG; Proxy: null)
What I can do to fix this?
# serverless.yml
service: serverless-flask
plugins:
- serverless-python-requirements
- serverless-wsgi
custom:
tableName: 'users-table-${self:provider.stage}'
wsgi:
app: app.app
packRequirements: false
pythonRequirements:
dockerizePip: non-linux
provider:
name: aws
runtime: python3.6
stage: dev
region: us-east-1
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
- { "Fn::GetAtt": ["UsersDynamoDBTable", "Arn" ] }
environment:
USERS_TABLE: ${self:custom.tableName}
functions:
app:
handler: wsgi.handler
events:
- http: ANY /
- http: 'ANY {proxy+}'
resources:
Resources:
UsersDynamoDBTable:
Type: 'AWS::DynamoDB::Table'
Properties:
AttributeDefinitions:
-
AttributeName: userId
AttributeType: S
KeySchema:
-
AttributeName: userId
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
TableName: ${self:custom.tableName}
I am trying to implement the code here build a rest api with serverless lambda dynamo
For anybody experiencing the same issue, take a look at the tableName property. Instead of having the single quotes the line should look like that
tableName: `users-table-${self:provider.stage}`
Had the same minor error, it is easy to be overlooked.
i'm trying to figure out the best way to define response/request models for my Lambda functions and API Gateway.
What am I trying to achieve?
What I want is to store all my models within my git repo for requests and responses, these will be deployed to API Gateway using the serverless-aws-documentation plugin.
So let's say there is a 500/400 error, the response would be formatted using this model, not the code. Let's focus on the error response, this should be like so:
"Error": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"type": {
"type": "string"
},
"request-id": {
"type": "string"
}
}
}
What I currently have
Below is what I have right now, which creates the models on my API Gateway just fine, however i'm currently formatting the response within code, ideally I would just throw an exception here and let the model handle for formatting?
unresolvedVariablesNotificationMode: error
useDotenv: true
provider:
name: aws
profile: ${opt:aws-profile, 'sandbox'}
region: eu-west-2
stage: ${opt:stage, 'dev'}
lambdaHashingVersion: 20201221
environment:
TABLE_PREFIX: ${self:provider.stage}-${self:service}-
API_ROOT: ${self:custom.domains.${self:provider.stage}}
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:DescribeTable
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
- Fn::GetAtt:
- enquiriesTable
- Arn
- Fn::GetAtt:
- vehiclesTable
- Arn
plugins:
- serverless-api-gateway-throttling
- serverless-associate-waf
# - serverless-domain-manager
- serverless-reqvalidator-plugin
- serverless-aws-documentation
- serverless-webpack
- serverless-dynamodb-local
- serverless-offline
custom:
apiGatewayThrottling:
maxRequestsPerSecond: 10
maxConcurrentRequests: 5
webpack:
includeModules: true
dynamodb:
stages: [ dev ]
start:
migrate: true
documentation:
models:
-
name: "ErrorResponse"
description: "This is how an error would return"
contentType: "application/json"
schema: ${file(models/Error.json)}
functions:
createEnquiry:
handler: src/services/enquiries/create.handler
environment:
API_ROOT: ${self:custom.domains.${self:provider.stage}}
events:
- http:
path: /
method: POST
reqValidatorName: onlyParameters
documentation:
requestModels:
"application/json": "CreateRequest"
methodResponses:
-
statusCode: "400"
responseModels:
"application/json": "ErrorResponse"
resources:
Resources:
onlyParameters:
Type: "AWS::ApiGateway::RequestValidator"
Properties:
Name: "only-parameters"
RestApiId:
Ref: ApiGatewayRestApi
ValidateRequestBody: true
ValidateRequestParameters: true
enquiriesTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:provider.stage}-${self:service}-enquiries
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
vehiclesTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:provider.stage}-${self:service}-vehicles
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
Can someone point me in the right direction to achieve what i'm attempting. So to have the models defined within the repo, and have these define the response rather than the Node.
Update
Just attempted the following from this link:
functions:
createEnquiry:
handler: src/services/enquiries/create.handler
environment:
API_ROOT: ${self:custom.domains.${self:provider.stage}}
events:
- http:
path: /
method: POST
reqValidatorName: onlyParameters
x-amazon-apigateway-integration:
responses:
".*httpStatus\\\":404.*":
statusCode: 404,
responseTemplates:
application/json: "#set ($errorMessageObj = $util.parseJson($input.path('$.errorMessage')))\n#set ($bodyObj = $util.parseJson($input.body))\n{\n \"type\" : \"$errorMessageObj.errorType\",\n \"message\" : \"$errorMessageObj.message\",\n \"request-id\" : \"$errorMessageObj.requestId\"\n}"
export const handler: APIGatewayProxyHandler = async (event) => {
return {
statusCode: 400,
body: 'Enquiry already exists'
}
This still just returned the following response as a string:
Enquiryalreadyexists
I am building a rest api with lambda and dynamodb.
I am typing sls deploy in the terminal which should deploy my function to aws but it gives me a syntax error and does not say where the error is.
Another file is create using the yml file which aws uses but I am posting the yml file as it is easier to read.
This is the yml file. I have been tinkering with it to get the syntax right but it still is not working.
The exact error is:
An error occurred: IamRoleLambdaExecution - Syntax errors in policy. (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument; Request ID: b089926b-6d47-4111-9710-e3b6987fd8d7).
I can post the other file instead if that would make it easier to solve. Can anyone find the flaw in this file?
service: sls
custom:
settings:
POSTS_TABLE: posts
provider:
name: aws
runtime: nodejs12.x
environment: ${self:custom.settings}
region: eu-west-2
iamRoleStatements:
- Effect: "Allow"
Action:
- dynamodb: DescribeTable
- dynamodb: Scan
- dynamodb: GetItem
- dynamodb: PutItem
- dynamodb: UpdateItem
- dynamodb: DeleteItem
Resource:
- "arn:aws:dynamodb:${self:provider.region}:*:table/${self:custom.settings.POSTS_TABLE}"
functions:
createPost:
handler: handler.createPost
events:
- http:
path: /post
method: post
resources:
Resources:
PostsTable:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
- AttributeName: "id"
AttributeType: "S"
KeySchema:
- AttributeName: "id"
KeyType: "HASH"
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
TableName: ${self:custom.settings.POSTS_TABLE}
A Likely reason is that correct actions names don't have spaces. Thus, instead of
- dynamodb: DescribeTable
- dynamodb: Scan
- dynamodb: GetItem
- dynamodb: PutItem
- dynamodb: UpdateItem
- dynamodb: DeleteItem
it should be
- dynamodb:DescribeTable
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Facing Syntax IamRoleLambdaExecution - Syntax errors in policy. (Service: AmazonIdentityManagement; Status Code: 400; Error Code: MalformedPolicyDocument; Request ID: ********-****-****-****-************).
for the below serverless.yml file.
plugins:
- serverless-pseudo-parameters
provider:
name: aws
runtime: nodejs8.10
iamRoleStatements:
- Effect: Allow
Action:
- "dynamodb:PutItem"
- "dynamodb:GetItem"
Resource:
- arn:aws:dynamodb:#{AWS::Region}:#{AWS::AccountId}:table/ordersTable
- Effect: Allow
Action:
- kinesis: "PutRecord"
Resource:
- arn:aws:kinesis:#{AWS::Region}:#{AWS::AccountId}:stream/order-events
functions:
createOrder:
handler: handler.createOrder
events:
- http:
path: /order
method: post
environment:
orderTableName: ordersTable
orderStreamName: order-events
resources:
Resources:
orderEventsStream:
Type: AWS::Kinesis::Stream
Properties:
Name: order-events
ShardCount: 1
orderTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ordersTable
AttributeDefinitions:
- AttributeName: "orderId"
AttributeType: "S"
KeySchema:
- AttributeName: "orderId"
KeyType: "HASH"
BillingMode: PAY_PER_REQUEST```
serverless details:
- Framework Core: 1.71.3
- Plugin: 3.6.12
- SDK: 2.3.0
- Components: 2.30.11
Based on OP's feedback in the comment, changing kinesis: "PutRecord" to "kinesis: PutRecord" should work.
provider:
name: aws
runtime: nodejs8.10
environment: ${self:custom.settings.${self:custom.myStage}}
plugins:
- serverless-webpack
- serverless-dynamodb-local
package:
individually: true
custom:
webpack:
webpackConfig: ./webpack.config.js
includeModules: true
myStage: ${opt:stage, self:provider.stage}
settings:
dev:
ITEMS_DYNAMODB_TABLE: sls-basic-operations-items-dev
prod:
ITEMS_DYNAMODB_TABLE: sls-basic-operations-items-prod
iamRoleStatements:
- Effect: "Allow"
Action:
- "dynamodb:GetItem"
- "dynamodb:PutItem"
- "dynamodb:UpdateItem"
- "dynamodb:DeleteItem"
- "dynamodb:ListStreams"
Resource:
- "arn:aws:dynamodb:${self:provider.region}:*:table/${self:custom.settings.${self:custom.myStage}.ITEMS_DYNAMODB_TABLE}"
# you can overwrite defaults here
stage: dev
region: us-east-1
functions:
saveItem:
handler: handler.saveItem
events:
- http:
path: item
method: post
triggerStream:
handler: handler.triggerStream
events:
- stream:
type: dynamodb
batchSize: 1
startingPosition: LATEST
arn:
Fn::GetAtt:
- ImagesTable
- StreamArn
resources:
Resources:
ImagesTable:
Type: "AWS::DynamoDB::Table"
Properties:
AttributeDefinitions:
- AttributeName: "itemId"
AttributeType: "S"
KeySchema:
- AttributeName: "itemId"
KeyType: "HASH"
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
TableName: ${self:custom.settings.${self:custom.myStage}.ITEMS_DYNAMODB_TABLE}
StreamSpecification:
StreamViewType: NEW_IMAGE
The above YAML file I provided . I tried to connect with AWS Dynamo DB using AWS LAMBDA. But once I upload the project and tried to call save item function through postman it gives the following log on AWS cloud watch. I gave the both full administrative and dynamo DB access to the IAM User. Actually I am new to AWS and pardon my English
UnhandledPromiseRejectionWarning: AccessDeniedException: User: arn:aws:sts::247618643673:assumed-role/aws-nodejs-dev-us-east-1-lambdaRole/aws-nodejs-dev-saveItem is not authorized to perform: dynamodb:PutItem on resource: arn:aws:dynamodb:us-east-1:247618643673:table/sls-basic-operations-items-dev
at Request.extractError (/var/task/node_modules/aws-sdk/lib/protocol/json.js:51:27)
at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:683:14)
at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/var/task/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /var/task/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:38:9)
at Request.<anonymous> (/var/task/node_modules/aws-sdk/lib/request.js:685:12`enter code here`)
Your IAM role definitions should be configured under provider and not as a root property in your serverless.yml.
provider:
name: aws
runtime: nodejs8.10
environment: ${self:custom.settings.${self:custom.myStage}}
iamRoleStatements:
- Effect: "Allow"
Action:
- "dynamodb:GetItem"
- "dynamodb:PutItem"
- "dynamodb:UpdateItem"
- "dynamodb:DeleteItem"
- "dynamodb:ListStreams"
Resource:
- "arn:aws:dynamodb:${self:provider.region}:*:table/${self:custom.settings.${self:custom.myStage}.ITEMS_DYNAMODB_TABLE}"
If you want to be more granular, you can also put that in the function level.