I am trying to send a custom Response header from my API, I tried using events.response.statusCodes but it is not working, looks like it was only implemented for http but not for httpApi event.
functions:
myfunction:
name: test
handler: src/index.handler
events:
- httpApi:
path: /graphql
method: post
response:
statusCodes:
200:
headers:
Strict-Transport-Security: "'max-age=31536000'"
500:
headers:
Strict-Transport-Security: "'max-age=31536000'"
you are corrrect that it hasn't been implemented for httpApi. It is supported by HTTP API on AWS level though, so you can override manually properties of created AWS::ApiGatewayV2::Integration by using the following syntax:
resources:
extensions:
<LogicalIdOfYourIntegrationResource>:
Properties:
ResponseParameters: ...
See CloudFormation docs for that resource for reference: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigatewayv2-integration.html#cfn-apigatewayv2-integration-responseparameters
I am trying to remove the redundant path which is used in both my serverless configuration and aws api gateway mapping.
Problem:
Login serverless yaml
serverless.yml
frameworkversion: '>1.8'
service: ${stage}-login
provider:
name: aws
runtime: nodejs10.x
timeout: 12
functions:
login:
name: login
handler: login.handler
events:
- http:
path: login
cors: true
integration: lambda
request:
passThrough: WHEN_NO_MATCH
template:
application/json:
<response omitted>
plugins:
- serverless-offline
API mapping to my custom domain
API - login-dev
Stage - dev
Path(optional) - login
Goal:
Lambda Functions :
login - {base url}/dev/login
register - {base url}/dev/register
What happened:
login {base url}/dev/login/login
register - {base url}/dev/register/register
Actions taken:
Tried to remove the Path(optional) but it would not allow me to add another lambda function if path is omitted.
Tried to proxy(unsure if this works the way i understand it) but it doesn;t allow because an error shows that {login} is used in one of my lambda function parameters.
Removed path in serverless yaml configuration file and replaced it with blank or / - but not an option for me because i need to keep the existing configuration.
Any help is very much appreciated.
Have you tried this:
functions:
login:
name: login
handler: login.handler
events:
- http:
path: /login
................
By adding a "/" in the starting of path.
FYI - I've checked similar issues related to this, but none solves my problem.
I'm trying to create the Swagger definition for a number of APIs under AWS Api-Gateway. I'm able to successfully do this for other(POST, GET) endpoints from an auto-generated YAML configuration I downloaded from the API Stage.
But I encountered issues when I tried to do same for an Api-Gateway endpoint with Lambda Proxy Integration: Error from Swagger editor.swagger.io
Below is my YAML definition for the failing endpoint:
swagger: "2.0"
info:
version: "2018-04-18T17-09-07Z"
title: "XXX API"
host: "api.xxx.io"
schemes:
- "https"
parameters:
stage:
name: stage
in: path
type: string
enum: [ staging, production]
required: true
paths:
/env/{stage}/{proxy+}:
x-amazon-apigateway-any-method:
produces:
- "application/json"
parameters:
- $ref: '#/parameters/stage'
- name: "proxy"
in: "path"
required: true
type: "string"
responses: {}
x-amazon-apigateway-integration:
uri: "arn:aws:apigateway:eu-central-1:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-central-1:xxxxxxxxx:function:environment/invocations"
responses:
default:
statusCode: "200"
passthroughBehavior: "when_no_match"
httpMethod: "POST"
cacheNamespace: "4vbcjm"
cacheKeyParameters:
- "method.request.path.proxy"
contentHandling: "CONVERT_TO_TEXT"
type: "aws_proxy"
this is inline with AWS Documentation: enter link description here
Please, what am I missing?
At a glance I believe you have an error in your parameters block. If you include a $ref it discards anything in that block that follows it, so your proxy name is getting dropped. I have a similar setup with api-gateway proxying all calls to a lambda and this is my parameters block:
parameters:
- name: "proxy"
in: "path"
required: true
type: "string"
Additionally you may want an authorizer if you're at all worried about DDoS or serving up secure data. That's done by adding a security array as a sibling to parameters, and a securityDefinitions block as a sibling to paths
security:
- authorizer: []
securityDefinitions:
authorizer:
type : "apiKey"
name : "Authorization"
in : "header"
x-amazon-apigateway-authtype : "custom"
x-amazon-apigateway-authorizer : {
type : "request",
authorizerUri : "arn:aws:apigateway:${region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${region}:${account_id}:function:${authorizer_function_name}/invocations",
authorizerResultTtlInSeconds : 58,
identitySource: "method.request.header.authorization",
}
*note I'm publishing swagger as a terraform template, hence the ${} substitution.
I'm configuring the caching on AWS API Gateway side to improve performance of my REST API. The endpoint I'm trying to configure is using a query parameter. I already enabled caching on AWS API Gateway side but unfortunately had to find out that it's ignoring the query parameters when building the cache key.
For instance, when I make first GET call with query parameter "test1"
GET https://2kdslm234ds9.execute-api.us-east-1.amazonaws.com/api/test?search=test1
Response for this call is saved in cache, and when after that I make call another query parameter - "test2"
GET https://2kdslm234ds9.execute-api.us-east-1.amazonaws.com/api/test?search=test2
I get again response for first call.
Settings for caching are pretty simple and I didn't find something related to parameters configuration.
How can I configure Gateway caching to take into account query parameters?
You need to configure this option in the Gateway API panel.
Choose your API and click Resources.
Choose the method and see the
URL Query String session.
If there is no query string, add one.
Mark the "caching" option of the query string.
Perform the final tests and finally, deploy changes.
Screenshot
The following is how we can achieve this utilising SAM:
The end result in the AWS API Gateway console must display that the set caching checkbox is:
The *.yml template for the API Gateway would be:
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
CacheClusterEnabled: true
CacheClusterSize: '0.5'
MethodSettings:
- HttpMethod: GET
CacheTtlInSeconds: 120
ResourcePath: "/getData"
CachingEnabled: true
DefinitionBody:
swagger: 2.0
basePath: /Prod
info:
title: OutService
x-amazon-apigateway-policy:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: "*"
Action: execute-api:Invoke
Resource:
- execute-api:/*/*/*
paths:
"/getData":
get:
# ** Parameter(s) can be set here **
parameters:
- name: "path"
in: "query"
required: "false"
type: "string"
x-amazon-apigateway-integration:
# ** Key is cached **
cacheKeyParameters:
- method.request.querystring.path
httpMethod: POST
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OutLambda.Arn}/invocations
responses: {}
EndpointConfiguration: PRIVATE
Cors:
AllowHeaders: "'*'"
So I'm trying to run a lambda on amazon and narrowed down the error finally by testing the lambda in amazons testing console.
The error I got is this.
{
"errorMessage": "Please install mysql2 package manually",
"errorType": "Error",
"stackTrace": [
"new MysqlDialect (/var/task/node_modules/sequelize/lib/dialects/mysql/index.js:14:30)",
"new Sequelize (/var/task/node_modules/sequelize/lib/sequelize.js:234:20)",
"Object.exports.getSequelizeConnection (/var/task/src/twilio/twilio.js:858:20)",
"Object.<anonymous> (/var/task/src/twilio/twilio.js:679:25)",
"__webpack_require__ (/var/task/src/twilio/twilio.js:20:30)",
"/var/task/src/twilio/twilio.js:63:18",
"Object.<anonymous> (/var/task/src/twilio/twilio.js:66:10)",
"Module._compile (module.js:570:32)",
"Object.Module._extensions..js (module.js:579:10)",
"Module.load (module.js:487:32)",
"tryModuleLoad (module.js:446:12)",
"Function.Module._load (module.js:438:3)",
"Module.require (module.js:497:17)",
"require (internal/module.js:20:19)"
]
}
Easy enough, so I have to install mysql2. So I added it to my package.json file.
{
"name": "test-api",
"version": "1.0.0",
"description": "",
"main": "handler.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 0"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"aws-sdk": "^2.153.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-3": "^6.24.1",
"serverless-domain-manager": "^1.1.20",
"serverless-dynamodb-autoscaling": "^0.6.2",
"serverless-webpack": "^4.0.0",
"webpack": "^3.8.1",
"webpack-node-externals": "^1.6.0"
},
"dependencies": {
"babel-runtime": "^6.26.0",
"mailgun-js": "^0.13.1",
"minimist": "^1.2.0",
"mysql": "^2.15.0",
"mysql2": "^1.5.1",
"qs": "^6.5.1",
"sequelize": "^4.31.2",
"serverless": "^1.26.0",
"serverless-plugin-scripts": "^1.0.2",
"twilio": "^3.10.0",
"uuid": "^3.1.0"
}
}
I noticed when I do sls deploy however, it seems to only be packaging some of the modules?
Serverless: Package lock found - Using locked versions
Serverless: Packing external modules: babel-runtime#^6.26.0, twilio#^3.10.0, qs#^6.5.1, mailgun-js#^0.13.1, sequelize#^4.31.2, minimi
st#^1.2.0, uuid#^3.1.0
Serverless: Packaging service...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
................................
Serverless: Stack update finished...
I think this is why it's not working. In short, how do I get mysql2 library to be packaged correctly with serverless so my lambda function will work with the sequelize library?
Please note that when I test locally my code works fine.
My serverless file is below
service: testapi
# Use serverless-webpack plugin to transpile ES6/ES7
plugins:
- serverless-webpack
- serverless-plugin-scripts
# - serverless-domain-manager
custom:
#Define the Stage or default to Staging.
stage: ${opt:stage, self:provider.stage}
webpackIncludeModules: true
#Define Databases Here
databaseName: "${self:service}-${self:custom.stage}"
#Define Bucket Names Here
uploadBucket: "${self:service}-uploads-${self:custom.stage}"
#Custom Script setup
scripts:
hooks:
#Script below will run schema changes to the database as neccesary and update according to stage.
'deploy:finalize': node database-schema-update.js --stage ${self:custom.stage}
#Domain Setup
# customDomain:
# basePath: "/"
# domainName: "api-${self:custom.stage}.test.com"
# stage: "${self:custom.stage}"
# certificateName: "*.test.com"
# createRoute53Record: true
provider:
name: aws
runtime: nodejs6.10
stage: staging
region: us-east-1
environment:
DOMAIN_NAME: "api-${self:custom.stage}.test.com"
DATABASE_NAME: ${self:custom.databaseName}
DATABASE_USERNAME: ${env:RDS_USERNAME}
DATABASE_PASSWORD: ${env:RDS_PASSWORD}
UPLOAD_BUCKET: ${self:custom.uploadBucket}
TWILIO_ACCOUNT_SID: ""
TWILIO_AUTH_TOKEN: ""
USER_POOL_ID: ""
APP_CLIENT_ID: ""
REGION: "us-east-1"
IDENTITY_POOL_ID: ""
RACKSPACE_API_KEY: ""
#Below controls permissions for lambda functions.
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:DescribeTable
- dynamodb:UpdateTable
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource: "arn:aws:dynamodb:us-east-1:*:*"
functions:
create_visit:
handler: src/visits/create.main
events:
- http:
path: visits
method: post
cors: true
authorizer: aws_iam
get_visit:
handler: src/visits/get.main
events:
- http:
path: visits/{id}
method: get
cors: true
authorizer: aws_iam
list_visit:
handler: src/visits/list.main
events:
- http:
path: visits
method: get
cors: true
authorizer: aws_iam
update_visit:
handler: src/visits/update.main
events:
- http:
path: visits/{id}
method: put
cors: true
authorizer: aws_iam
delete_visit:
handler: src/visits/delete.main
events:
- http:
path: visits/{id}
method: delete
cors: true
authorizer: aws_iam
twilio_send_text_message:
handler: src/twilio/twilio.send_text_message
events:
- http:
path: twilio/sendtextmessage
method: post
cors: true
authorizer: aws_iam
#This function handles incoming calls and where to route it to.
twilio_incoming_call:
handler: src/twilio/twilio.incoming_calls
events:
- http:
path: twilio/calls
method: post
twilio_failure:
handler: src/twilio/twilio.twilio_failure
events:
- http:
path: twilio/failure
method: post
twilio_statuschange:
handler: src/twilio/twilio.statuschange
events:
- http:
path: twilio/statuschange
method: post
twilio_incoming_message:
handler: src/twilio/twilio.incoming_message
events:
- http:
path: twilio/messages
method: post
twilio_whisper:
handler: src/twilio/twilio.whisper
events:
- http:
path: twilio/whisper
method: post
- http:
path: twilio/whisper
method: get
twilio_start_call:
handler: src/twilio/twilio.start_call
events:
- http:
path: twilio/startcall
method: post
- http:
path: twilio/startcall
method: get
resources:
Resources:
uploadBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:custom.uploadBucket}
RDSDatabase:
Type: AWS::RDS::DBInstance
Properties:
Engine : mysql
MasterUsername: ${env:RDS_USERNAME}
MasterUserPassword: ${env:RDS_PASSWORD}
DBInstanceClass : db.t2.micro
AllocatedStorage: '5'
PubliclyAccessible: true
#TODO: The Value of Stage is also available as a TAG automatically which I may use to replace this manually being put here..
Tags:
-
Key: "Name"
Value: ${self:custom.databaseName}
DeletionPolicy: Snapshot
DNSRecordSet:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneName: test.com.
Name: database-${self:custom.stage}.test.com
Type: CNAME
TTL: '300'
ResourceRecords:
- {"Fn::GetAtt": ["RDSDatabase","Endpoint.Address"]}
DependsOn: RDSDatabase
UPDATE:: So I confirmed that running sls package --stage dev seems to create this in the zip folder that would eventually upload to AWS. This confirms that serverless is not creating the package correctly with the mysql2 reference for some reason? Why is this?
webpack config file as requested
const slsw = require("serverless-webpack");
const nodeExternals = require("webpack-node-externals");
module.exports = {
entry: slsw.lib.entries,
target: "node",
// Since 'aws-sdk' is not compatible with webpack,
// we exclude all node dependencies
externals: [nodeExternals()],
// Run babel on all .js files and skip those in node_modules
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
include: __dirname,
exclude: /node_modules/
}
]
}
};
Thanks to dashmugs comment after some investigation on this page (https://github.com/serverless-heaven/serverless-webpack), there is a section on Forced Inclusion. I'll paraphrase it here.
Forced inclusion Sometimes it might happen that you use dynamic
requires in your code, i.e. you require modules that are only known at
runtime. Webpack is not able to detect such externals and the compiled
package will miss the needed dependencies. In such cases you can force
the plugin to include certain modules by setting them in the
forceInclude array property. However the module must appear in your
service's production dependencies in package.json.
# serverless.yml
custom:
webpackIncludeModules:
forceInclude:
- module1
- module2
So I simply did this...
webpackIncludeModules:
forceInclude:
- mysql
- mysql2
Now it works! Hope this helps someone else with the same issue.
None of the previous helped me, I used this solution: https://github.com/sequelize/sequelize/issues/9489#issuecomment-493304014
The trick is to use dialectModule property and override sequelize.
import Sequelize from 'sequelize';
import mysql2 from 'mysql2'; // Needed to fix sequelize issues with WebPack
const sequelize = new Sequelize(
process.env.DB_NAME,
process.env.DB_USER,
process.env.DB_PASSWORD,
{
dialect: 'mysql',
dialectModule: mysql2, // Needed to fix sequelize issues with WebPack
host: process.env.DB_HOST,
port: process.env.DB_PORT
}
)
export async function connectToDatabase() {
console.log('Trying to connect via sequelize')
await sequelize.sync()
await sequelize.authenticate()
console.log('=> Created a new connection.')
// Do something
}
The previous so far works on MySql but is not working with Postgres