Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make it easier to drop levels of abstraction and access CloudFormation outputs. Allow a.handler.function to have a datasource. #1658

Closed
sisygoboom opened this issue Jun 15, 2024 · 1 comment
Labels
feature-request New feature or request function Issue pertaining to Amplify Function

Comments

@sisygoboom
Copy link

sisygoboom commented Jun 15, 2024

Environment information

N/A

Description

Amplify's backend currently makes anything outside of the expected patterns extremely difficult. This is because of a combination of two things:

  1. Automated resource creation
  2. Inability to access the low-level CDK constructs from said resource creation in a typesafe or object-oriented way with the ARNs attached

Example/steps to reproduce:

I have a custom resolver in my schema, it needs a role with access to write to DynamoDB.

I can see the problem from the console and its an easy fix:

Failed to process request: User: arn:aws:sts::592261843145:assumed-role/amplify-paritaeapp-chris--getMessagesByConversation-iAvA6ZVYEWJM/amplify-paritaeapp-chris--getMessagesByConversatio-esQehfeuATUS is not authorized to perform: dynamodb:Query on resource: arn:aws:dynamodb:eu-west-2:592261843145:table/ChatTable because no identity-based policy allows the dynamodb:Query action

but defineFunction does not allow me to modify any of the constructs. Next logical step would be to add a dynamodbdatasource to the handler but that is also not an option because a.handler.function only has the property brandSymbol and no additional parameters besides the function. Next bet is to try a.query()...authorization(allow => ['dynamodb:Query']) or something similar but that allow only includes IAM options. Event the defineData factory returns nothing of use.

After exhausting options in data/resource.ts I looked for possibilities in backend.ts but unfortunately this turned out to be impossible without running into a circular dependency. It also doesn't help that while the cloudformation outputs are present somewhere in backend its not easy to navigate as the typing system here is very loose and the random hash applied to resources by amplify make it impossible to guess/hardcode the arn.

// backend.ts

import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';
import { data } from './data/resource';
import { AttributeType, BillingMode, Table } from 'aws-cdk-lib/aws-dynamodb';
import { Stack } from 'aws-cdk-lib';

const backend = defineBackend({
  auth,
  data,
});

// Define the DynamoDB table
const chatTable = new Table(Stack.of(backend.data), "ChatTable", {
  tableName: "ChatTable",
  partitionKey: {
    name: "pk",
    type: AttributeType.STRING,
  },
  sortKey: {
    name: "sk",
    type: AttributeType.STRING,
  },
  billingMode: BillingMode.PAY_PER_REQUEST,
});

// Add the DynamoDB data source to the backend
backend.data.addDynamoDbDataSource("ChatTableDataSource", chatTable);

export default backend;

// data/resource.ts

import { type ClientSchema, a, defineData, defineFunction } from '@aws-amplify/backend';

export const getMessagesByConversationId = defineFunction({
  name: 'getMessagesByConversationIdFunction',
  entry: './getMessagesByConversationId.ts',
});

const schema = a.schema({
  ChatTable: a.customType({
    pk: a.string().required(),
    sk: a.string().required(),
    type: a.string().required(),
    message: a.string(),
    userId: a.string(),
    conversationId: a.string(),
    timestamp: a.string(),
  }),
  getMessagesByConversationId: a
    .query()
    .arguments({
      conversationId: a.string().required(),
      lastKey: a.string(),
    })
    .returns(a.ref("ChatTable").array())
    .handler(a.handler.function(getMessagesByConversationId))
    .authorization(allow => [allow.publicApiKey()]),
})
.authorization(allow => [
  allow.resource(getMessagesByConversationId).to(['query']),
]);

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: 'apiKey',
    apiKeyAuthorizationMode: {
      expiresInDays: 30
    },
  }
});
@sisygoboom sisygoboom added the pending-triage Incoming issues that need categorization label Jun 15, 2024
@ykethan
Copy link
Member

ykethan commented Jun 19, 2024

Hey @sisygoboom, thank you for reaching out.
From the error message and behavior observed on the backend.ts, the issue appears to similar to
#1375
#1552

Could you try the suggestions on comments #1375 (comment)
#1552 (comment)

You should be able to access the table name on the backend.ts for example backend.data.resources.tables["Todo"].tableArn which should return a token and resolved by CloudFormation.
Do let us know if i may have misunderstood anything.

But i do agree, a prop to add datasources on the function would be great. Marking this as feature request.

@ykethan ykethan added feature-request New feature or request function Issue pertaining to Amplify Function and removed pending-triage Incoming issues that need categorization labels Jun 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request New feature or request function Issue pertaining to Amplify Function
Projects
None yet
Development

No branches or pull requests

2 participants