1

I'm trying to find the table name to use the dynamo db that is auto generated using AWS Amplify after creating a schema using 'data'. How can I find that?

Here is what I've tried:

resource.ts file

const schema = a
  .schema({
    UserProfileFlags: a.customType({
      isBetaUser: a.boolean(),
      isFounder: a.boolean(),
      isBanned: a.boolean(),
      isSuspended: a.boolean(),
      isVerified: a.boolean(),
      isDeleted: a.boolean(),
    }),

    UserProfile: a
      .model({
        userName: a.string().required(),
        owner: a
          .string()
          .authorization((allow) => [allow.owner().to(['read', 'delete'])]),
...

to define a database in dynamo named UserProfile. That works fine, the db is created and the table exists. Now I'm trying to create a function to access that table. I've tried many iterations, but they all have errors/won't compile or work:

I found this:

import { DynamoDB } from 'aws-sdk';
import { getDataSource } from '@aws-amplify/backend-function';
import type { Schema } from '../../data/resource';

const dynamodb = new DynamoDB.DocumentClient();

export const handler: Schema['createEmptyProfile']['handler'] = async (event, context) => {
  const dataSource = getDataSource(context);
  const TABLE_NAME = dataSource.resources.UserProfile.tableName;

This one tells me that import { getDataSource } from '@aws-amplify/backend-function'; is a problem:

Module '"@aws-amplify/backend-function"' has no exported member 'getDataSource'.ts(2305)

I've also tried running this: npx ampx generate graphql-client-code --out /graphql

and then

import { env } from "$amplify/env/post-confirmation";
...
        endpoint: env.AMPLIFY_DATA_GRAPHQL_ENDPOINT,
...

But this too shows AMPLIFY_DATA_GRAPHQL_ENDPOINT is undefined, and if I look in the generated .ts files, I don't see it either.

That kind of makes sense, since I'm not sure how that would work when deployed, as it needs a different table name. This is all running against a local sandbox.

Here is the docs link that I can find: https://docs.amplify.aws/react/build-a-backend/functions/examples/create-user-profile-record/

1
  • I'm using Gen2. I would think that would be the correct version, but it seems like Gen1 is way more common. Commented Oct 29, 2024 at 22:33

3 Answers 3

3

You can get the access to the table name (and other details) after defineBackend() is done, like this:

backend.data.resources.tables["UserProfile"].tableName

But in order to use it in your lambda function, add it as env var to the function:

backend.createEmptyProfile.addEnvironment("USER_PROFILE_TABLE", backend.data.resources.tables["UserProfile"].tableName);

And inside the function, just access it with this:

import { env } from "$amplify/env/createEmptyProfile";

const TABLE_NAME = env.USER_PROFILE_TABLE;

NOTE: "env" will be updated locally (so you don't get ts errors) only after you've saved backend.js and run npx ampx sandbox

NOTE2: in order to avoid circular dependency issue when provisioning cloud formation stack, the function needs to belong to the same resource group as the models; for your case I believe this would do it - in the defineFunction() add:

  resourceGroupName: "data",
Sign up to request clarification or add additional context in comments.

1 Comment

using backend.data.resources.tables["UserProfile"].tableName for env creates circular dependency issue and adding resourceGroupName as data also didn't help .
1

I'm running Amplify Gen 2 also; here's what worked for me.

I wasn't able to get any solution involving setting environment variables to work reliably. But what did work was to create SSM parameters with the values I needed, and grant my lambda permissions to read them.

In my backend, after creating the resources I need (AccountTable's ARN, in this case):

const envName = process.env.AMPLIFY_BRANCH || 'dev';
const accountTableParam = new cdk.aws_ssm.StringParameter(
  apiStack,
  "AccountTableParam",
  {
    parameterName: `/secure-site/${envName}/account-table-name`,
    stringValue: accountTable.tableName,
  }
);

const allowSignLambdaToAccessAccountTablePolicy = new Policy(
  cdk.Stack.of(accountTable),
  "allowSignLambdaToAccessAccountTablePolicy",
  {
    statements: [
      new PolicyStatement({
        effect: Effect.ALLOW,
        actions: [
          "dynamodb:GetItem",
          "dynamodb:UpdateItem",
          "dynamodb:Query",
          "dynamodb:Scan",
        ],
        resources: [accountTable.tableArn],
      }),
      new PolicyStatement({
        effect: Effect.ALLOW,
        actions: ["ssm:GetParameter"],
        resources: [
          accountTableParam.parameterArn,
        ],
      }),
    ],
  }
);

Then in my lambda's code, I could read the parameter:

const ssmClient = new SSMClient();
const envName = process.env.AMPLIFY_BRANCH || 'dev';

async function getParameter(name: string): Promise<string> {
  const paramPath = `/secure-site/${envName}/${name}`;
  const command = new GetParameterCommand({ Name: paramPath });
  const response = await ssmClient.send(command);
  return response.Parameter?.Value || '';
}

const table = await getParameter('account-table-name');

Comments

0

Here's how to programmatically find your DynamoDB table names by querying the AppSync API:

  1. Find your AppSync API ID by matching the GraphQL URL
  2. List all data sources for that API
  3. Extract table names from DynamoDB data sources

import { AppSyncClient, ListDataSourcesCommand, ListGraphqlApisCommand } from "@aws-sdk/client-appsync";

async function getTableMappingsFromAppSync(graphqlUrl: string, region: string) {
  const appSyncClient = new AppSyncClient({ region });

  // Step 1: Find API ID by matching GraphQL URL
  const listApisResult = await appSyncClient.send(new ListGraphqlApisCommand({}));
  const matchingApi = listApisResult.graphqlApis?
    .find(api =>api.uris?.GRAPHQL === graphqlUrl);

  if (!matchingApi?.apiId) {
    throw new Error(`Could not find AppSync API with URL: ${graphqlUrl}`);
  }

  // Step 2: Get all data sources for this API
  const listDataSourcesResult = await appSyncClient.send(new ListDataSourcesCommand(
    { apiId: matchingApi.apiId })
  );

  // Step 3: Extract table names from DynamoDB data sourcesconst tableMappings:
  Record<string, string> = {};

  for (const dataSource of listDataSourcesResult.dataSources || []) {
    if (dataSource.type === "AMAZON_DYNAMODB" && dataSource.dynamodbConfig?.tableName) {
    // Extract model name from data source name (e.g., "CampaignTable" -> "Campaign")
    const modelName = dataSource.name?.replace(/Table$/, '');
    if (modelName) {
      tableMappings[modelName] = dataSource.dynamodbConfig.tableName; 
    }
  }
}

return tableMappings;

}

const url = amplify_outputs.data.url;
const region = amplify_outputs.data.aws_region;
const tableMappings = await getTableMappingsFromAppSync(url, region);
console.log(tableMappings);
// Output: { User: "User-def456" }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.