Creating a CDK resource in TypeScript if it doesn't already exist

Recently, I set up a DynamoDB table in my CDK project to be used by lambdas within the same project. Everything was working fine until we needed to delete the stack with the retain resource option set to true for the table.

However, when attempting a fresh deployment, we encountered an error stating that the table already exists, leading to the entire stack rolling back. I am now looking for code that will create the table only if it does not already exist.

Here is a snippet of the basic table creation code. Despite searching extensively, I have been unable to find any documentation addressing this issue or detailing the specific exception that needs to be caught. All we see are logs on the AWS CloudFormation console.

 const dynamoTable = new Table(this, "my-table", {
      tableName: StackConfiguration.tableName,
      partitionKey: { name: "id", type: AttributeType.STRING },
    });

Answer №1

Regrettably, accomplishing that task in CDK is not possible due to the fact that CDK generates CloudFormation template during compile time rather than runtime. There are a few alternative approaches available:

  1. Utilize CloudFormation Resource Import to bring an existing table into your stack
  2. Implement a Custom resource lambda function to execute an AWS API call for checking the existence of the table. Then use the Custom resource output within Fn.conditionEquals in the CDK code to conditionally create the table

If this task is a one-time occurrence, it is suggested to go with the first option. On the other hand, if this task is expected to be recurring, option 2 would be more suitable.

Answer №2

Starting in September 2023, the CloudFormation Development Kit (CDK) now offers the ability to import existing resources. I successfully followed the steps outlined to import my existing DynamoDB table using the CDK. However, upon running the cdk import command, an error was thrown stating that there were changes detected in my Lambda functions despite the cdk diff showing no modifications. To resolve this issue, I had to include the --force option with the import command.

Please note that this method did not align with the original intention of @AnonymousAlias, who wanted to either create the resource if it didn't exist or skip it if it did. As suggested by @Tofig Hasanov, a workaround would involve checking for the existence of the resource before creating it.

Referencing https://docs.aws.amazon.com/cdk/v2/guide/cli.html#cli-import:

Importing existing resources into a stack

The cdk import command allows you to incorporate resources into the management of an AWS CDK stack through CloudFormation. This is useful for scenarios such as transitioning to AWS CDK, migrating resources between stacks, or altering their logical identifier. The cdk import operation leverages CloudFormation resource imports. Here's a list of supported resources eligible for import.

To import an existing resource into an AWS CDK stack, follow these steps:

  • Ensure the resource is not under the governance of another CloudFormation stack. If so, adjust the removal policy to RemovalPolicy.RETAIN within the current stack, conduct a deployment, then exclude the resource and deploy again to release it from CloudFormation management without deletion.

  • Perform a cdk diff operation to confirm no impending changes in the target AWS CDK stack. Only additions of new resources are permitted during an "import" process.

  • Add constructs representing the resources intended for import into your stack. For instance, to import an Amazon S3 bucket, add a construct like new s3.Bucket(this, 'ImportedS3Bucket', {});. Avoid making adjustments to other resources.

    It's crucial to accurately model the current state of the resource into the definition. Include all pertinent details such as AWS KMS keys and lifecycle policies for the bucket. Neglecting this could lead to unexpected outcomes during subsequent updates.

    You have the flexibility to decide whether or not to include the physical bucket name. Omitting resource names from your AWS CDK definitions simplifies the process for deploying resources repeatedly.

  • Execute cdk import STACKNAME.

  • If the resource names are absent in your model, the CLI will prompt you to provide the actual names of the resources being imported. Once identified, the import process commences.

  • Upon successful completion reported by cdk import, the resource becomes managed by AWS CDK and CloudFormation. Subsequent alterations made to the resource properties within your AWS CDK app or the construct configuration will take effect in the next deployment.

  • To verify that the resource definition in your AWS CDK app corresponds with the current state of the resource, initiate a CloudFormation drift detection operation.

Kindly note that this feature currently does not support importing resources into nested stacks.

Answer №3

Although not the most optimal solution, I have come up with a workaround that might be helpful to someone. By incorporating table creation within a try-catch block in our code, we can handle exceptions more effectively. Instead of catching a general exception, it would be useful to identify the specific one for better error handling. This approach ensures the successful deployment of the stack.

 try {
     const dynamoTable = new Table(this, "my-table", {
      tableName: StackConfiguration.tableName,
      partitionKey: { name: "id", type: AttributeType.STRING },
    });
    
      return dynamoReplayTable;
    } catch (e) {
      return;
    }

To utilize the table effectively in your code, consider referencing the ARN instead of the table variable name. Alternatively, you could explore importing from the name within the catch block. However, the most efficient solution is to maintain tables in a separate stack.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to display Leaflet pins within Angular?

I've been working with Leaflet and despite extensive research, I'm still struggling to get my marker to display on the map. I've tried all the solutions available out there, including the Angular workaround recommended by Leaflet. Currently ...

Attempting to utilize Array Methods with an Array Union Type

Currently, I am in the process of refactoring an Angular application to enable strict typing. One issue I have encountered is using array methods with an array union type in our LookupService. When attempting to call const lookup = lookupConfig.find(l =&g ...

Declaration of types for invoking the lodash `mapKeys` function

Is there a way to create a function that can map object keys from camelCase to snakeCase, and be used multiple times with different objects? I have already written a function called mapKeysToSnakeCase which does the job, but I'm curious if there is a ...

"Optimizing Performance: Discovering Effective Data Caching

As a developer, I have created two functions - one called Get to fetch data by id from the database and cache it, and another called POST to update data in the database. However, I am facing an issue where I need to cache after both the get and update oper ...

The display of the selected input is not appearing when the map function is utilized

I am attempting to use Material UI Select, but it is not functioning as expected. When I use the map function, the default value is not displayed as I would like it to be. However, it does work properly when using the traditional method. *** The Method th ...

When using Angular, receiving a "Bad Request" error message with a status code of 400 after making a POST

I am encountering an issue when trying to send register form data to my server as I keep receiving a (Bad Request) error. Interestingly, the server works correctly when tested with postman using the following data: { "username": "root", "email": " ...

Best practices for implementing dual ngFor directives within a single tr element?

Click here to view the page The image attached shows the view I want to iterate through two ngFor loops inside the tr tag. When using a div tag inside the tr, it's looping the button next to the tag instead of where I want it in the file table header ...

Building a gateway for integrating a scikit-learn model within AWS Sagemaker

My goal is to establish an endpoint for a scikit-learn logistic regression model within Amazon SageMaker. I have the scikit-learn code stored in a file named scikitlogistic.py. Below is the content of the scikitlogistic.py file: import subprocess as sb im ...

Steering clear of the generic Function type in React with TypeScript

Can anyone help me find a guideline that prohibits the use of "Function" as a type? myMethod: Function; I have searched but couldn't locate any information on this. Appreciate any suggestions :) ...

Turning an array of strings into a multidimensional array

I have a JavaScript string array that I need to convert into a multidimensional array: const names = [ "local://john/doe/blog", "local://jane/smith/portfolio", "as://alexander/wong/resume" ]; The desired output sh ...

Webpack 5 is failing to bundle re-exports correctly

Whilst bundling my web application, I've come across an issue with re-exports of certain modules not behaving as expected. Despite trying various optimization settings, I have been unsuccessful in resolving this issue. Setup Here's the setup tha ...

Encountering difficulties transferring data from a parent to a child component within Angular 9

In my current situation, I am passing a variable's value up to its grand-parent component using EventEmitter successfully. However, once the value reaches the grand-parent, I want to pass it to another child component within that grand-parent. I have ...

Utilize Immer and ES6 to effortlessly update a nested object within the Redux store by manipulating normalized data structure

I own a store where I use the global Update action I am interested in updating only a section of the data, without having to get the full data again to normalize Here is how my store looks like: { store:{ students:{ "1": { "n ...

Experiencing issues with effectively using a component

I have created a component, but I am unable to use it. This is a problem I have never faced before. https://i.sstatic.net/n5I8V.png Despite extensive Google searches, I have not been able to find a solution. For reference, you can view an example of the ...

Can you provide some insight into why the init() method is throwing an error?

My project utilizes DynamoDB access through https://www.npmjs.com/package/react-native-dynamodb. I followed the code provided on the website for implementation. The issue I'm facing is that when hovering over my .init() method in WebStorm IDE, it sho ...

Modifying the value of a property in an object array created using the map method is ineffective

I have a collection of objects: https://i.sstatic.net/XNrcU.png Within the collection, I wished to include an additional property to the objects. To achieve this, I utilized the map function: returnArray = returnArray.map((obj) => { obj.active = "fal ...

Where can I find the endpoint URL for the Node backend deployed to the AWS S3 bucket?

Currently, I have a react application stored in an AWS S3 bucket which is functioning perfectly. Alongside, I have an operational RDS database with its endpoint accessible. Furthermore, I have a node application that runs on an express server, equipped to ...

Issue "Module not found" arises while trying to import an external JSON file in TypeScript

Working with local JSON files is not an issue for me. I've successfully implemented the following code: import data from "./example.json"; However, I encounter an error when attempting to access remote files like the one below, resulting in a "Canno ...

Error 404 Encountered During Azure Functions GET Request

I have double-checked the file and everything seems to be correct. The name matches the Azure website, the API Key is included, but I am not getting any response when trying to use this on Postman as a GET request. What could be the issue? //https://disn ...

The issue arises when attempting to call a method from the same service within jsPDF in an Angular environment

Below you will find my Angular project's pdfService. I am facing an issue where calling the this.formatter() method inside myPDF is not functioning properly. export class pdfService { formatter(value: number): string { return new Intl.N ...