CDK add mapping templates to LambdaIntegration - amazon-web-services

I have a Lambda function which can be accessed by api gateway.
How can I make CDK to add an Mapping template like in this Screenshot:
I tried multiple variants of this:
....
const restApi = new apigateway.LambdaRestApi(this, "dyndns-api", {
handler: dyndnsLambda,
proxy: false,
domainName: {
domainName: siteDomain,
certificate: certificate,
endpointType: apigateway.EndpointType.REGIONAL
}
});
const methodResponse: apigateway.MethodResponse = {
statusCode: "200",
responseModels: {"application/json": apigateway.Model.EMPTY_MODEL}
}
const requestTemplate = {
"execution_mode" : "$input.params('mode')",
"source_ip" : "$context.identity.sourceIp",
"set_hostname" : "$input.params('hostname')",
"validation_hash" : "$input.params('hash')"
}
const dnydnsIntegration = new apigateway.LambdaIntegration(dyndnsLambda, {
allowTestInvoke: true,
passthroughBehavior: apigateway.PassthroughBehavior.WHEN_NO_TEMPLATES,
requestTemplates: { "application/json": JSON.stringify(requestTemplate) },
});
restApi.root.addMethod("GET", dnydnsIntegration, {
methodResponses: [methodResponse]
});
But with not effect, it does not seem to arrive in the console, as I would expect.

solved it like this:
needed to add proxy setting to restApi, so the requestTemplate gets accepted. also needed integrationResponse.
const restApi = new apigateway.LambdaRestApi(this, "dyndns-api", {
handler: dyndnsLambda,
proxy: false,
domainName: {
securityPolicy: apigateway.SecurityPolicy.TLS_1_2,
domainName: siteDomain,
certificate: certificate,
endpointType: apigateway.EndpointType.REGIONAL
}
});
const methodResponse: apigateway.MethodResponse = {
statusCode: "200",
responseModels: {"application/json": apigateway.Model.EMPTY_MODEL}
}
const integrationResponse: apigateway.IntegrationResponse = {
statusCode: "200",
contentHandling: apigateway.ContentHandling.CONVERT_TO_TEXT
}
const requestTemplate = {
"execution_mode" : "$input.params('mode')",
"source_ip" : "$context.identity.sourceIp",
"set_hostname" : "$input.params('hostname')",
"validation_hash" : "$input.params('hash')"
}
const dnydnsIntegration = new apigateway.LambdaIntegration(dyndnsLambda, {
allowTestInvoke: true,
proxy: false,
integrationResponses: [integrationResponse],
passthroughBehavior: apigateway.PassthroughBehavior.WHEN_NO_TEMPLATES,
requestTemplates: { "application/json": JSON.stringify(requestTemplate) },
});
restApi.root.addMethod("GET", dnydnsIntegration, {
methodResponses: [methodResponse]
});

Related

AWS JavaScript resolver, Unable to convert

Trying JS resolver for the first time, Getting the Unable to convert error,
// Query-listItems-request.js
import { util } from '#aws-appsync/utils';
export function request(ctx) {
const { args: { userId } } = ctx;
return {
operation: 'Query',
query: {
expression: '#id = :id',
expressionValues: util.dynamodb.toMapValues({ ':id': `${userId}` }),
expressionNames: { '#id': 'id' },
},
};
}
export function response(ctx) {
return ctx.result;
}
AWS Sam tempalte:
AppGraphqlApiQueryListBalanceLogsResolver:
Type: AWS::AppSync::Resolver
Properties:
TypeName: Query
DataSourceName: !GetAtt AppGraphqlApiToListItemDataSource.Name
RequestMappingTemplateS3Location: Query-listItems-request.js
ResponseMappingTemplateS3Location: AppGraphqlApi/response.vtl
ApiId: !Ref AppGraphqlApi
FieldName: listItems
DependsOn: AppGraphqlBOApiSchema

AWS API Gateway Export is exporting an older version

I created an API Gateway with AWS CDK with a resource and a request model:
const api = new apigateway.RestApi(this, 'MyApiGateway', {
deploy: true,
retainDeployments: false
});
const createDto = api.addModel('CreateUserDto', {
modelName: 'CreateUserDto',
schema: ...
});
const users = api.root.addResource('users');
users.addMethod(
'POST',
createUserLambdaIntegration, {
operationName: 'Create User',
requestModels: {
'application/json': createDto
},
methodResponses: [
{
statusCode: '201'
}
]
}
);
then I changed it by adding a response model and changing the name of the request model:
const api = new apigateway.RestApi(this, 'MyApiGateway', {
deploy: true,
retainDeployments: false
});
const createUserRequest = api.addModel('CreateUserRequest', {
modelName: 'CreateUserRequest',
schema: ...
});
const createUserResponse = api.addModel('CreateUserResponse', {
modelName: 'CreateUserResponse',
schema: ...
});
const users = api.root.addResource('users');
users.addMethod(
'POST',
createUserLambdaIntegration, {
operationName: 'Create User',
requestModels: {
'application/json': createUserRequest
},
methodResponses: [
{
statusCode: '201',
responseModels: {
'application/json': createUserResponse
}
}
]
}
);
this all works somewhat fine, as I am able to see the updated models on the API Gateway console, but when I try exporting the API as a Swagger JSON, it always exports the first version I deployed. I tried exporting it using both the API Gateway console and the AWS CLI with the exact same result.
What am I doing wrong?

define API mappings for apigateway in CDK

how can I deploy the following setting to my apigateway using cdk?
relevant part of my CDK-stack for my API:
....
const restApi = new apigateway.LambdaRestApi(this, "dyndns-api", {
handler: dyndnsLambda,
proxy: false,
domainName: {
securityPolicy: apigateway.SecurityPolicy.TLS_1_2,
domainName: siteDomain,
certificate: certificate,
endpointType: apigateway.EndpointType.REGIONAL
}
});
const methodResponse: apigateway.MethodResponse = {
statusCode: "200",
responseModels: {"application/json": apigateway.Model.EMPTY_MODEL}
}
const integrationResponse: apigateway.IntegrationResponse = {
statusCode: "200",
contentHandling: apigateway.ContentHandling.CONVERT_TO_TEXT
}
new route53.ARecord(this, "apiDNS", {
zone: zone,
recordName: siteDomain,
target: route53.RecordTarget.fromAlias(new route53Targets.ApiGateway(restApi)),
});
const requestTemplate = {
"execution_mode" : "$input.params('mode')",
"source_ip" : "$context.identity.sourceIp",
"set_hostname" : "$input.params('hostname')",
"validation_hash" : "$input.params('hash')"
}
const dnydnsIntegration = new apigateway.LambdaIntegration(dyndnsLambda, {
allowTestInvoke: true,
proxy: false,
integrationResponses: [integrationResponse],
passthroughBehavior: apigateway.PassthroughBehavior.WHEN_NO_TEMPLATES,
requestTemplates: { "application/json": JSON.stringify(requestTemplate) },
});
restApi.root.addMethod("GET", dnydnsIntegration, {
methodResponses: [methodResponse]
});
I know, that there is apigatewayv2.ApiMapping, but I have trouble implementing that into my stack. Also tried the deprecated class CfnApiMappingV2 with no success either.

AWS CDK event bridge and api gateway AWS example does not work

I am following the instructions here to setup an event bridge: https://eventbus-cdk.workshop.aws/en/04-api-gateway-service-integrations/01-rest-api/rest-apis.html
Based on the error message, the error is coming from this line of code: languageResource.addMethod("POST", new apigw.Integration({
I am not sure what is causing this issue because this is an example given by AWS and should work, but it does not.
I can build it but it fails with the following error on cdk deploy:
CREATE_FAILED | AWS::ApiGateway::Method | MyRestAPI/Default/{language}/POST (MyRestAPIlanguagePOSTB787D51A) Invalid Resource identifier specified (Service: AmazonApiGateway; Status Code: 404; Error Code: NotFoundException;
The code is below:
const myLambda = new lambda.Function(this, "MyEventProcessor", {
code: new lambda.InlineCode("def main(event, context):\n\tprint(event)\n\treturn {'statusCode': 200, 'body': 'Hello, World'}"),
handler: "index.main",
runtime: lambda.Runtime.PYTHON_3_7
})
const bus = new events.EventBus(this, `pwm-${this.stage}-MdpEventBus`)
new cdk.CfnOutput(this, "PwmMdpEventBus", {value: bus.eventBusName})
new events.Rule(this, `PwmMdpEventBusRule`, {
eventBus: bus,
eventPattern: {source: [`com.amazon.alexa.english`]},
targets: [new targets.LambdaFunction(myLambda)]
})
const apigwRole = new iam.Role(this, "MYAPIGWRole", {
assumedBy: new iam.ServicePrincipal("apigateway"),
inlinePolicies: {
"putEvents": new iam.PolicyDocument({
statements: [new iam.PolicyStatement({
actions: ["events:PutEvents"],
resources: [bus.eventBusArn]
})]
})
}
});
const options = {
credentialsRole: apigwRole,
requestParameters: {
"integration.request.header.X-Amz-Target": "'AWSEvents.PutEvents'",
"integration.request.header.Content-Type": "'application/x-amz-json-1.1'"
},
requestTemplates: {
"application/json": `#set($language=$input.params('language'))\n{"Entries": [{"Source": "com.amazon.alexa.$language", "Detail": "$util.escapeJavaScript($input.body)", "Resources": ["resource1", "resource2"], "DetailType": "myDetailType", "EventBusName": "${bus.eventBusName}"}]}`
},
integrationResponses: [{
statusCode: "200",
responseTemplates: {
"application/json": ""
}
}]
}
const myRestAPI = new apigw.RestApi(this, "MyRestAPI");
const languageResource = myRestAPI.root.addResource("{language}");
languageResource.addMethod("POST", new apigw.Integration({
type: apigw.IntegrationType.AWS,
uri: `arn:aws:apigateway:${cdk.Aws.REGION}:events:path//`,
integrationHttpMethod: "POST",
options: options,
}),
{
methodResponses: [{
statusCode: "200"
}],
requestModels: {"application/json": model.getModel(this, myRestAPI) },
requestValidator: new apigw.RequestValidator(this, "myValidator", {
restApi: myRestAPI,
validateRequestBody: true
})
})
In the AWS example, they are encapsulating your code inside
export class MyCdkAppStack extends cdk.Stack {
...
}
Are you missing that encapsulation? I noticed your sample code didn't include it. Because when you execute const myRestAPI = new apigw.RestApi(this, "MyRestAPI"); the this should refer to the MyCdkAppStack instance.

cdk api gateway route53 lambda custom domain name not working

Similar questions has been made but none of them were able to help me fix the issue that I'm facing.
What I'm trying to do is to connect my api-gateway/lamnda function with a custom domain name and for some reason when calling the api/domain is not returning what I expected.
cdk version: 1.53.0
const lambdaFunction = new lambda.Function(this, 'LambdaApi', {
functionName: 'lambda-api',
handler: 'lambda.handler',
runtime: lambda.Runtime.NODEJS_12_X,
code: new lambda.AssetCode(join(process.cwd(), '../api/dist')),
memorySize: 128,
timeout: cdk.Duration.seconds(5),
})
const zone = route53.HostedZone.fromLookup(scope, 'Zone', {
'example.com',
privateZone: false,
})
const certificate = certificatemanager.Certificate.fromCertificateArn(
this,
'Certificate',
CERT_ARN,
)
const api = new apigateway.LambdaRestApi(this, 'LambdaApiGateway', {
handler: lambdaFunction,
proxy: true,
endpointTypes: [apigateway.EndpointType.EDGE],
defaultCorsPreflightOptions: {
allowOrigins: apigateway.Cors.ALL_ORIGINS,
},
options: {
restApiName: 'gateway-api',
domainName: {
domainName: 'api.example.com',
certificate,
},
deployOptions: {
stageName: 'prod',
metricsEnabled: true,
loggingLevel: apigateway.MethodLoggingLevel.INFO,
dataTraceEnabled: true,
},
},
})
new route53.ARecord(this, 'CustomDomainAliasRecord', {
zone,
recordName: 'api',
target: route53.RecordTarget.fromAlias(new targets.ApiGateway(api)),
})
The deployment process works fine, a ARecord is created on route53 that is pointing to the api-gateway domain name, the api mappings is created as well pointing to prod as specified on stageName but when calling the domain name it doesn’t work but when calling the api-gateway endpoint it does.
api.example.com/ping returns healthy
{id}.execute-api.us-east-1.amazonaws.com/prod/ping returns the current date
Been researching but I'm not able to find out why the api.example.com/ping is not working
For the most part we've done what you are doing there, but after the zone and certificate creation we've got something like this:
const customDomain = new DomainName(this, 'customDomain', {
domainName: 'api.example.com',
certificate: certificate,
endpointType: EndpointType.REGIONAL // yours may be Edge here
})
We also use basePathMapping so we don't have to use "dev|stg|prod" on the end of the domain.
new BasePathMapping(this, 'CustomBasePathMapping', {
domainName: customDomain,
restApi: api // again yours may differ here
})
I fixed with cloudfront distribution, here is the code.
const api = new apigateway.LambdaRestApi(
this,
'lambda-api-gateway',
{
handler: lambdaFunction,
proxy: true,
endpointTypes: [apigateway.EndpointType.EDGE],
defaultCorsPreflightOptions: {
allowOrigins: apigateway.Cors.ALL_ORIGINS,
allowMethods: apigateway.Cors.ALL_METHODS,
},
options: {
restApiName: 'gateway-api',
domainName: {
domainName,
certificate,
},
deployOptions: {
stageName: props.stageName,
metricsEnabled: true,
loggingLevel: apigateway.MethodLoggingLevel.INFO,
dataTraceEnabled: true,
},
},
},
)
const distribution = new cloudfront.CloudFrontWebDistribution(
this,
'api-cloudfront-distribution',
{
defaultRootObject: '/',
originConfigs: [
{
customOriginSource: {
domainName: `${api.restApiId}.execute-api.${this.region}.${this.urlSuffix}`,
},
originPath: `/${props.stageName}`,
behaviors: [
{
allowedMethods: cloudfront.CloudFrontAllowedMethods.ALL,
isDefaultBehavior: true,
forwardedValues: {
cookies: {
forward: 'all',
},
queryString: true,
},
},
],
},
],
enableIpV6: true,
viewerCertificate: cloudfront.ViewerCertificate.fromAcmCertificate(
certificate,
{
aliases: [domainName],
securityPolicy: cloudfront.SecurityPolicyProtocol.TLS_V1,
sslMethod: cloudfront.SSLMethod.SNI,
},
),
},
)
const zone = zoneFromLookUp(this, props.zoneDomainName)
const target = route53.RecordTarget.fromAlias(
new targets.CloudFrontTarget(distribution),
)
new route53.ARecord(this, 'arecord-api', {
zone,
recordName: domainName,
target,
})