in lib/amazon-qldb-rest-api-service.ts [32:489]
constructor(scope: Construct, id: string) {
super(scope, id);
const ledgerQLDB = new qldb.CfnLedger(this, 'qldb-ledger-kvs', {
name: LEDGER_NAME,
permissionsMode: 'STANDARD',
deletionProtection: false,
tags: [{
key: 'QLDBRESTAPI',
value: 'QLDBLEDGER',
}],
});
const backend = new lambda.Function(this, 'qldb-lambda-kvs', {
runtime: lambda.Runtime.NODEJS_14_X,
code: lambda.Code.fromAsset('resources/lambda'),
handler: 'index.main',
timeout: Duration.seconds(10),
environment: {
LEDGER_NAME: ledgerQLDB.ref,
TABLE_NAME,
},
});
backend.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [`arn:aws:qldb:${AWS_REGION}:${AWS_ACCOUNT}:ledger/${ledgerQLDB.ref}`],
actions: [
'qldb:GetBlock',
'qldb:ListLedgers',
'qldb:GetRevision',
'qldb:DescribeLedger',
'qldb:SendCommand',
'qldb:GetDigest',
],
}));
backend.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [`arn:aws:qldb:${AWS_REGION}:${AWS_ACCOUNT}:ledger/${ledgerQLDB.ref}/table/*`],
actions: [
'qldb:PartiQLCreateTable',
'qldb:PartiQLCreateIndex',
'qldb:PartiQLInsert',
'qldb:PartiQLUpdate',
'qldb:PartiQLSelect',
'qldb:PartiQLHistoryFunction',
],
}));
backend.addToRolePolicy(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
resources: [`arn:aws:qldb:${AWS_REGION}:${AWS_ACCOUNT}:ledger/${ledgerQLDB.ref}/information_schema/user_tables`],
actions: [
'qldb:PartiQLSelect',
],
}));
const api = new apigateway.RestApi(this, 'qldb-rest-api-kvs', {
endpointTypes: [EndpointType.REGIONAL],
deployOptions: {
methodOptions: {
'/*/*': { // This special path applies to all resource paths and all HTTP methods
throttlingRateLimit: 10,
throttlingBurstLimit: 50,
},
},
},
restApiName: 'Amazon QLDB key value store Service',
description: 'This service exposes a key-value store interface API for Amazon QLDB through REST pattern.',
});
const { root } = api;
const successResponseModel = api.addModel('SuccessResponseModel', {
contentType: 'application/json',
modelName: 'SuccessResponseModel',
schema: {
schema: JsonSchemaVersion.DRAFT4,
title: 'SuccessResponseModel',
type: JsonSchemaType.OBJECT,
},
});
const errorResponseModel = api.addModel('ErrorResponseModel', {
contentType: 'application/json',
modelName: 'ErrorResponseModel',
schema: {
schema: JsonSchemaVersion.DRAFT4,
title: 'ErrorResponseModel',
type: JsonSchemaType.OBJECT,
properties: {
message: { type: JsonSchemaType.STRING },
},
},
});
const IntegrationResponse200 = {
statusCode: '200',
responseTemplates: {},
responseParameters: {
'method.response.header.Content-Type': "'application/json'",
'method.response.header.Access-Control-Allow-Origin': "'*'",
'method.response.header.Access-Control-Allow-Credentials': "'true'",
},
};
const IntegrationResponse400 = {
selectionPattern: '.*Client Error.*',
statusCode: '400',
responseTemplates: {
'application/json': JSON.stringify({ message: "$util.escapeJavaScript($input.path('$.errorMessage'))" }),
},
responseParameters: {
'method.response.header.Content-Type': "'application/json'",
'method.response.header.Access-Control-Allow-Origin': "'*'",
'method.response.header.Access-Control-Allow-Credentials': "'true'",
},
};
const IntegrationResponse500 = {
selectionPattern: '(\n|.)+',
statusCode: '500',
responseTemplates: {
'application/json': JSON.stringify({ message: "$util.escapeJavaScript($input.path('$.errorMessage'))" }),
},
responseParameters: {
'method.response.header.Content-Type': "'application/json'",
'method.response.header.Access-Control-Allow-Origin': "'*'",
'method.response.header.Access-Control-Allow-Credentials': "'true'",
},
};
const methodResponse200 = {
// Successful response from the integration
statusCode: '200',
// Define what parameters are allowed or not
responseParameters: {
'method.response.header.Content-Type': true,
'method.response.header.Access-Control-Allow-Origin': true,
'method.response.header.Access-Control-Allow-Credentials': true,
},
// Validate the schema on the response
responseModels: {
'application/json': successResponseModel,
},
};
const methodResponse400 = {
statusCode: '400',
responseParameters: {
'method.response.header.Content-Type': true,
'method.response.header.Access-Control-Allow-Origin': true,
'method.response.header.Access-Control-Allow-Credentials': true,
},
responseModels: {
'application/json': errorResponseModel,
},
};
const methodResponse500 = {
statusCode: '500',
responseParameters: {
'method.response.header.Content-Type': true,
'method.response.header.Access-Control-Allow-Origin': true,
'method.response.header.Access-Control-Allow-Credentials': true,
},
responseModels: {
'application/json': errorResponseModel,
},
};
// Cannot use requestValidationOptions more than once due to bug - https://github.com/aws/aws-cdk/issues/14684
const validateBodyQueryStringAndHeader = new RequestValidator(this, 'validateBodyQueryStringAndHeader', {
restApi: api,
requestValidatorName: 'Validate body, query string parameters, and headers',
validateRequestBody: true,
validateRequestParameters: true,
});
const validateQueryStringAndHeader = new RequestValidator(this, 'validateQueryStringAndHeader', {
restApi: api,
requestValidatorName: 'Validate query string parameters and headers',
validateRequestBody: false,
validateRequestParameters: true,
});
// ## POST / - setValue - Create Single or Multiple Invoices ##
const setValueModel = api.addModel('SetValueModel', SetValueModel);
const setValueIntegration = new LambdaIntegration(backend, {
proxy: false,
requestParameters: {},
allowTestInvoke: true,
requestTemplates: {
'application/json': '{"ops":"setValue","payload":$input.json("$")}',
},
passthroughBehavior: PassthroughBehavior.NEVER,
integrationResponses: [
IntegrationResponse200,
IntegrationResponse400,
IntegrationResponse500,
],
});
root.addMethod('POST', setValueIntegration, {
requestParameters: {
'method.request.header.Content-Type': true,
},
requestModels: {
'application/json': setValueModel,
},
requestValidator: validateBodyQueryStringAndHeader,
methodResponses: [methodResponse200, methodResponse400, methodResponse500],
});
// ## END OF POST / - setValue - Create Single or Multiple Invoices ##
// ## GET / - getValue - Get Single or Multiple Invoices ##
const getValueRequestTemplate = `
#set($v = $util.escapeJavaScript($input.params("keys")))
#set($valueArray = $v.split(","))
{
"ops": "getValue",
"payload": [#foreach($item in $valueArray)
"$item"#if($foreach.hasNext),#end
#end
]
}`;
const getValueIntegration = new LambdaIntegration(backend, {
proxy: false,
requestParameters: {},
allowTestInvoke: true,
requestTemplates: {
'application/json': getValueRequestTemplate,
},
passthroughBehavior: PassthroughBehavior.NEVER,
integrationResponses: [
IntegrationResponse200,
IntegrationResponse400,
IntegrationResponse500],
});
root.addMethod('GET', getValueIntegration, {
requestParameters: {
'method.request.querystring.keys': true,
},
requestValidator: validateQueryStringAndHeader,
methodResponses: [methodResponse200, methodResponse400, methodResponse500],
});
// ## END OF GET / - getValue - Get Single or Multiple Invoices ##
// ## GET /receipt-by-key - getMetadataByKey - Get Metadata by Key ##
const getMetadataByKeyResource = api.root.addResource('receipt-by-key');
const getMetadataByKeyRequestTemplate = `
#set($v = $util.escapeJavaScript($input.params("key")))
{
"ops": "getMetadataByKey",
"payload": "$v"
}`;
const getMetadataByKeyIntegration = new LambdaIntegration(backend, {
proxy: false,
requestParameters: {},
allowTestInvoke: true,
requestTemplates: {
'application/json': getMetadataByKeyRequestTemplate,
},
passthroughBehavior: PassthroughBehavior.NEVER,
integrationResponses: [
IntegrationResponse200,
IntegrationResponse400,
IntegrationResponse500],
});
getMetadataByKeyResource.addMethod('GET', getMetadataByKeyIntegration, {
requestParameters: {
'method.request.querystring.key': true,
},
requestValidator: validateQueryStringAndHeader,
methodResponses: [methodResponse200, methodResponse400, methodResponse500],
});
// ## END OF GET /receipt-by-key - getMetadataByKey - Get Metadata by Key ##
// ## GET /receipt-by-doc - getMetadataByDoc - Get Metadata by documentId and TxId ##
const getMetadataByDocResource = api.root.addResource('receipt-by-doc');
const getMetadataByDocRequestTemplate = `
#set($d = $util.escapeJavaScript($input.params("documentId")))
#set($t = $util.escapeJavaScript($input.params("txId")))
{
"ops": "getMetadataByDoc",
"payload": {
"documentId": "$d",
"txId": "$t"
}
}`;
const getMetadataByDocIntegration = new LambdaIntegration(backend, {
proxy: false,
requestParameters: {},
allowTestInvoke: true,
requestTemplates: {
'application/json': getMetadataByDocRequestTemplate,
},
passthroughBehavior: PassthroughBehavior.NEVER,
integrationResponses: [
IntegrationResponse200,
IntegrationResponse400,
IntegrationResponse500],
});
getMetadataByDocResource.addMethod('GET', getMetadataByDocIntegration, {
requestParameters: {
'method.request.querystring.documentId': true,
'method.request.querystring.txId': true,
},
requestValidator: validateQueryStringAndHeader,
methodResponses: [methodResponse200, methodResponse400, methodResponse500],
});
// ## END OF GET /receipt-by-doc - getMetadataByDoc - Get Metadata by documentId and TxId ##
// ## POST /verify-receipt - verifyLedgerMetadata - Verify Receipt ##
const verifyLedgerMetadataResource = api.root.addResource('verify-receipt');
const verifyLedgerMetadataModel = api.addModel('verifyLedgerMetadataModel', VerifyLedgerMetadataModel);
const verifyLedgerMetadataIntegration = new LambdaIntegration(backend, {
proxy: false,
requestParameters: {},
allowTestInvoke: true,
requestTemplates: {
'application/json': '{"ops":"verifyLedgerMetadata","payload":$input.json("$")}',
},
passthroughBehavior: PassthroughBehavior.NEVER,
integrationResponses: [
IntegrationResponse200,
IntegrationResponse400,
IntegrationResponse500],
});
verifyLedgerMetadataResource.addMethod('POST', verifyLedgerMetadataIntegration, {
requestParameters: {
'method.request.header.Content-Type': true,
},
requestModels: {
'application/json': verifyLedgerMetadataModel,
},
requestValidator: validateBodyQueryStringAndHeader,
methodResponses: [methodResponse200, methodResponse400, methodResponse500],
});
// ## END OF POST /verify-receipt - verifyLedgerMetadata - Verify Receipt ##
// ## POST /retrieve-doc-revision - getRevisionByMetadata - Get Document Revision by Metadata ##
const getRevisionByMetadataResource = api.root.addResource('retrieve-doc-revision');
const getRevisionByMetadataModel = api.addModel('GetRevisionByMetadataModel', GetRevisionByMetadataModel);
const getRevisionByMetadataIntegration = new LambdaIntegration(backend, {
proxy: false,
requestParameters: {},
allowTestInvoke: true,
requestTemplates: {
'application/json': '{"ops":"getDocumentRevisionByLedgerMetadata","payload":$input.json("$")}',
},
passthroughBehavior: PassthroughBehavior.NEVER,
integrationResponses: [
IntegrationResponse200,
IntegrationResponse400,
IntegrationResponse500],
});
getRevisionByMetadataResource.addMethod('POST', getRevisionByMetadataIntegration, {
requestParameters: {
'method.request.header.Content-Type': true,
},
requestModels: {
'application/json': getRevisionByMetadataModel,
},
requestValidator: validateBodyQueryStringAndHeader,
methodResponses: [methodResponse200, methodResponse400, methodResponse500],
});
// ## END OF /retrieve-doc-revision - getRevisionByMetadata - Get Document Revision by Metadata ##
// ## GET /history - history - Get History for Invoice ##
const getHistoryResource = api.root.addResource('history');
const getHistoryRequestTemplate = `
#set($k = $util.escapeJavaScript($input.params("key")))
#set($f = $util.escapeJavaScript($input.params("from")))
#set($t = $util.escapeJavaScript($input.params("to")))
{
"ops": "getHistory",
"payload": {
"key": "$k",
"from": "$f",
"to": "$t"
}
}`;
const getHistoryIntegration = new LambdaIntegration(backend, {
proxy: false,
requestParameters: {},
allowTestInvoke: true,
requestTemplates: {
'application/json': getHistoryRequestTemplate,
},
passthroughBehavior: PassthroughBehavior.NEVER,
integrationResponses: [
IntegrationResponse200,
IntegrationResponse400,
IntegrationResponse500],
});
getHistoryResource.addMethod('GET', getHistoryIntegration, {
requestParameters: {
'method.request.querystring.key': true,
'method.request.querystring.from': false,
'method.request.querystring.to': false,
},
requestValidator: validateQueryStringAndHeader,
methodResponses: [methodResponse200, methodResponse400, methodResponse500],
});
// ## END OF GET /history - history - Get History for Invoice ##
// ## POST /verify-doc-revision - verifyDocumentRevisionHash - Verify Doc Revision Hash ##
const verifyDocumentRevisionHashResource = api.root.addResource('verify-doc-revision');
const verifyDocumentRevisionHashModel = api.addModel('verifyDocumentRevisionHashModel',
VerifyDocumentRevisionHashModel);
const verifyDocumentRevisionHashIntegration = new LambdaIntegration(backend, {
proxy: false,
requestParameters: {},
allowTestInvoke: true,
requestTemplates: {
'application/json': '{"ops":"verifyDocumentRevisionHash","payload":$input.json("$")}',
},
passthroughBehavior: PassthroughBehavior.NEVER,
integrationResponses: [
IntegrationResponse200,
IntegrationResponse400,
IntegrationResponse500],
});
verifyDocumentRevisionHashResource.addMethod('POST', verifyDocumentRevisionHashIntegration, {
requestParameters: {
'method.request.header.Content-Type': true,
},
requestModels: {
'application/json': verifyDocumentRevisionHashModel,
},
requestValidator: validateBodyQueryStringAndHeader,
methodResponses: [methodResponse200, methodResponse400, methodResponse500],
});
// ## END OF POST /verify-doc-revision - verifyDocumentRevisionHash - Verify Doc Revision Hash ##
}