diff --git a/.projen/deps.json b/.projen/deps.json index 439f05f1..094367c9 100644 --- a/.projen/deps.json +++ b/.projen/deps.json @@ -159,6 +159,10 @@ "name": "axios", "type": "runtime" }, + { + "name": "cdk-monitoring-constructs", + "type": "runtime" + }, { "name": "constructs", "type": "runtime" diff --git a/.projen/tasks.json b/.projen/tasks.json index 1dceb67e..22ecb010 100644 --- a/.projen/tasks.json +++ b/.projen/tasks.json @@ -253,13 +253,13 @@ }, "steps": [ { - "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@aws-sdk/client-cognito-identity-provider,@aws-sdk/client-dynamodb,@aws-sdk/client-s3,@aws-sdk/lib-dynamodb,@hapi/boom,@types/jest,@types/js-yaml,@types/jsonwebtoken,@types/jwk-to-pem,@types/lambda-log,@types/node,@types/uuid,eslint-import-resolver-typescript,eslint-plugin-import,jest,projen,ts-jest,ts-node,typescript,openapi-typescript,@types/aws-lambda,axios,constructs,date-fns,js-yaml,jsonwebtoken,jwk-to-pem,lambda-log,uuid" + "exec": "npx npm-check-updates@16 --upgrade --target=minor --peer --no-deprecated --dep=dev,peer,prod,optional --filter=@aws-sdk/client-cognito-identity-provider,@aws-sdk/client-dynamodb,@aws-sdk/client-s3,@aws-sdk/lib-dynamodb,@hapi/boom,@types/jest,@types/js-yaml,@types/jsonwebtoken,@types/jwk-to-pem,@types/lambda-log,@types/node,@types/uuid,eslint-import-resolver-typescript,eslint-plugin-import,jest,projen,ts-jest,ts-node,typescript,openapi-typescript,@types/aws-lambda,axios,cdk-monitoring-constructs,constructs,date-fns,js-yaml,jsonwebtoken,jwk-to-pem,lambda-log,uuid" }, { "exec": "npm install" }, { - "exec": "npm update @aws-sdk/client-cognito-identity-provider @aws-sdk/client-dynamodb @aws-sdk/client-s3 @aws-sdk/lib-dynamodb @hapi/boom @stylistic/eslint-plugin @types/jest @types/js-yaml @types/jsonwebtoken @types/jwk-to-pem @types/lambda-log @types/node @types/uuid @typescript-eslint/eslint-plugin @typescript-eslint/parser commit-and-tag-version constructs eslint-import-resolver-typescript eslint-plugin-import eslint jest jest-junit projen ts-jest ts-node typedoc typescript aws-cdk-lib dynamodb-onetable openapi-typescript @types/aws-lambda axios date-fns js-yaml jsonwebtoken jwk-to-pem lambda-log uuid" + "exec": "npm update @aws-sdk/client-cognito-identity-provider @aws-sdk/client-dynamodb @aws-sdk/client-s3 @aws-sdk/lib-dynamodb @hapi/boom @stylistic/eslint-plugin @types/jest @types/js-yaml @types/jsonwebtoken @types/jwk-to-pem @types/lambda-log @types/node @types/uuid @typescript-eslint/eslint-plugin @typescript-eslint/parser commit-and-tag-version constructs eslint-import-resolver-typescript eslint-plugin-import eslint jest jest-junit projen ts-jest ts-node typedoc typescript aws-cdk-lib dynamodb-onetable openapi-typescript @types/aws-lambda axios cdk-monitoring-constructs date-fns js-yaml jsonwebtoken jwk-to-pem lambda-log uuid" }, { "exec": "npx projen" diff --git a/.projenrc.js b/.projenrc.js index ddad60c6..2a2a4f6b 100644 --- a/.projenrc.js +++ b/.projenrc.js @@ -20,6 +20,7 @@ const project = new typescript.TypeScriptProject({ 'axios', 'uuid', 'lambda-log', + 'cdk-monitoring-constructs', 'constructs', ], defaultReleaseBranch: 'main', diff --git a/docs/constructs/assets/hierarchy.js b/docs/constructs/assets/hierarchy.js index 7d2a5d3c..675cec04 100644 --- a/docs/constructs/assets/hierarchy.js +++ b/docs/constructs/assets/hierarchy.js @@ -1 +1 @@ -window.hierarchyData = "eJyVkrFuwyAURf/lzaSRA8aYLe1QdWu7RhmQ/VKjELCATJH/vSJNW9pEtrMwwH2cewQn8M7FAHIjKOEVKeotAY87g03UzgaQJyjqtFp1QJDw8uQ+rI5ufYwd2qgblXJAYK9tC3JVcgJHb0CCthH9TjUYlreHHrp4MECgMSoEkBBDu0i3LH4m02GnTevRgtwwvh0IMJ61GS9TrMR3mTMDw/K+Il8bAwFeZdBHFXDd61fv+jAhnkfv1aW0JKw6Owt6jR+zvEQmvP7SOCOsFolGaZnhnr3quzczU/hfeoZzAnJ2Ezim+Juafj1W5X/mHUOcaZNH56mwWlyjxjwukSmJYfgEhuw1OA==" \ No newline at end of file +window.hierarchyData = "eJyVk71uwyAUhd/lziSRY34MW9qhytZ2jTIgm9SoBCwgU+R3r2jdFreR7SwMcA7nfFxxBe9cDCAOVYkoQwU/IvDqZFQdtbMBxBUKnlYrzwoE7B/dm9XR7S6xVTbqWiYdIHjXtgGxJRTBxRsQoG1U/iRrFTa3Tes2ng0gqI0MAQTE0KzSLasfZzpstWm8siAOmB57BJhmbabLFNvqu8xnhgqb+4p8bfQIKMtCH2RQu04/e9eFGfBcei9uiSnCnCXmqvwfP0U5SGa4xmmMIFLwlFaOnvjJy659MQuB/6gXMKdARm4GTiH+quanh3k+vlcV4kKaXLoMhYw+y+Cf4hgkcxB9/wGQYDU6" \ No newline at end of file diff --git a/docs/constructs/assets/search.js b/docs/constructs/assets/search.js index 6dcfc4a5..1c6d5b30 100644 --- a/docs/constructs/assets/search.js +++ b/docs/constructs/assets/search.js @@ -1 +1 @@ -window.searchData = "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"; \ No newline at end of file +window.searchData = "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"; \ No newline at end of file diff --git a/docs/constructs/classes/BaseApi.html b/docs/constructs/classes/BaseApi.html index d9729c10..51dd7907 100644 --- a/docs/constructs/classes/BaseApi.html +++ b/docs/constructs/classes/BaseApi.html @@ -4,11 +4,15 @@ apiFQDN? apiHostName? hostedZone? +monitoring? node -

Methods

toString +

Methods

addFunctionMonitoringSegment +addFunctionToMonitoring +addSingleTableMonitoring +toString isConstruct -

Constructors

Properties

apiDomainName?: string
apiFQDN?: string
apiHostName?: string
hostedZone?: IHostedZone
node: Node

The tree node.

-

Methods

  • Returns a string representation of this construct.

    +

Constructors

Properties

apiDomainName?: string
apiFQDN?: string
apiHostName?: string
hostedZone?: IHostedZone
monitoring?: MonitoringFacade
node: Node

The tree node.

+

Methods

  • Returns void

  • Parameters

    • operationId: string
    • fn: IFunction

    Returns void

  • Returns a string representation of this construct.

    Returns string

  • Checks if x is a construct.

    Use this method instead of instanceof to properly detect Construct instances, even when the construct library is symlinked.

    @@ -24,4 +28,4 @@ this type-testing method instead.

    Parameters

    • x: any

      Any object

    Returns x is Construct

    true if x is an object created from a class which extends Construct.

    -
+
diff --git a/docs/constructs/classes/GraphQlApi.html b/docs/constructs/classes/GraphQlApi.html index d6bfe005..91f9c8a6 100644 --- a/docs/constructs/classes/GraphQlApi.html +++ b/docs/constructs/classes/GraphQlApi.html @@ -5,18 +5,22 @@

Type Parameters

Hierarchy (View Summary)

Properties

api: GraphqlApi

The AWS AppSync GraphQL API instance.

-
apiDomainName?: string
apiFQDN?: string
apiHostName?: string
hostedZone?: IHostedZone
node: Node

The tree node.

+
apiDomainName?: string
apiFQDN?: string
apiHostName?: string
hostedZone?: IHostedZone
monitoring?: MonitoringFacade
node: Node

The tree node.

tableDataSource?: DynamoDbDataSource

The optional DynamoDB data source for the GraphQL API.

-

Methods

  • Type Parameters

    • TYPE extends string | number | symbol
    • FIELDTYPE extends {}

    Parameters

    Returns void

  • Type Parameters

    • TYPE extends string | number | symbol
    • FIELDTYPE extends {}

    Parameters

    Returns void

  • Type Parameters

    • TYPE extends string | number | symbol
    • FIELDTYPE extends {}

    Parameters

    Returns void

  • getFunctionForOperation

    +

Methods

  • Type Parameters

    • TYPE extends string | number | symbol
    • FIELDTYPE extends {}

    Parameters

    Returns void

  • Type Parameters

    • TYPE extends string | number | symbol
    • FIELDTYPE extends {}

    Parameters

    Returns void

  • Parameters

    • operationId: string
    • fn: IFunction

    Returns void

  • Type Parameters

    • TYPE extends string | number | symbol
    • FIELDTYPE extends {}

    Parameters

    Returns void

  • getFunctionForOperation

    Type Parameters

    • TYPE extends string | number | symbol
    • FIELDTYPE extends {}

    Parameters

    Returns LambdaFunction

  • Type Parameters

    • TYPE extends string | number | symbol
    • FIELDTYPE extends {}

    Parameters

    • grantee: IGrantable
    • typeName: TYPE
    • ...fieldNames: (keyof FIELDTYPE)[]

    Returns void

  • Type Parameters

    • TYPE extends string | number | symbol
    • FIELDTYPE extends {}

    Parameters

    Returns void

  • Type Parameters

    • TYPE extends string | number | symbol
    • FIELDTYPE extends {}

    Parameters

    Returns void

  • Returns a string representation of this construct.

    Returns string

  • Checks if x is a construct.

    Use this method instead of instanceof to properly detect Construct @@ -48,4 +52,4 @@ this type-testing method instead.

    Parameters

    • x: any

      Any object

    Returns x is Construct

    true if x is an object created from a class which extends Construct.

    -
+
diff --git a/docs/constructs/classes/LambdaFunction.html b/docs/constructs/classes/LambdaFunction.html index 21f3e6fb..246421d6 100644 --- a/docs/constructs/classes/LambdaFunction.html +++ b/docs/constructs/classes/LambdaFunction.html @@ -5,7 +5,7 @@
const lambdaFunction = new LambdaFunction(this, 'MyLambdaFunction', {
entry: 'path/to/lambda/handler.ts',
handler: 'main',
stageName: 'dev',
table: myDynamoDBTable,
userPool: myCognitoUserPool,
assetBucket: myS3Bucket,
lambdaOptions: {
timeout: Duration.seconds(30),
memorySize: 512,
},
});

// Add additional permissions
lambdaFunction.grantSendEmails();
lambdaFunction.grantTableWrite();
-

Hierarchy

Constructors

Hierarchy

Constructors

Properties

architecture canCreatePermissions deadLetterQueue? diff --git a/docs/constructs/classes/RestApi.html b/docs/constructs/classes/RestApi.html index e97e2216..c526d686 100644 --- a/docs/constructs/classes/RestApi.html +++ b/docs/constructs/classes/RestApi.html @@ -6,16 +6,20 @@

Type Parameters

  • PATHS

    The type definition for the API paths.

  • OPS

    The type definition for the API operations.

    -

Hierarchy (View Summary)

Properties

api: SpecRestApi

The AWS API Gateway REST API instance.

apiDomainName?: string
apiFQDN?: string
apiHostName?: string
apiSpec: OpenAPI3

The OpenAPI specification for the REST API.

-
hostedZone?: IHostedZone
node: Node

The tree node.

-

Methods

  • Parameters

    • operation: OperationObject
    • method: string
    • description: string
    • additionalLambdaOptions: LambdaOptions = {}

    Returns undefined | LambdaFunction

  • Type Parameters

    • P extends string | number | symbol

    Parameters

    Returns undefined | LambdaFunction

  • Parameters

    • spec: { [key: string]: any }

    Returns { [key: string]: any }

  • return the generated Lambda function for the specified API operation

    +
hostedZone?: IHostedZone
monitoring?: MonitoringFacade
node: Node

The tree node.

+

Methods

  • Parameters

    • operation: OperationObject
    • method: string
    • description: string
    • additionalLambdaOptions: LambdaOptions = {}

    Returns undefined | LambdaFunction

  • Parameters

    • operationId: string
    • fn: IFunction

    Returns void

  • Type Parameters

    • P extends string | number | symbol

    Parameters

    Returns undefined | LambdaFunction

  • Parameters

    • spec: { [key: string]: any }

    Returns { [key: string]: any }

  • return the generated Lambda function for the specified API operation

    Parameters

    • operationId: keyof OPS

    Returns LambdaFunction

  • Visitor method to modify the given functions

    Parameters

    • operationIds: (keyof OPS)[]

      the list of functions to visit

      @@ -57,4 +61,4 @@ this type-testing method instead.

      Parameters

      • x: any

        Any object

      Returns x is Construct

      true if x is an object created from a class which extends Construct.

      -
+
diff --git a/docs/constructs/classes/SingleTableDatastore.html b/docs/constructs/classes/SingleTableDatastore.html index 21d4361f..77f960c8 100644 --- a/docs/constructs/classes/SingleTableDatastore.html +++ b/docs/constructs/classes/SingleTableDatastore.html @@ -4,7 +4,7 @@
const datastore = new SingleTableDatastore(this, 'MyDatastore', {
design: {
primaryKey: {
partitionKey: 'PK',
sortKey: 'SK',
},
globalIndexes: [
{
indexName: 'GSI1',
partitionKey: { name: 'GSI1PK', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'GSI1SK', type: dynamodb.AttributeType.STRING },
},
],
localIndexes: [
{
indexName: 'LSI1',
sortKey: { name: 'LSI1SK', type: dynamodb.AttributeType.STRING },
},
],
timeToLiveAttribute: 'TTL',
},
encryption: dynamodb.TableEncryption.AWS_MANAGED,
});
-

Hierarchy

Constructors

Hierarchy

  • Construct
    • SingleTableDatastore

Constructors

Properties

Methods

toString diff --git a/docs/constructs/classes/Workflow.html b/docs/constructs/classes/Workflow.html index e5ce34d6..c502d7cb 100644 --- a/docs/constructs/classes/Workflow.html +++ b/docs/constructs/classes/Workflow.html @@ -4,7 +4,7 @@
const workflow = new Workflow(this, 'MyWorkflow', {
definitionFileName: 'path/to/definition.asl.json',
stateMachineType: sfn.StateMachineType.STANDARD,
loggingConfiguration: {
level: sfn.LogLevel.ALL,
includeExecutionData: true,
destinations: [new logs.LogGroup(this, 'LogGroup')],
},
tracingConfiguration: {
enabled: true,
},
definitionSubstitutions: {
'${MyVariable}': 'MyValue',
},
});

const lambdaFunction = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
});

workflow.grantPrincipal.grantInvoke(lambdaFunction);
-

Hierarchy

  • Construct
    • Workflow

Implements

  • IGrantable

Constructors

Hierarchy

  • Construct
    • Workflow

Implements

  • IGrantable

Constructors

Properties

grantPrincipal node role diff --git a/docs/constructs/hierarchy.html b/docs/constructs/hierarchy.html index c0bc8871..c17cb3b0 100644 --- a/docs/constructs/hierarchy.html +++ b/docs/constructs/hierarchy.html @@ -1 +1 @@ -cdk-serverless
+cdk-serverless
diff --git a/docs/constructs/interfaces/GraphQlApiProps.html b/docs/constructs/interfaces/GraphQlApiProps.html index 723a6295..9a507b19 100644 --- a/docs/constructs/interfaces/GraphQlApiProps.html +++ b/docs/constructs/interfaces/GraphQlApiProps.html @@ -1,4 +1,4 @@ -GraphQlApiProps | cdk-serverless

Interface GraphQlApiProps

interface GraphQlApiProps {
    additionalEnv?: { [key: string]: string };
    apiHostname?: string;
    apiName: string;
    assetCdn?: AssetCdn;
    authentication?: IJwtAuthentication | ICognitoAuthentication;
    definitionFileName: string;
    domainName?: string;
    hostedZone?: IHostedZone;
    lambdaOptions?: LambdaOptions;
    lambdaTracing?: LambdaTracingOptions;
    monitoring?: boolean;
    singleTableDatastore?: SingleTableDatastore;
    stageName: string;
}

Hierarchy (View Summary)

Properties

additionalEnv? +GraphQlApiProps | cdk-serverless

Interface GraphQlApiProps

interface GraphQlApiProps {
    additionalEnv?: { [key: string]: string };
    apiHostname?: string;
    apiName: string;
    assetCdn?: AssetCdn;
    authentication?: IJwtAuthentication | ICognitoAuthentication;
    definitionFileName: string;
    domainName?: string;
    hostedZone?: IHostedZone;
    lambdaOptions?: LambdaOptions;
    lambdaTracing?: LambdaTracingOptions;
    monitoring?: boolean;
    singleTableDatastore?: SingleTableDatastore;
    stageName: string;
}

Hierarchy (View Summary)

Properties

additionalEnv? apiHostname? apiName assetCdn? diff --git a/docs/constructs/interfaces/RestApiProps.html b/docs/constructs/interfaces/RestApiProps.html index f46b808e..ed2367b7 100644 --- a/docs/constructs/interfaces/RestApiProps.html +++ b/docs/constructs/interfaces/RestApiProps.html @@ -1,4 +1,4 @@ -RestApiProps | cdk-serverless

Interface RestApiProps<OPS>

interface RestApiProps<OPS> {
    additionalEnv?: { [key: string]: string };
    apiHostname?: string;
    apiName: string;
    assetCdn?: AssetCdn;
    authentication?: IJwtAuthentication | ICognitoAuthentication;
    autoGenerateRoutes?: boolean;
    cors: boolean;
    definitionFileName: string;
    domainName?: string;
    hostedZone?: IHostedZone;
    lambdaOptions?: LambdaOptions;
    lambdaOptionsByOperation?: {
        [operationId in string | number | symbol]?: LambdaOptions
    };
    lambdaTracing?: LambdaTracingOptions;
    monitoring?: boolean;
    restApiProps?: RestApiBaseProps;
    singleTableDatastore?: SingleTableDatastore;
    stageName: string;
}

Type Parameters

  • OPS

Hierarchy (View Summary)

Properties

additionalEnv? +RestApiProps | cdk-serverless

Interface RestApiProps<OPS>

interface RestApiProps<OPS> {
    additionalEnv?: { [key: string]: string };
    apiHostname?: string;
    apiName: string;
    assetCdn?: AssetCdn;
    authentication?: IJwtAuthentication | ICognitoAuthentication;
    autoGenerateRoutes?: boolean;
    cors: boolean;
    definitionFileName: string;
    domainName?: string;
    hostedZone?: IHostedZone;
    lambdaOptions?: LambdaOptions;
    lambdaOptionsByOperation?: {
        [operationId in string | number | symbol]?: LambdaOptions
    };
    lambdaTracing?: LambdaTracingOptions;
    monitoring?: boolean;
    restApiProps?: RestApiBaseProps;
    singleTableDatastore?: SingleTableDatastore;
    stageName: string;
}

Type Parameters

  • OPS

Hierarchy (View Summary)

Properties

additionalEnv? apiHostname? apiName assetCdn? diff --git a/package-lock.json b/package-lock.json index 13660119..f0933c2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@types/aws-lambda": "^8.10.148", "axios": "^1.8.4", + "cdk-monitoring-constructs": "^9.12.0", "constructs": "^10.3.0", "date-fns": "^4.1.0", "js-yaml": "^4.1.0", @@ -101,14 +102,12 @@ "version": "2.2.230", "resolved": "https://registry.npmjs.org/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.230.tgz", "integrity": "sha512-kUnhKIYu42hqBa6a8x2/7o29ObpJgjYGQy28lZDq9awXyvpR62I2bRxrNKNR3uFUQz3ySuT9JXhGHhuZPdbnFw==", - "dev": true, "license": "Apache-2.0" }, "node_modules/@aws-cdk/asset-node-proxy-agent-v6": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@aws-cdk/asset-node-proxy-agent-v6/-/asset-node-proxy-agent-v6-2.1.0.tgz", "integrity": "sha512-7bY3J8GCVxLupn/kNmpPc5VJz8grx+4RKfnnJiO1LG+uxkZfANZG3RMHhE+qQxxwkyQ9/MfPtTpf748UhR425A==", - "dev": true, "license": "Apache-2.0" }, "node_modules/@aws-cdk/cloud-assembly-schema": { @@ -119,7 +118,6 @@ "jsonschema", "semver" ], - "dev": true, "license": "Apache-2.0", "dependencies": { "jsonschema": "~1.4.1", @@ -131,7 +129,6 @@ }, "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/jsonschema": { "version": "1.4.1", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -140,7 +137,6 @@ }, "node_modules/@aws-cdk/cloud-assembly-schema/node_modules/semver": { "version": "7.7.1", - "dev": true, "inBundle": true, "license": "ISC", "bin": { @@ -5177,7 +5173,6 @@ "yaml", "mime-types" ], - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-cdk/asset-awscli-v1": "^2.2.229", @@ -5204,13 +5199,11 @@ }, "node_modules/aws-cdk-lib/node_modules/@balena/dockerignore": { "version": "1.0.2", - "dev": true, "inBundle": true, "license": "Apache-2.0" }, "node_modules/aws-cdk-lib/node_modules/ajv": { "version": "8.17.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -5226,7 +5219,6 @@ }, "node_modules/aws-cdk-lib/node_modules/ansi-regex": { "version": "5.0.1", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -5235,7 +5227,6 @@ }, "node_modules/aws-cdk-lib/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -5250,7 +5241,6 @@ }, "node_modules/aws-cdk-lib/node_modules/astral-regex": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -5259,13 +5249,11 @@ }, "node_modules/aws-cdk-lib/node_modules/balanced-match": { "version": "1.0.2", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/aws-cdk-lib/node_modules/brace-expansion": { "version": "1.1.11", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -5275,7 +5263,6 @@ }, "node_modules/aws-cdk-lib/node_modules/case": { "version": "1.6.3", - "dev": true, "inBundle": true, "license": "(MIT OR GPL-3.0-or-later)", "engines": { @@ -5284,7 +5271,6 @@ }, "node_modules/aws-cdk-lib/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -5296,31 +5282,26 @@ }, "node_modules/aws-cdk-lib/node_modules/color-name": { "version": "1.1.4", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/aws-cdk-lib/node_modules/concat-map": { "version": "0.0.1", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/aws-cdk-lib/node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/aws-cdk-lib/node_modules/fast-deep-equal": { "version": "3.1.3", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/aws-cdk-lib/node_modules/fast-uri": { "version": "3.0.6", - "dev": true, "funding": [ { "type": "github", @@ -5336,7 +5317,6 @@ }, "node_modules/aws-cdk-lib/node_modules/fs-extra": { "version": "11.3.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -5350,13 +5330,11 @@ }, "node_modules/aws-cdk-lib/node_modules/graceful-fs": { "version": "4.2.11", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/aws-cdk-lib/node_modules/ignore": { "version": "5.3.2", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -5365,7 +5343,6 @@ }, "node_modules/aws-cdk-lib/node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -5374,13 +5351,11 @@ }, "node_modules/aws-cdk-lib/node_modules/json-schema-traverse": { "version": "1.0.0", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/aws-cdk-lib/node_modules/jsonfile": { "version": "6.1.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -5392,7 +5367,6 @@ }, "node_modules/aws-cdk-lib/node_modules/jsonschema": { "version": "1.5.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -5401,13 +5375,11 @@ }, "node_modules/aws-cdk-lib/node_modules/lodash.truncate": { "version": "4.4.2", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/aws-cdk-lib/node_modules/mime-db": { "version": "1.52.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -5416,7 +5388,6 @@ }, "node_modules/aws-cdk-lib/node_modules/mime-types": { "version": "2.1.35", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -5428,7 +5399,6 @@ }, "node_modules/aws-cdk-lib/node_modules/minimatch": { "version": "3.1.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -5440,7 +5410,6 @@ }, "node_modules/aws-cdk-lib/node_modules/punycode": { "version": "2.3.1", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -5449,7 +5418,6 @@ }, "node_modules/aws-cdk-lib/node_modules/require-from-string": { "version": "2.0.2", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -5458,7 +5426,6 @@ }, "node_modules/aws-cdk-lib/node_modules/semver": { "version": "7.7.1", - "dev": true, "inBundle": true, "license": "ISC", "bin": { @@ -5470,7 +5437,6 @@ }, "node_modules/aws-cdk-lib/node_modules/slice-ansi": { "version": "4.0.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -5487,7 +5453,6 @@ }, "node_modules/aws-cdk-lib/node_modules/string-width": { "version": "4.2.3", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -5501,7 +5466,6 @@ }, "node_modules/aws-cdk-lib/node_modules/strip-ansi": { "version": "6.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -5513,7 +5477,6 @@ }, "node_modules/aws-cdk-lib/node_modules/table": { "version": "6.9.0", - "dev": true, "inBundle": true, "license": "BSD-3-Clause", "dependencies": { @@ -5529,7 +5492,6 @@ }, "node_modules/aws-cdk-lib/node_modules/universalify": { "version": "2.0.1", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -5538,7 +5500,6 @@ }, "node_modules/aws-cdk-lib/node_modules/yaml": { "version": "1.10.2", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -5984,6 +5945,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/cdk-monitoring-constructs": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/cdk-monitoring-constructs/-/cdk-monitoring-constructs-9.12.0.tgz", + "integrity": "sha512-FO/Vbgb6sFH1Ugcou9ei0kNoW9AduSuEXBhXYDVlUQiInCkEtVQMif8fxhrl4uar43fAskPuHsj6/Abo11dWmw==", + "license": "Apache-2.0", + "peerDependencies": { + "aws-cdk-lib": "^2.160.0", + "constructs": "^10.0.5" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -6177,7 +6148,6 @@ "version": "10.4.2", "resolved": "https://registry.npmjs.org/constructs/-/constructs-10.4.2.tgz", "integrity": "sha512-wsNxBlAott2qg8Zv87q3eYZYgheb9lchtBfjHzzLHtXbttwSrHPs1NNQbBrmbb1YZvYg2+Vh0Dor76w4mFxJkA==", - "dev": true, "license": "Apache-2.0" }, "node_modules/conventional-changelog": { diff --git a/package.json b/package.json index 2f57b460..09e9612a 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "dependencies": { "@types/aws-lambda": "^8.10.148", "axios": "^1.8.4", + "cdk-monitoring-constructs": "^9.12.0", "constructs": "^10.3.0", "date-fns": "^4.1.0", "js-yaml": "^4.1.0", diff --git a/src/constructs/base-api.ts b/src/constructs/base-api.ts index 1ec453b9..0d8b4bc6 100644 --- a/src/constructs/base-api.ts +++ b/src/constructs/base-api.ts @@ -1,8 +1,11 @@ import { aws_route53 } from 'aws-cdk-lib'; +import { IFunction } from 'aws-cdk-lib/aws-lambda'; +import { DefaultDashboardFactory, MonitoringFacade } from 'cdk-monitoring-constructs'; import { Construct } from 'constructs'; import { AssetCdn } from './asset-cdn'; import { ICognitoAuthentication, IJwtAuthentication } from './authentication'; import { LambdaOptions, LambdaTracingOptions } from './func'; +import { AggregatedFunctionMonitoring } from './monitoring/aggregated-function-monitoring'; import { SingleTableDatastore } from './table'; export interface BaseApiProps { @@ -96,6 +99,8 @@ export abstract class BaseApi extends Construct { protected readonly apiHostName?: string; protected readonly apiDomainName?: string; protected readonly apiFQDN?: string; + public readonly monitoring?: MonitoringFacade; + private readonly functionMonitoring?: AggregatedFunctionMonitoring; constructor(scope: Construct, id: string, props: BaseApiProps) { super(scope, id); @@ -114,6 +119,37 @@ export abstract class BaseApi extends Construct { this.apiFQDN = `${this.apiHostName}.${this.apiDomainName}`; } + if (props.monitoring ?? true) { + this.monitoring = new MonitoringFacade(this, 'Monitoring', { + dashboardFactory: new DefaultDashboardFactory(this, 'DashboardFactory', { + dashboardNamePrefix: props.apiName, + }), + }); + this.functionMonitoring = new AggregatedFunctionMonitoring(this.monitoring, { + title: 'Lambda metrics', + apiName: props.apiName, + functions: {}, + }); + } + + } + + protected addSingleTableMonitoring(dataStore: SingleTableDatastore) { + if (this.monitoring) { + this.monitoring.monitorDynamoTable({ table: dataStore.table }); + } + } + + protected addFunctionToMonitoring(operationId: string, fn: IFunction) { + if (this.monitoring && this.functionMonitoring) { + this.functionMonitoring?.addFunction(operationId, fn); + } + } + + protected addFunctionMonitoringSegment() { + if (this.monitoring && this.functionMonitoring) { + this.monitoring.addSegment(this.functionMonitoring); + } } } diff --git a/src/constructs/graphql.ts b/src/constructs/graphql.ts index 5fb03716..42b5b430 100644 --- a/src/constructs/graphql.ts +++ b/src/constructs/graphql.ts @@ -147,6 +147,17 @@ export class GraphQlApi extends BaseApi { }, }, }); + + if (this.monitoring) { + this.monitoring.monitorAppSyncApi({ + api: this.api, + }); + this.addFunctionMonitoringSegment(); + if (props.singleTableDatastore) { + this.addSingleTableMonitoring(props.singleTableDatastore); + } + } + if (customDomainName && this.api.appSyncDomainName) { new aws_route53.CnameRecord(this, 'DnsRecord', { zone: this.hostedZone!, @@ -155,57 +166,6 @@ export class GraphQlApi extends BaseApi { }); } - // if ((props.monitoring ?? true) && this.monitoring) { - // this.monitoring.apiErrorsWidget.addLeftMetric(new cloudwatch.Metric({ - // namespace: 'AWS/AppSync', - // metricName: '5XXError', - // dimensionsMap: { - // GraphQLAPIId: this.api.apiId, - // }, - // statistic: 'sum', - // })); - // this.monitoring.apiErrorsWidget.addLeftMetric(new cloudwatch.Metric({ - // namespace: 'AWS/AppSync', - // metricName: '4XXError', - // dimensionsMap: { - // GraphQLAPIId: this.api.apiId, - // }, - // statistic: 'sum', - // })); - // this.monitoring.apiLatencyWidget.addLeftMetric(new cloudwatch.Metric({ - // namespace: 'AWS/AppSync', - // metricName: 'Latency', - // dimensionsMap: { - // GraphQLAPIId: this.api.apiId, - // }, - // statistic: 'Average', - // })); - // this.monitoring.apiLatencyWidget.addLeftMetric(new cloudwatch.Metric({ - // namespace: 'AWS/AppSync', - // metricName: 'Latency', - // dimensionsMap: { - // GraphQLAPIId: this.api.apiId, - // }, - // statistic: 'p90', - // })); - // this.monitoring.apiLatencyTailWidget.addLeftMetric(new cloudwatch.Metric({ - // namespace: 'AWS/AppSync', - // metricName: 'Latency', - // dimensionsMap: { - // GraphQLAPIId: this.api.apiId, - // }, - // statistic: 'p95', - // })); - // this.monitoring.apiLatencyTailWidget.addLeftMetric(new cloudwatch.Metric({ - // namespace: 'AWS/AppSync', - // metricName: 'Latency', - // dimensionsMap: { - // GraphQLAPIId: this.api.apiId, - // }, - // statistic: 'p99', - // })); - // } - if (props.singleTableDatastore) { this.tableDataSource = new aws_appsync.DynamoDbDataSource(this, 'SingleTableSource', { api: this.api, @@ -281,12 +241,9 @@ export class GraphQlApi extends BaseApi { this._functions[operationId] = fn; Tags.of(fn).add('GraphQL', description); - // if (this.monitoring) { - // this.monitoring.lambdaDurationsWidget.addLeftMetric(fn.metricDuration()); - // this.monitoring.lambdaInvokesWidget.addLeftMetric(fn.metricInvocations()); - // this.monitoring.lambdaErrorsWidget.addLeftMetric(fn.metricErrors()); - // this.monitoring.lambdaErrorsWidget.addLeftMetric(fn.metricThrottles()); - // } + if (this.monitoring) { + this.addFunctionToMonitoring(operationId, fn); + } const dataSource = new aws_appsync.LambdaDataSource(this, `LambdaDS${operationId}`, { api: this.api, diff --git a/src/constructs/load-yaml.ts b/src/constructs/load-yaml.ts new file mode 100644 index 00000000..66e8df0e --- /dev/null +++ b/src/constructs/load-yaml.ts @@ -0,0 +1,5 @@ +import fs from 'fs'; +import * as yaml from 'js-yaml'; +import { OpenAPI3 } from 'openapi-typescript'; + +export const loadYaml = (filename: string) => yaml.load(fs.readFileSync(filename).toString()) as OpenAPI3; diff --git a/src/constructs/monitoring/aggregated-function-monitoring.ts b/src/constructs/monitoring/aggregated-function-monitoring.ts new file mode 100644 index 00000000..979522ef --- /dev/null +++ b/src/constructs/monitoring/aggregated-function-monitoring.ts @@ -0,0 +1,101 @@ +import fs from 'fs'; +import { GraphWidget, IWidget, Row } from 'aws-cdk-lib/aws-cloudwatch'; +import { IFunction } from 'aws-cdk-lib/aws-lambda'; +import { + BaseMonitoringProps, CountAxisFromZero, DefaultGraphWidgetHeight, + Monitoring, + MonitoringHeaderWidget, + MonitoringScope, + ThirdWidth, TimeAxisMillisFromZero, +} from 'cdk-monitoring-constructs'; + +export interface AggregatedFunctionMonitoringProps extends BaseMonitoringProps { + functions: Record; + apiName: string; + title: string; +} + +export class AggregatedFunctionMonitoring extends Monitoring { + + readonly title: string; + readonly apiName: string; + + private readonly _functions: Record; + + constructor(scope: MonitoringScope, props: AggregatedFunctionMonitoringProps) { + super(scope, props); + + this.title = props.title; + this.apiName = props.apiName; + this._functions = props.functions; + } + + addFunction(operationId: string, func: IFunction) { + if (Object.keys(this._functions).includes(operationId)) { + throw new Error(`Operation '${operationId}' is being registered for monitoring twice!`); + } + this._functions[operationId] = func; + console.log(`Added ${operationId}`); + } + + createTitleWidget() { + const descriptionFile = `src/definitions/monitoring/${this.apiName}.description.md`; + let description = `Create a file named '${descriptionFile}' to add a description to this API`; + if (fs.existsSync(descriptionFile)) { + description = fs.readFileSync(descriptionFile).toString('utf-8'); + } + return new MonitoringHeaderWidget({ + family: this.apiName, + title: this.title, + description, + }); + } + + createDurationWidget(width: number, height: number) { + return new GraphWidget({ + width, + height, + title: 'Lambda Duration', + left: Object.entries(this._functions).map(([operationId, fn]) => fn.metricDuration({ label: operationId })), + leftYAxis: TimeAxisMillisFromZero, + }); + } + + createErrorsWidget(width: number, height: number) { + return new GraphWidget({ + width, + height, + title: 'Lambda Errors/Throttles', + left: [ + ...Object.entries(this._functions).map(([operationId, fn]) => fn.metricErrors({ label: operationId })), + ...Object.entries(this._functions).map(([operationId, fn]) => fn.metricThrottles({ label: operationId })), + ], + leftYAxis: CountAxisFromZero, + }); + } + + createInvocationsWidget(width: number, height: number) { + return new GraphWidget({ + width, + height, + title: 'Lambda Invocations', + left: [ + ...Object.entries(this._functions).map(([operationId, fn]) => fn.metricInvocations({ label: operationId })), + ], + leftYAxis: CountAxisFromZero, + }); + } + + widgets(): IWidget[] { + console.log(`Adding widgets for fucntions ${Object.keys(this._functions).join(', ')}`); + return [ + this.createTitleWidget(), + new Row( + this.createDurationWidget(ThirdWidth, DefaultGraphWidgetHeight), + this.createErrorsWidget(ThirdWidth, DefaultGraphWidgetHeight), + this.createInvocationsWidget(ThirdWidth, DefaultGraphWidgetHeight), + ), + ]; + } + +} \ No newline at end of file diff --git a/src/constructs/rest-api.ts b/src/constructs/rest-api.ts index 1a8464d5..5bf12980 100644 --- a/src/constructs/rest-api.ts +++ b/src/constructs/rest-api.ts @@ -1,4 +1,3 @@ -import * as fs from 'fs'; import { aws_certificatemanager, aws_iam, @@ -8,11 +7,11 @@ import { } from 'aws-cdk-lib'; import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; -import * as yaml from 'js-yaml'; import { OpenAPI3, OperationObject, PathItemObject } from 'openapi-typescript'; import { ICognitoAuthentication, IJwtAuthentication } from './authentication'; import { BaseApi, BaseApiProps } from './base-api'; import { LambdaFunction, LambdaOptions } from './func'; +import { loadYaml } from './load-yaml'; import { CFN_OUTPUT_SUFFIX_RESTAPI_DOMAINNAME, CFN_OUTPUT_SUFFIX_RESTAPI_URL } from '../shared/outputs'; export interface RestApiProps extends BaseApiProps { @@ -95,7 +94,7 @@ export class RestApi extends BaseApi { constructor(scope: Construct, id: string, private props: RestApiProps) { super(scope, id, props); - this.apiSpec = yaml.load(fs.readFileSync(props.definitionFileName).toString()) as OpenAPI3; + this.apiSpec = loadYaml(props.definitionFileName); let customDomainName: aws_apigateway.DomainNameOptions | undefined; if (this.apiFQDN) { @@ -116,28 +115,6 @@ export class RestApi extends BaseApi { }); } - // if ((props.monitoring ?? true) && this.monitoring) { - // this.monitoring.apiErrorsWidget.addLeftMetric(this.api.metricServerError({ - // statistic: 'sum', - // })); - // this.monitoring.apiErrorsWidget.addLeftMetric(this.api.metricClientError({ - // statistic: 'sum', - // })); - - // this.monitoring.apiLatencyWidget.addLeftMetric(this.api.metricLatency({ - // statistic: 'Average', - // })); - // this.monitoring.apiLatencyWidget.addLeftMetric(this.api.metricLatency({ - // statistic: 'p90', - // })); - // this.monitoring.apiLatencyTailWidget.addLeftMetric(this.api.metricLatency({ - // statistic: 'p95', - // })); - // this.monitoring.apiLatencyTailWidget.addLeftMetric(this.api.metricLatency({ - // statistic: 'p99', - // })); - // } - if (props.autoGenerateRoutes ?? true) { for (const path in this.apiSpec.paths) { if (Object.prototype.hasOwnProperty.call(this.apiSpec.paths, path)) { @@ -240,6 +217,19 @@ export class RestApi extends BaseApi { ...props.restApiProps, }); + if (this.monitoring) { + this.monitoring.addLargeHeader(`${props.apiName} Rest API Monitoring`); + this.monitoring.monitorApiGateway({ + api: this.api, + }); + + // FIXME This currently depends on the side effects of having generated the routes further above + this.addFunctionMonitoringSegment(); + if (props.singleTableDatastore) { + this.addSingleTableMonitoring(props.singleTableDatastore); + } + } + // add invoke permissions to Lambda functions for (const fn of Object.values(this._functions)) { fn.addPermission('RestApiInvoke', { @@ -352,13 +342,6 @@ export class RestApi extends BaseApi { this._functions[operation.operationId!] = fn; cdk.Tags.of(fn).add('OpenAPI', description.replace(/[^\w\s\d_.:/=+\-@]/g, '')); - // if (this.monitoring) { - // this.monitoring.lambdaDurationsWidget.addLeftMetric(fn.metricDuration()); - // this.monitoring.lambdaInvokesWidget.addLeftMetric(fn.metricInvocations()); - // this.monitoring.lambdaErrorsWidget.addLeftMetric(fn.metricErrors()); - // this.monitoring.lambdaErrorsWidget.addLeftMetric(fn.metricThrottles()); - // } - const hasVersionConfig = lambdaOptions.currentVersionOptions != undefined; operation['x-amazon-apigateway-integration'] = { @@ -376,6 +359,10 @@ export class RestApi extends BaseApi { payloadFormatVersion: '1.0', }; + if (this.monitoring) { + this.addFunctionToMonitoring(operation.operationId!, fn); + } + return fn; } diff --git a/test/constructs/__snapshots__/rest-api.test.ts.snap b/test/constructs/__snapshots__/rest-api.test.ts.snap new file mode 100644 index 00000000..a9ea4996 --- /dev/null +++ b/test/constructs/__snapshots__/rest-api.test.ts.snap @@ -0,0 +1,48 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`A generated RestApi when instantiated with monitoring active should create a Cloudwatch Dashboard 1`] = ` +{ + "TestSubjectDashboardFactoryDashboardEAA7D797": { + "Properties": { + "DashboardBody": { + "Fn::Join": [ + "", + [ + "{"start":"-PT8H","periodOverride":"inherit","widgets":[{"type":"text","width":24,"height":1,"x":0,"y":0,"properties":{"markdown":"# TestSubjectApi Rest API Monitoring"}},{"type":"text","width":24,"height":1,"x":0,"y":1,"properties":{"markdown":"### API Gateway Endpoint **TestSubjectApi [test] prod**"}},{"type":"metric","width":6,"height":5,"x":0,"y":2,"properties":{"view":"timeSeries","title":"TPS","region":"", + { + "Ref": "AWS::Region", + }, + "","metrics":[[{"label":"Count/s","expression":"FILL(requests,0) / PERIOD(requests)"}],["AWS/ApiGateway","Count","ApiName","TestSubjectApi [test]","Stage","prod",{"label":"Count","stat":"Sum","visible":false,"id":"requests"}]],"yAxis":{"left":{"min":0,"label":"Count","showUnits":false}}}},{"type":"metric","width":6,"height":5,"x":6,"y":2,"properties":{"view":"timeSeries","title":"Latency","region":"", + { + "Ref": "AWS::Region", + }, + "","metrics":[["AWS/ApiGateway","Latency","ApiName","TestSubjectApi [test]","Stage","prod",{"label":"P50 (avg: \${AVG})","stat":"p50"}],["AWS/ApiGateway","Latency","ApiName","TestSubjectApi [test]","Stage","prod",{"label":"P90 (avg: \${AVG})","stat":"p90"}],["AWS/ApiGateway","Latency","ApiName","TestSubjectApi [test]","Stage","prod",{"label":"P99 (avg: \${AVG})","stat":"p99"}]],"yAxis":{"left":{"min":0,"label":"ms","showUnits":false}}}},{"type":"metric","width":6,"height":5,"x":12,"y":2,"properties":{"view":"timeSeries","title":"Errors","region":"", + { + "Ref": "AWS::Region", + }, + "","metrics":[["AWS/ApiGateway","4XXError","ApiName","TestSubjectApi [test]","Stage","prod",{"label":"4XX Error","stat":"Sum"}],["AWS/ApiGateway","5XXError","ApiName","TestSubjectApi [test]","Stage","prod",{"label":"5XX Fault","stat":"Sum"}]],"yAxis":{"left":{"min":0,"label":"Count","showUnits":false}}}},{"type":"metric","width":6,"height":5,"x":18,"y":2,"properties":{"view":"timeSeries","title":"Errors (rate)","region":"", + { + "Ref": "AWS::Region", + }, + "","metrics":[["AWS/ApiGateway","4XXError","ApiName","TestSubjectApi [test]","Stage","prod",{"label":"4XX Error (avg)"}],["AWS/ApiGateway","5XXError","ApiName","TestSubjectApi [test]","Stage","prod",{"label":"5XX Fault (avg)"}]],"yAxis":{"left":{"min":0,"label":"Rate","showUnits":false}}}},{"type":"text","width":24,"height":2,"x":0,"y":7,"properties":{"markdown":"### TestSubjectApi **Lambda metrics**\\n\\nCreate a file named 'src/definitions/monitoring/TestSubjectApi.description.md' to add a description to this API"}},{"type":"metric","width":8,"height":5,"x":0,"y":9,"properties":{"view":"timeSeries","title":"Lambda Duration","region":"", + { + "Ref": "AWS::Region", + }, + "","metrics":[["TestNamespace","Duration"]],"yAxis":{"left":{"min":0,"label":"ms","showUnits":false}}}},{"type":"metric","width":8,"height":5,"x":8,"y":9,"properties":{"view":"timeSeries","title":"Lambda Errors/Throttles","region":"", + { + "Ref": "AWS::Region", + }, + "","metrics":[["TestNamespace","Errors"],["TestNamespace","Invocations"]],"yAxis":{"left":{"min":0,"label":"Count","showUnits":false}}}},{"type":"metric","width":8,"height":5,"x":16,"y":9,"properties":{"view":"timeSeries","title":"Lambda Invocations","region":"", + { + "Ref": "AWS::Region", + }, + "","metrics":[["TestNamespace","Invocations"]],"yAxis":{"left":{"min":0,"label":"Count","showUnits":false}}}}]}", + ], + ], + }, + "DashboardName": "TestSubjectApi", + }, + "Type": "AWS::CloudWatch::Dashboard", + }, +} +`; diff --git a/test/constructs/rest-api.test.ts b/test/constructs/rest-api.test.ts new file mode 100644 index 00000000..f103d9f3 --- /dev/null +++ b/test/constructs/rest-api.test.ts @@ -0,0 +1,109 @@ +import { App, Stack } from 'aws-cdk-lib'; +import { Template } from 'aws-cdk-lib/assertions'; +import { Metric, MetricOptions } from 'aws-cdk-lib/aws-cloudwatch'; +import { Permission } from 'aws-cdk-lib/aws-lambda'; +import { Construct } from 'constructs'; +import { OpenAPI3 } from 'openapi-typescript'; +import { LambdaFunction, LambdaFunctionProps, RestApi } from '../../src/constructs'; +import { loadYaml } from '../../src/constructs/load-yaml'; + +jest.mock('../../src/constructs/load-yaml'); +jest.mock('../../src/constructs/func'); + + +describe('A generated RestApi', () => { + + describe('when instantiated with monitoring active', () =>{ + let stack: Stack; + beforeEach(() => { + const app = new App(); + stack = new Stack(app); + }); + + test('should create a Cloudwatch Dashboard', () => { + interface Operations { + testEndpoint: { + responses: { + 200: {}; + }; + }; + } + + interface Paths { + '/test': { + get: Operations['testEndpoint']; + }; + } + + const buffer = { + openapi: '3.0.1', + paths: { + '/test': { + get: { + operationId: 'testEndpoint', + responses: { + 200: { + content: { + 'application/json': {}, + }, + description: '', + summary: '', + }, + }, + }, + }, + }, + info: { + title: 'Existing API definition', + version: '1.0', + }, + } as OpenAPI3; + + jest.mocked(loadYaml).mockReturnValue(buffer); + jest.mocked(LambdaFunction).mockImplementation((_scope: Construct, _id: string, _mockProps: LambdaFunctionProps) => { + return { + metricDuration(_props?: MetricOptions): Metric { + return new Metric({ + metricName: 'Duration', + namespace: 'TestNamespace', + }); + }, + metricInvocations(_props?: MetricOptions): Metric { + return new Metric({ + metricName: 'Invocations', + namespace: 'TestNamespace', + }); + }, + metricErrors(_props?: MetricOptions): Metric { + return new Metric({ + metricName: 'Errors', + namespace: 'TestNamespace', + }); + }, + metricThrottles(_props?: MetricOptions): Metric { + return new Metric({ + metricName: 'Invocations', + namespace: 'TestNamespace', + }); + }, + addPermission(__id: string, __permission: Permission) { + }, + } as LambdaFunction; + }); + + new RestApi(stack, 'TestSubject', { + monitoring: true, + apiName: 'TestSubjectApi', + definitionFileName: 'someFile', + cors: true, + stageName: 'test', + }); + + const template = Template.fromStack(stack); + + expect(template.findResources('AWS::CloudWatch::Dashboard')).toMatchSnapshot(); + + }); + }); + +}); \ No newline at end of file