) : null;
+ }
+
+ return tokenGroups.map((processedToken, i) => {
+ if (processedToken.type === 'regular') {
+ return renderProcessedToken(
+ processedToken,
+ `regular:${i}`,
+ false,
+ showLineNumbers
+ );
+ } else {
+ const highlightedCodeString = processedToken.tokens
+ .map((token) => token.line.map((line) => line.content).join(''))
+ .join('\n');
+
+ return (
+
+ {processedToken.tokens.map((token, j) => {
+ return renderProcessedToken(
+ token,
+ `highlighted:${i}:${j}`,
+ true,
+ showLineNumbers
+ );
+ })}
+
+ );
+ }
});
};
diff --git a/src/components/MDXComponents/__tests__/MDXCopyCodeButton.test.tsx b/src/components/MDXComponents/__tests__/MDXCopyCodeButton.test.tsx
index 9aa8c628b53..876e26b7129 100644
--- a/src/components/MDXComponents/__tests__/MDXCopyCodeButton.test.tsx
+++ b/src/components/MDXComponents/__tests__/MDXCopyCodeButton.test.tsx
@@ -1,8 +1,9 @@
import * as React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
-import { MDXCopyCodeButton, prepareCopyText } from '../MDXCopyCodeButton';
+import { MDXCopyCodeButton } from '../MDXCopyCodeButton';
import userEvent from '@testing-library/user-event';
import * as trackModule from '../../../utils/track';
+import { prepareCopyText } from '../utils/copy-code';
const codeString = `
import * as sns from 'aws-cdk-lib/aws-sns';
diff --git a/src/components/MDXComponents/utils/copy-code.ts b/src/components/MDXComponents/utils/copy-code.ts
new file mode 100644
index 00000000000..ef6250837f1
--- /dev/null
+++ b/src/components/MDXComponents/utils/copy-code.ts
@@ -0,0 +1,12 @@
+export const prepareCopyText = (codeString: string): string => {
+ // We need to strip out markdown comments from the code string
+ // so they don't show up in our copied text
+ const highlightStartText = /\/\/\s?highlight-start/g;
+ const highlightEndText = /\/\/\s?highlight-end/g;
+ const highlightNextLine = /\/\/\s?highlight-next-line/g;
+
+ return codeString
+ .replace(highlightStartText, '')
+ .replace(highlightEndText, '')
+ .replace(highlightNextLine, '');
+};
diff --git a/src/directory/directory.mjs b/src/directory/directory.mjs
index 8b51ded7cd2..b2f7db83bc3 100644
--- a/src/directory/directory.mjs
+++ b/src/directory/directory.mjs
@@ -229,7 +229,7 @@ export const directory = {
path: 'src/pages/[platform]/build-a-backend/functions/index.mdx',
children: [
{
- path: 'src/pages/[platform]/build-a-backend/functions/set-up-function/index.mdx'
+ path: 'src/pages/[platform]/build-a-backend/functions/define-function/index.mdx'
},
{
path: 'src/pages/[platform]/build-a-backend/functions/environment-variables-and-secrets/index.mdx'
@@ -255,6 +255,12 @@ export const directory = {
{
path: 'src/pages/[platform]/build-a-backend/functions/examples/google-recaptcha-challenge/index.mdx'
},
+ {
+ path: 'src/pages/[platform]/build-a-backend/functions/examples/kinesis-stream/index.mdx'
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/functions/examples/dynamo-db-stream/index.mdx'
+ },
{
path: 'src/pages/[platform]/build-a-backend/functions/examples/bedrock-response/index.mdx'
}
@@ -271,18 +277,6 @@ export const directory = {
{
path: 'src/pages/[platform]/build-a-backend/add-aws-services/index.mdx',
children: [
- {
- path: 'src/pages/[platform]/build-a-backend/add-aws-services/custom-resources/index.mdx'
- },
- {
- path: 'src/pages/[platform]/build-a-backend/add-aws-services/overriding-resources/index.mdx'
- },
- {
- path: 'src/pages/[platform]/build-a-backend/add-aws-services/rest-api/index.mdx'
- },
- {
- path: 'src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/index.mdx'
- },
{
path: 'src/pages/[platform]/build-a-backend/add-aws-services/analytics/index.mdx',
children: [
@@ -327,6 +321,41 @@ export const directory = {
{
path: 'src/pages/[platform]/build-a-backend/add-aws-services/geo/index.mdx'
},
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/index.mdx',
+ children: [
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/set-up-in-app-messaging/index.mdx'
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/integrate-application/index.mdx'
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/sync-messages/index.mdx'
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/display-messages/index.mdx'
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/clear-messages/index.mdx'
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/identify-user/index.mdx'
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/respond-interaction-events/index.mdx'
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/resolve-conflicts/index.mdx'
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/create-campaign/index.mdx'
+ }
+ ]
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/rest-api/index.mdx'
+ },
{
path: 'src/pages/[platform]/build-a-backend/add-aws-services/predictions/index.mdx',
children: [
@@ -355,6 +384,12 @@ export const directory = {
path: 'src/pages/[platform]/build-a-backend/add-aws-services/predictions/interpret-sentiment/index.mdx'
}
]
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/custom-resources/index.mdx'
+ },
+ {
+ path: 'src/pages/[platform]/build-a-backend/add-aws-services/overriding-resources/index.mdx'
}
]
}
@@ -1587,6 +1622,9 @@ export const directory = {
},
{
path: 'src/pages/gen1/[platform]/tools/cli/migration/identity-claim-changes/index.mdx'
+ },
+ {
+ path: 'src/pages/gen1/[platform]/tools/cli/migration/iam-auth-updates-for-cdk-construct/index.mdx'
}
]
},
diff --git a/src/fragments/lib/auth/android/social_signin_web_ui/20_signin.mdx b/src/fragments/lib/auth/android/social_signin_web_ui/20_signin.mdx
index 4541aa888b1..307c0aaf76b 100644
--- a/src/fragments/lib/auth/android/social_signin_web_ui/20_signin.mdx
+++ b/src/fragments/lib/auth/android/social_signin_web_ui/20_signin.mdx
@@ -4,8 +4,9 @@ For now, just add this method to the `onCreate` method of MainActivity with what
```java
+// Replace facebook with your chosen auth provider such as google, amazon, or apple
Amplify.Auth.signInWithSocialWebUI(
- AuthProvider.facebook(),
+ AuthProvider.facebook(),
this,
result -> Log.i("AuthQuickstart", result.toString()),
error -> Log.e("AuthQuickstart", error.toString())
@@ -16,8 +17,9 @@ Amplify.Auth.signInWithSocialWebUI(
```kotlin
+// Replace facebook with your chosen auth provider such as google, amazon, or apple
Amplify.Auth.signInWithSocialWebUI(
- AuthProvider.facebook(),
+ AuthProvider.facebook(),
this,
{ Log.i("AuthQuickstart", "Sign in OK: $it") },
{ Log.e("AuthQuickstart", "Sign in failed", it) }
@@ -29,6 +31,7 @@ Amplify.Auth.signInWithSocialWebUI(
```kotlin
try {
+ // Replace facebook with your chosen auth provider such as google, amazon, or apple
val result = Amplify.Auth.signInWithSocialWebUI(AuthProvider.facebook(), this)
Log.i("AuthQuickstart", "Sign in OK: $result")
} catch (error: AuthException) {
@@ -40,6 +43,7 @@ try {
```java
+// Replace facebook with your chosen auth provider such as google, amazon, or apple
RxAmplify.Auth.signInWithSocialWebUI(AuthProvider.facebook(), this)
.subscribe(
result -> Log.i("AuthQuickstart", result.toString()),
diff --git a/src/fragments/lib/storage/android/upload.mdx b/src/fragments/lib/storage/android/upload.mdx
index c1783d213ee..bbf16c8c9fa 100644
--- a/src/fragments/lib/storage/android/upload.mdx
+++ b/src/fragments/lib/storage/android/upload.mdx
@@ -10,7 +10,7 @@ To upload data to S3 from an `InputStream`:
private void uploadInputStream() {
try {
InputStream exampleInputStream = getContentResolver().openInputStream(uri);
-
+
Amplify.Storage.uploadInputStream(
"ExampleKey",
exampleInputStream,
@@ -61,10 +61,10 @@ private suspend fun uploadInputStream(uri: Uri) {
private void uploadInputStream() {
try {
InputStream exampleInputStream = getContentResolver().openInputStream(uri);
-
+
RxProgressAwareSingleOperation rxUploadOperation =
RxAmplify.Storage.uploadInputStream("ExampleKey", exampleInputStream);
-
+
rxUploadOperation
.observeResult()
.subscribe(
@@ -81,7 +81,7 @@ private void uploadInputStream() {
## Upload files
-To upload to S3 from a data object, specify the key and the file to be uploaded.
+To upload to S3 from a data object, specify the key and the file to be uploaded.
@@ -257,6 +257,134 @@ upload
+## Transfer with Object Metadata
+
+To upload a file accompanied by metadata, utilize the `StorageUploadFileOptions` builder. Start by creating a hashMap object, then incorporate it into the `StorageUploadFileOptions` during the build process before passing it along to the upload function.
+
+
+```java
+private void uploadFile() {
+ File exampleFile = new File(getApplicationContext().getFilesDir(), "ExampleKey");
+ try {
+ BufferedWriter writer = new BufferedWriter(new FileWriter(exampleFile));
+ writer.append("Example file contents");
+ writer.close();
+ } catch (Exception exception) {
+ Log.e("MyAmplifyApp", "Upload failed", exception);
+ }
+
+ // Create metadata
+ Map userMetadata = new HashMap<>();
+ userMetadata.put("myKey", "myVal");
+
+ // Configure upload options with metadata
+ StorageUploadFileOptions options = StorageUploadFileOptions.builder()
+ .metadata(userMetadata)
+ .build();
+
+ // Perform the upload
+ Amplify.Storage.uploadFile(
+ "ExampleKey",
+ exampleFile,
+ options,
+ result -> Log.i("MyAmplifyApp", "Successfully uploaded: " + result.getKey()),
+ error -> Log.e("MyAmplifyApp", "Upload failed", error)
+ );
+}
+```
+
+
+```kotlin
+fun uploadFile() {
+ val exampleFile = File(applicationContext.filesDir, "ExampleFileName")
+ exampleFile.writeText("Example file contents")
+
+ // Create metadata
+ val userMetadata: MutableMap = HashMap()
+ userMetadata["myKey"] = "myVal"
+
+ // Configure upload options with metadata
+ val options = StorageUploadFileOptions.builder()
+ .metadata(userMetadata)
+ .build()
+
+ // Perform the upload
+ Amplify.Storage.uploadFile(
+ "ExampleKey",
+ exampleFile,
+ options,
+ { result -> Log.i("MyAmplifyApp", "Successfully uploaded: ${result.key}") },
+ { error -> Log.e("MyAmplifyApp", "Upload failed", error) }
+ )
+}
+```
+
+
+```kotlin
+fun uploadFile() {
+ val exampleFile = File(applicationContext.filesDir, "ExampleFileName")
+ exampleFile.writeText("Example file contents")
+
+ // Create metadata
+ val userMetadata: MutableMap = HashMap()
+ userMetadata["myKey"] = "myVal"
+
+ // Configure upload options with metadata
+ val options = StorageUploadFileOptions.builder()
+ .metadata(userMetadata)
+ .build()
+
+ val upload = Amplify.Storage.uploadFile("ExampleKey", exampleFile, options)
+ val progressJob = activityScope.async {
+ upload.progress().collect {
+ Log.i("MyAmplifyApp", "Fraction completed: ${it.fractionCompleted}")
+ }
+ }
+ try {
+ val result = upload.result()
+ Log.i("MyAmplifyApp", "Successfully uploaded: ${result.key}")
+ } catch (error: StorageException) {
+ Log.e("MyAmplifyApp", "Upload failed", error)
+ }
+ progressJob.cancel()
+}
+```
+
+
+```Java
+private void uploadFile() {
+ File exampleFile = new File(getApplicationContext().getFilesDir(), "ExampleKey");
+
+ try {
+ BufferedWriter writer = new BufferedWriter(new FileWriter(exampleFile));
+ writer.append("Example file contents");
+ writer.close();
+ } catch (Exception exception) {
+ Log.e("MyAmplifyApp", "Upload failed", exception);
+ }
+
+ Map userMetadata = new HashMap<>();
+ userMetadata.put("myKey", "myVal");
+
+ StorageUploadFileOptions options = StorageUploadFileOptions.builder()
+ .metadata(userMetadata)
+ .build();
+
+ RxStorageBinding.RxProgressAwareSingleOperation rxUploadOperation =
+ RxAmplify.Storage.uploadFile("ExampleKey", exampleFile, options);
+
+ rxUploadOperation
+ .observeResult()
+ .subscribe(
+ result -> Log.i("MyAmplifyApp", "Successfully uploaded: " + result.getKey()),
+ error -> Log.e("MyAmplifyApp", "Upload failed", error)
+ );
+}
+ ```
+
+
+
+
## MultiPart upload
Amplify will automatically perform a S3 multipart upload for objects that are larger than 5MB. For more information about S3's multipart upload, see [Uploading and copying objects using multipart upload](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html)
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/app-uninstall/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/app-uninstall/index.mdx
index 237cb7aaa49..e50fedd345f 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/app-uninstall/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/app-uninstall/index.mdx
@@ -23,11 +23,11 @@ export function getStaticProps(context) {
Some Amplify categories such as Analytics and Auth persist data to the local device. This application data is removed when a user uninstalls the application from the device.
-If the [Android Auto Backup for Apps](https://developer.android.com/guide/topics/data/autobackup) service was enabled, this service will attempt to restore application data.
+If the [Android Auto Backup for Apps](https://developer.android.com/guide/topics/data/autobackup) service is enabled, this service will attempt to restore application data.
-Amplify Auth uses [EncryptedSharedPreferences](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences) when persisting auth data. When an application is uninstalled, the [Android Keystore](https://developer.android.com/training/articles/keystore) keys used to create our EncryptedSharedPreferences files are deleted. Upon an application re-install, these restored files are no longer readable due to the key removal from the Android Keystore.
+Amplify Auth uses [EncryptedSharedPreferences](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences) when persisting auth data. When an application is uninstalled, the [Android Keystore](https://developer.android.com/training/articles/keystore) keys used to create our EncryptedSharedPreferences files are deleted. Upon an application reinstall, these restored files are no longer readable due to the key removal from the Android Keystore.
-Due to this limitation with EncryptedSharedPreferences, Auth information can’t be restored on an application re-install. The user will have to re-authenticate.
+Due to this limitation with EncryptedSharedPreferences, Auth information can’t be restored on an application reinstall. The user will have to re-authenticate.
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/auto-track-sessions/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/auto-track-sessions/index.mdx
index 32e745d0a6a..9917daef5e5 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/auto-track-sessions/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/auto-track-sessions/index.mdx
@@ -31,11 +31,11 @@ export function getStaticProps(context) {
-Analytics Auto Tracking helps you to automatically track user behaviors like sessions start/stop, page view change and web events like clicking or mouseover.
+Analytics auto tracking helps you to automatically track user behaviors like sessions' start/stop, page view change and web events like clicking or mouseover.
## Session Tracking
-You can track the session both in a web app or a React Native app by using Analytics. A web session can be defined in different ways. To keep it simple we define a web session as being active when the page is not hidden and inactive when the page is hidden. A session in a React Native app is active when the app is in the foreground and inactive when the app is in the background.
+You can track the session both in a web app or a React Native app by using Analytics. A web session can be defined in different ways. To keep it simple, we define a web session as being active when the page is not hidden and inactive when the page is hidden. A session in a React Native app is active when the app is in the foreground and inactive when the app is in the background.
For example:
@@ -127,7 +127,7 @@ configureAutoTrack({
## Page Event Tracking
-Use this type of tracking to track user interactions with specific elements on a page. Just attach the specified selectors to your DOM element and turn on the auto tracking.
+Use page event tracking to track user interactions with specific elements on a page. Attach the specified selectors to your DOM element and turn on the auto tracking.
This behavior can be enabled by calling `configureAutoTrack`:
```javascript
@@ -197,14 +197,14 @@ configureAutoTrack({
-**Note:** Amplify doesn't capture the location automatically. Instead, you can add the location information in the default config when you [configure Analytics](/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/#set-up-existing-analytics-backend) or while [updating the end point](/[platform]/build-a-backend/add-aws-services/analytics/existing-resources).
+**Note:** Amplify doesn't capture location automatically. Instead, you can add the location information in the default config when you [configure Analytics](/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/#set-up-existing-analytics-backend) or while [updating the end point](/[platform]/build-a-backend/add-aws-services/analytics/existing-resources).
-The Amplify analytics plugin records when an application opens and closes. This session information can be viewed either from the AWS Console for Pinpoint.
+The Amplify analytics plugin records when an application opens and closes. This session information can be viewed either from the AWS Console for Amazon Pinpoint.
-1. On the Pinpoint Console under **Analytics**, choose **Events**.
+1. In the Amazon Pinpoint Console under **Analytics**, choose **Events**.
2. Enable filters, you can select `Session Start` and `Session Stop` events to filter on session events.
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/data-usage-policy/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/data-usage-policy/index.mdx
index a594ad4a6eb..faf6f0b195f 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/data-usage-policy/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/data-usage-policy/index.mdx
@@ -20,7 +20,7 @@ export function getStaticProps(context) {
}
-Apple requires app developers to provide the data usage policy of the app when they submit their app to the App Store. See Apple's [User privacy and data use](https://developer.apple.com/app-store/user-privacy-and-data-use/) for more details. Amplify Library is used to interact with AWS resources under the developer’s ownership and management. The library cannot predict the usage of its APIs and it is up to the developer to provide the privacy manifest that accurately reflects the data collected by the app. Below are the different categories identified by Apple and the corresponding data type used by the Amplify Library.
+Apple requires app developers to provide the data usage policy of the app when they submit their app to the App Store. See Apple's [User privacy and data use](https://developer.apple.com/app-store/user-privacy-and-data-use/) for more details. The Amplify Library is used to interact with AWS resources under the developer’s ownership and management. The library cannot predict the usage of its APIs and it is up to the developer to provide the privacy manifest that accurately reflects the data collected by the app. Below are the different categories identified by Apple and the corresponding data type used by the Amplify Library.
By utilizing the library, Amplify gathers API usage metrics from the AWS services accessed. This process involves adding a user agent to the request made to your AWS service. The user-agent header is included with information about the Amplify Library version, operating system name, and version. AWS collects this data to generate metrics related to our library usage. This information is not linked to the user’s identity and not used for tracking purposes as described in Apple's privacy and data use guidelines.
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/enable-disable/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/enable-disable/index.mdx
index b25dd2612fe..b46b37ee4d6 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/enable-disable/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/enable-disable/index.mdx
@@ -31,7 +31,7 @@ export function getStaticProps(context) {
## Disable Analytics
-Analytics is enabled by default when you configure it in your app. To disable Analytics in your app use the `disable` function:
+Analytics are enabled by default when you configure it in your app. To disable Analytics in your app use the `disable` function:
```javascript
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/existing-resources/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/existing-resources/index.mdx
index 72f2004bb23..50b7a2f5c77 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/existing-resources/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/existing-resources/index.mdx
@@ -33,7 +33,7 @@ export function getStaticProps(context) {
## Set up existing analytics backend
-The manual setup enables you to use your existing Amazon Pinpoint resource in your app.
+This manual setup enables you to use your existing Amazon Pinpoint resource in your app.
```javascript
import { Amplify } from 'aws-amplify';
@@ -67,7 +67,7 @@ Amplify.configure({
## Update your IAM Policy
-Amazon Pinpoint service requires an IAM policy in order to use the `record` and `identifyUser` APIs:
+Amazon Pinpoint requires an AWS Identity and Access Management (IAM) policy in order to use the `record` and `identifyUser` APIs:
```json
{
"Version": "2012-10-17",
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/identify-user/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/identify-user/index.mdx
index 591f9f68745..162370910bf 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/identify-user/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/identify-user/index.mdx
@@ -32,7 +32,7 @@ export function getStaticProps(context) {
This call sends information that you have specified about the user to Amazon Pinpoint. This could be for an unauthenticated or an authenticated user.
-In addition, `customProperties` and `userAttributes` can also be provided when invoking `identifyUser`. The Amazon Pinpoint console makes that data available as part of the criteria for segment creation. Attributes passed in via `customProperties` will appear under **Custom Endpoint Attributes**, while `userAttributes` will appear under **Custom User Attributes**. See the [Pinpoint documentation](https://docs.aws.amazon.com/pinpoint/latest/userguide/segments-building.html#choosecriteria) for more information on segment creation.
+In addition, `customProperties` and `userAttributes` can also be provided when invoking `identifyUser`. The Amazon Pinpoint console makes that data available as part of the criteria for segment creation. Attributes passed in via `customProperties` will appear under **Custom Endpoint Attributes**, while `userAttributes` will appear under **Custom User Attributes**. See the [Amazon Pinpoint documentation](https://docs.aws.amazon.com/pinpoint/latest/userguide/segments-building.html#choosecriteria) for more information on segment creation.
You can get the current user's ID from the Amplify Auth category as shown below. Be sure you have it added and setup per the [Auth category documentation](/[platform]/build-a-backend/auth/set-up-auth/).
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/personalize-recommendations/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/personalize-recommendations/index.mdx
index 55167ee105f..09a25c3cafd 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/personalize-recommendations/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/personalize-recommendations/index.mdx
@@ -37,7 +37,7 @@ For more information, see [Record Events](https://docs.aws.amazon.com/personaliz
### Installation and Configuration
-After creating the Amazon Personalize dataset group, you need to add the `personalize:PutEvents` permission to your Amplify IAM user roles.
+After creating the Amazon Personalize dataset group, you need to add the `personalize:PutEvents` permission to your AWS Identity and Access Management (IAM) user roles.
An example IAM policy:
```json
@@ -76,7 +76,7 @@ Amplify.configure({
### Working with the API
You can use the `Identify` event type to track a user identity. This lets you connect a user to their actions and record traits about them. To identify a user, specify a unique identifier for the userId property.
- Consider the following user interactions when choosing when and how often to call record with the Identify eventType:
+ Consider the following user interactions when choosing when and how often to call record with the Identify eventType:
* After a user registers.
* After a user logs in.
@@ -93,7 +93,7 @@ record({
}
});
```
-You can send events to Amazon personalize by calling the `record` operation. If you already use `Identify` to track end-user data, you can skip the userId, the SDK will fetch the userId based on current browser session.
+You can send events to Amazon Personalize by calling the `record` operation. If you already use `Identify` to track end-user data, you can skip the userId, the SDK will fetch the userId based on current browser session.
For information about the properties field, see [Put Events](https://docs.aws.amazon.com/personalize/latest/dg/API_UBS_PutEvents.html).
```javascript
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/record-events/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/record-events/index.mdx
index 6f8b02af202..d5ad1750839 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/record-events/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/record-events/index.mdx
@@ -32,7 +32,7 @@ export function getStaticProps(context) {
## Record event
-The Amplify analytics plugin also makes it easy to record custom events within the app. The plugin handles retry logic in the event the device loses network connectivity and automatically batches requests to reduce network bandwidth.
+The Amplify Analytics plugin makes it easy to record custom events within an app. The plugin handles retry logic in the event that the device loses network connectivity, and it automatically batches requests to reduce network bandwidth.
@@ -84,7 +84,7 @@ RxAmplify.Analytics.recordEvent(event);
-The AWS Pinpoint event count updates in minutes after recording your event.
+The Amazon Pinpoint event count updates in minutes after recording your event.
However, it can take upwards of 30 minutes for the event to display in the Filter section, and for its custom attributes to appear in Pinpoint.
@@ -92,7 +92,7 @@ However, it can take upwards of 30 minutes for the event to display in the Filte
## Flush events
-Events have default configuration to flush out to the network every 30 seconds. If you would like to change this, update `amplifyconfiguration.json` with the value in milliseconds you would like for `autoFlushEventsInterval`. This configuration will flush events every 10 seconds:
+Events have a default configuration to flush out to the network every 30 seconds. If you would like to change this, update `amplifyconfiguration.json` with the value in milliseconds you would like for `autoFlushEventsInterval`. This configuration will flush events every 10 seconds:
```json
{
@@ -143,11 +143,11 @@ When flushing events, a [Hub event](/[platform]/build-a-backend/utilities/hub/)
## Authentication events
-Indicate how frequently users authenticate with your application.
+Authentication events indicate how frequently users authenticate with your application.
On the **Analytics** page, the **Users** tab displays charts for **Sign-ins, Sign-ups, and Authentication failures**.
-To learn how frequently users authenticate with your app, update your application code so that Pinpoint receives the following standard event types for authentication:
+To learn how frequently users authenticate with your app, update your application code so that Amazon Pinpoint receives the following standard event types for authentication:
- `_userauth.sign_in`
- `_userauth.sign_up`
@@ -193,7 +193,6 @@ You can report authentication events by doing either of the following:
```kotlin
-
/**
* Call this method to log an authentication event to the analytics client.
*/
@@ -309,9 +308,9 @@ Future recordCustomEvent() async {
-The AWS Pinpoint event count updates in minutes after recording your event.
+The Amazon Pinpoint event count updates in minutes after recording your event.
-However, it can take upwards of 30 minutes for the event to display in the Filter section, and for its custom attributes to appear in Pinpoint.
+However, it can take upwards of 30 minutes for the event to display in the Filter section, and for its custom attributes to appear in Amazon Pinpoint.
@@ -408,7 +407,7 @@ Amplify.Analytics.record(event: event)
-The AWS Pinpoint event count updates in minutes after recording your event.
+The Amazon Pinpoint event count updates in minutes after recording your event.
However, it can take upwards of 30 minutes for the event to display in the Filter section, and for its custom attributes to appear in Pinpoint.
@@ -549,7 +548,7 @@ record({
});
```
-Recorded events will be buffered and periodically sent to Pinpoint.
+Recorded events will be buffered and periodically sent to Amazon Pinpoint.
## Record Engagement Metrics
@@ -568,9 +567,9 @@ Metric values must be a `Number` type such as a float or integer.
-The AWS Pinpoint event count updates in minutes after recording your event.
+The Amazon Pinpoint event count updates in minutes after recording your event.
-However, it can take upwards of 30 minutes for the event to display in the Filter section, and for its custom attributes to appear in Pinpoint.
+However, it can take upwards of 30 minutes for the event to display in the Filter section, and for its custom attributes to appear in Amazon Pinpoint.
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/sdk/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/sdk/index.mdx
index abdd4068382..ab0907afaba 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/sdk/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/sdk/index.mdx
@@ -23,11 +23,11 @@ export function getStaticProps(context) {
}
-For advanced use cases where Amplify does not provide the functionality, you can retrieve the escape hatch to access the underlying Amazon Pinpoint client.
+For advanced use cases where Amplify does not provide the functionality, you can retrieve an escape hatch to access the underlying Amazon Pinpoint client.
-**Note:** While the Amplify Library for Swift is production ready, please note that the underlying AWS SDK for Swift is currently in Developer Preview, and is not yet intended for production workloads. [Here is additional reading material](https://github.com/awslabs/aws-sdk-swift/blob/main/Sources/Core/AWSSDKForSwift/Documentation.docc/stability.md) on the stability of the SDK
+**Note:** While the Amplify Library for Swift is production ready, please note that the underlying AWS SDK for Swift is currently in Developer Preview, and is not yet intended for production workloads. [Here is additional reading material](https://github.com/awslabs/aws-sdk-swift/blob/main/Sources/Core/AWSSDKForSwift/Documentation.docc/stability.md) on the stability of the SDK.
@@ -59,7 +59,7 @@ do {
-For advanced use cases where Amplify does not provide the functionality, you can retrieve the escape hatch to access the underlying Amazon Pinpoint client.
+For advanced use cases where Amplify does not provide the functionality, you can retrieve an escape hatch to access the underlying Amazon Pinpoint client.
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx
index c0b888919e5..3fc090a4a21 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/set-up-analytics/index.mdx
@@ -29,7 +29,7 @@ export function getStaticProps(context) {
};
}
-Amplify enables you to collect analytics data for your app. The Analytics category uses [Amazon Cognito Identity pools](https://docs.aws.amazon.com/cognito/latest/developerguide/identity-pools.html) to _identify_ users in your App. Cognito allows you to receive data from authenticated, and unauthenticated users in your App.
+Amplify enables you to collect analytics data for your app. In order to use Analytics, you will enable [Amazon Kinesis](https://aws.amazon.com/kinesis/) or [Amazon Pinpoint](https://aws.amazon.com/pinpoint/) using the AWS Cloud Development Kit (AWS CDK). The Analytics category uses [Amazon Cognito identity pools](https://docs.aws.amazon.com/cognito/latest/developerguide/identity-pools.html) to _identify_ users in your app. Cognito allows you to receive data from authenticated, and unauthenticated users in your app.
## Prerequisites
@@ -75,7 +75,7 @@ For more information on how to use the `visionos-preview` branch, see [Platform
## Set up Analytics backend
-The following is an example utilizing the [AWS Cloud Development Kit (AWS CDK)](https://docs.aws.amazon.com/cdk/latest/guide/home.html) to create the an Analytics resource powered by [Amazon Pinpoint](https://aws.amazon.com/pinpoint/).
+Use the [AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/home.html) to create an analytics resource powered by [Amazon Pinpoint](https://aws.amazon.com/pinpoint/).
```ts title="amplify/backend.ts"
import { auth } from "./auth/resource";
@@ -134,7 +134,7 @@ npm install aws-amplify
-1. To install Amplify Libraries in your application, open your project in Xcode and select **File > Add Packages...**.
+1. To install the Amplify Libraries in your application, open your project in Xcode and select **File > Add Packages...**.
2. Enter the **Amplify Library for Swift** GitHub repo URL (`https://github.com/aws-amplify/amplify-swift`) into the search bar and click **Add Package**.
@@ -512,13 +512,7 @@ Congratulations! Now that you have Analytics' backend provisioned and Analytics
## Known Issues
-When importing alternative service providers listed below, instead of the default Pinpoint provider:
-
-- Kinesis (`aws-amplify/analytics/kinesis`)
-- Kinesis Data Firehose (`aws-amplify/analytics/kinesis-firehose`)
-- Personalize Event (`aws-amplify/analytics/personalize`)
-
-you may encounter the following error when starting the bundler:
+You may encounter the following error when starting the bundler when using Amazon Kinesis (`aws-amplify/analytics/kinesis`), Amazon Kinesis Data Firehose (`aws-amplify/analytics/kinesis-firehose`), Personalize Event (`aws-amplify/analytics/personalize`):
> Error: Unable to resolve module stream from /path/to/node_modules/@aws-sdk/... This is a [known issue](https://github.com/aws/aws-sdk-js-v3/issues/4877). Please follow [the steps](https://github.com/aws/aws-sdk-js-v3/issues/4877#issuecomment-1656007484) outlined in the issue to resolve the error.
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/storing-data/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/storing-data/index.mdx
index e40b77ceee7..ca1a5eb9af1 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/storing-data/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/storing-data/index.mdx
@@ -32,7 +32,7 @@ The Amazon Data Firehose analytics provider allows you to send analytics data to
The following is an example utilizing the [AWS Cloud Development Kit (AWS CDK)](https://docs.aws.amazon.com/cdk/latest/guide/home.html) to create the Analytics resource powered by [Amazon Data Firehose](https://aws.amazon.com/firehose/).
-Let's create a storage bucket to store the data from Amazon Data Firehose stream.
+Let's create a storage bucket to store the data from the Firehose stream.
```ts title="amplify/storage/resource.ts"
import { defineStorage } from "@aws-amplify/backend";
@@ -44,7 +44,7 @@ export const storage = defineStorage({
```
-next, let's create the Amazon Data Firehose resource.
+next, let's create the Firehose resource.
```ts title="amplify/backend.ts"
import { defineBackend } from "@aws-amplify/backend";
@@ -124,7 +124,7 @@ Example IAM policy for Amazon Data Firehose:
}
```
-Configure Kinesis Firehose:
+Configure Firehose:
```javascript
import { Amplify } from 'aws-amplify';
@@ -154,7 +154,7 @@ Amplify.configure({
## Storing data
-You can send a data to a Kinesis Firehose stream with the standard `record` method. Any data is acceptable and `streamName` is required:
+You can send a data to a Firehose stream with the standard `record` method. Any data is acceptable and `streamName` is required:
```javascript
import { record } from 'aws-amplify/analytics/kinesis-firehose';
@@ -182,8 +182,8 @@ flushEvents();
When importing alternative service providers listed below, instead of the default Pinpoint provider:
-- Kinesis (`aws-amplify/analytics/kinesis`)
-- Kinesis Data Firehose (`aws-amplify/analytics/kinesis-firehose`)
+- Amazon Kinesis (`aws-amplify/analytics/kinesis`)
+- Amazon Data Firehose (`aws-amplify/analytics/kinesis-firehose`)
- Personalize Event (`aws-amplify/analytics/personalize`)
you may encounter the following error when starting the bundler:
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/streaming-data/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/streaming-data/index.mdx
index 322ab9bfbfc..b9e9c6f98ac 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/analytics/streaming-data/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/analytics/streaming-data/index.mdx
@@ -26,7 +26,7 @@ export function getStaticProps(context) {
};
}
-The Amazon Kinesis analytics provider allows you to send analytics data to an [Amazon Kinesis](https://aws.amazon.com/kinesis) stream for real-time processing.
+The Amazon Kinesis analytics provider allows you to send analytics data to an [Kinesis](https://aws.amazon.com/kinesis) stream for real-time processing.
## Setup Kinesis stream
@@ -86,7 +86,7 @@ Example IAM policy for Amazon Kinesis:
}
```
-For more information visit [Amazon Kinesis Developer Documentation](https://docs.aws.amazon.com/streams/latest/dev/learning-kinesis-module-one-iam.html).
+For more information visit the [Amazon Kinesis Developer Documentation](https://docs.aws.amazon.com/streams/latest/dev/learning-kinesis-module-one-iam.html).
Configure Kinesis:
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/clear-messages/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/clear-messages/index.mdx
new file mode 100644
index 00000000000..ce807ac87f7
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/clear-messages/index.mdx
@@ -0,0 +1,41 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Clear messages',
+ description: "Learn more about how to clear synced in-app messages from the user's device.",
+ platforms: [
+ 'javascript',
+ 'react-native',
+ 'angular',
+ 'nextjs',
+ 'react',
+ 'vue'
+ ],
+};
+
+export const getStaticPaths = async () => {
+ return getCustomStaticPath(meta.platforms);
+};
+
+export function getStaticProps(context) {
+ return {
+ props: {
+ platform: context.params.platform,
+ meta
+ }
+ };
+}
+
+Once messages have been synced to your user's device, `clearMessages()` can be used to clear the synced messages.
+
+```js
+import { clearMessages } from 'aws-amplify/in-app-messaging';
+
+await clearMessages();
+```
+
+
+
+**Note:** If your app has authentication implemented, we recommend calling `clearMessages()` in between user log-ins to remove messages targeted for specific user segments. This is especially important if you anticipate your application will be used in shared device scenarios.
+
+
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/create-campaign/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/create-campaign/index.mdx
new file mode 100644
index 00000000000..46d946274d1
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/create-campaign/index.mdx
@@ -0,0 +1,91 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Creating an in-app messaging campaign on AWS Console',
+ description: 'Learn how to create a new Pinpoint campaign and configure it to be used with your Amplify project.',
+ platforms: [
+ 'javascript',
+ 'react-native',
+ 'angular',
+ 'nextjs',
+ 'react',
+ 'vue'
+ ],
+};
+
+export const getStaticPaths = async () => {
+ return getCustomStaticPath(meta.platforms);
+};
+
+export function getStaticProps(context) {
+ return {
+ props: {
+ platform: context.params.platform,
+ meta
+ }
+ };
+}
+
+Alternatively, you can use the AWS console to create a campaign that sends messages through any single channel that is supported by Amazon Pinpoint: Mobile Push, In-App, Email, SMS or Custom channels. [Learn how to create a campaign using Amazon Pinpoint](https://docs.aws.amazon.com/pinpoint/latest/userguide/campaigns.html) to continue integrating in-app messages in your app with Amplify.
+
+1. Login to the [AWS Console](https://console.aws.amazon.com/console/home), and Search for **Pinpoint**.
+2. Click on your project from the list of available project. Your project name would be the name you provided when you created the pinpoint project using CDK.
+
+3. Click on **Campaigns** from the left navigation menu, and then click on **Create a campaign**
+
+ 
+
+4. Add a name to your campaign, and keep the following options as follows and then click Next:
+
+ 1. Campaign type: **Standard campaign**
+ 2. Channel: **In-App messaging**
+ 3. set prioritization: **Fairly important**
+
+5. Click on the **Create a segment** radio button, and add a name for your segment, and then click **Next**.
+
+ 1. You can add as many segments as needed to the campaign. For this quickstart, you can use **Include any audiences** under the _Segment group 1_ section.
+ 2. You can add a criteria to your segments to ensure that audiences that satisfy that criteria can receive the in-app message.
+ 3. If you see an error message titled _Segment might include multiple channels_, click **I understand** to proceed.
+
+ 
+
+6. Click on the **Create a new in-app message** radio button.
+7. You have the ability to customize the following attributes of the in-app message:
+ - **Layout**: Which includes all of the different messaging layout options.
+ - **Header**: Title of the in-app message, including the text color/alignment.
+ - **Message**: The body of the Message, including the text color/alignment.
+ - **Background**: Control the background color of the in-app message.
+ - **Image URL**: Add an image to be displayed as part of the in-app message body.
+ - **Primary button**: Allows the addition of a button to add functionality to the in-app message.
+ - **Secondary button**: Allows the addition of an extra button for additional functionality.
+ - **Custom Data**: Allows the in-app message to pass additional data to the frontend app once it is triggered by an event.
+
+
+
+ As React Native does not support SVG rendering out of the box, Amplify cannot render SVG images by default. For SVG image support with In-App Messaging a custom UI implementation is required.
+
+
+
+For this tutorial you can create a simple message as shown below. Customers in your application will see the same message once the event is triggered.
+
+
+
+8. Once you have finished customizing your in-app message, click on **Next**.
+9. Under _Trigger events_, add the name of the analytics trigger that will be sent from your frontend app.
+ - You have the ability to customize the trigger to allow only certain attributes or metrics that are passed with the analytics event to trigger the in-app message. (Optional)
+
+
+
+10. By default, the number of messages shown per session is 1. You can update this threshold during campaign setup.
+
+
+
+11. Review your campaign, and then click on **Launch campaign**.
+
+Your campaign is now setup, and you are ready to start integrating the In-App Messaging functionality into your app.
+
+
+
+**Note:** Campaign start time must be at least 15 minutes in future. In-app messages can only be synced to local device once the campaign becomes active (status should be "In Progress" in the campaigns screen of the Pinpoint console).
+
+
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/display-messages/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/display-messages/index.mdx
new file mode 100644
index 00000000000..e0e50e876e3
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/display-messages/index.mdx
@@ -0,0 +1,61 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Display messages',
+ description: 'Learn how in-app messages are displayed when an In-App Messaging or analytics event is sent and matches the criteria set forth by your active In-App Messaging campaigns.',
+ platforms: [
+ 'javascript',
+ 'react-native',
+ 'angular',
+ 'nextjs',
+ 'react',
+ 'vue'
+ ],
+};
+
+export const getStaticPaths = async () => {
+ return getCustomStaticPath(meta.platforms);
+};
+
+export function getStaticProps(context) {
+ return {
+ props: {
+ platform: context.params.platform,
+ meta
+ }
+ };
+}
+
+In-app messages are displayed when an In-App Messaging or analytics event is sent and matches the criteria defined by your active In-App Messaging campaigns.
+
+## Analytics event
+
+Now that messages have been synced to your users' devices, Amplify In-App Messaging will allow you to start displaying them with Amplify Analytics events with no additional integration steps. Any events you record or are already recording using the Analytics' `record` API are automatically picked up and processed by In-App Messaging. If the event matches the attributes and criteria defined in an in-app message, that message will be displayed.
+
+```js
+import { record } from 'aws-amplify/analytics';
+
+record({
+ name: 'first_event',
+ attributes: { color: 'red' },
+ metrics: { quantity: 10 }
+});
+```
+
+If the event name, attributes, and metrics match those set forth by one of your In-App Messaging campaigns, you should see the in-app message displayed in your app.
+
+## In-App Messaging event
+
+In addition to or instead of Amplify Analytics events, you can also dispatch In-App Messaging events to trigger an in-app message display programmatically.
+
+```js
+import { dispatchEvent } from 'aws-amplify/in-app-messaging';
+
+dispatchEvent({
+ name: 'first_event',
+ attributes: { color: 'red' },
+ metrics: { quantity: 10 }
+});
+```
+
+If the event name, attributes, and metrics match those set forth by one of your In-App Messaging campaigns, you should see the in-app message displayed in your app.
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/identify-user/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/identify-user/index.mdx
new file mode 100644
index 00000000000..b9300288745
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/identify-user/index.mdx
@@ -0,0 +1,85 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Identify a user',
+ description: 'Learn how to segment and target your In-App Messaging campaigns to specific user subsets.',
+ platforms: [
+ 'javascript',
+ 'react-native',
+ 'angular',
+ 'nextjs',
+ 'react',
+ 'vue'
+ ],
+};
+
+export const getStaticPaths = async () => {
+ return getCustomStaticPath(meta.platforms);
+};
+
+export function getStaticProps(context) {
+ return {
+ props: {
+ platform: context.params.platform,
+ meta
+ }
+ };
+}
+
+To fully harness the potential of In-App Messaging, you must segment and target your In-App Messaging campaigns to specific user subsets. By identifying users with additional information, including their device demographics, location and any attributes of your choosing, you will be able to display intelligent, targeted in-app messages to the right users.
+
+```js
+import { identifyUser } from 'aws-amplify/in-app-messaging';
+
+await identifyUser({
+ userId: '', // E.g. user-id
+ userProfile: {
+ email: '', // E.g. example@service.com
+ name: '', // E.g. name-of-the-user
+ plan: '' // E.g. plan-they-subscribe-to
+ customProperties: {
+ // E.g. hobbies: ['cooking', 'knitting'],
+ },
+ demographic: {
+ appVersion: '',
+ locale: '', // E.g. en_US
+ make: '', // E.g. Apple
+ model: '', // E.g. iPhone
+ modelVersion: '', // E.g. 13
+ platform: '', // E.g. iOS
+ platformVersion: '', // E.g. 15
+ timezone: '' // E.g. Americas/Los_Angeles
+ },
+ location: {
+ city: '', // E.g. Seattle
+ country: '', // E.g. US,
+ postalCode: '', // E.g. 98121
+ region: '', // E.g. WA
+ latitude: 0.0,
+ longitude: 0.0
+ },
+ metrics: {
+ // E.g. logins: 157
+ },
+ },
+});
+```
+
+## Identify a user with Amazon Pinpoint
+
+When using `identifyUser` with Amazon Pinpoint, in addition to the other user info properties you can configure the `address`, `optOut` and `userAttributes` properties under `options`.
+
+```js
+import { identifyUser } from 'aws-amplify/in-app-messaging';
+
+await identifyUser({
+ userId: '', // E.g. user-id
+ options: {
+ address: '' // E.g. A device token or email address
+ optOut: '' // Either ALL or NONE
+ userAttributes: {
+ // E.g. interests: ['soccer', 'shoes'],
+ }
+ },
+});
+```
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/index.mdx
index bffc5849979..ef635b20787 100644
--- a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/index.mdx
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/index.mdx
@@ -1,17 +1,17 @@
+import { getChildPageNodes } from '@/utils/getChildPageNodes';
import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
export const meta = {
title: 'In-App Messaging',
description: 'Learn how to set up In-App Messaging resource powered by Pinpoint',
+ route: "/[platform]/build-a-backend/add-aws-services/in-app-messaging",
platforms: [
- 'android',
'angular',
'flutter',
'javascript',
'nextjs',
'react',
'react-native',
- 'swift',
'vue'
]
};
@@ -21,133 +21,13 @@ export const getStaticPaths = async () => {
};
export function getStaticProps(context) {
+ const childPageNodes = getChildPageNodes(meta.route);
return {
props: {
- meta
+ meta,
+ childPageNodes
}
};
}
-
-
-**Under active development:** The `addOutput` method for Amplify Gen 2 is under active development. The experience may change between versions of `@aws-amplify/backend`. Try it out and provide feedback at https://github.com/aws-amplify/amplify-backend/issues/new/choose
-
-
-
-Amplify allows interacting with In-App Messaging APIs, which enables you to send messages to your app users. In-App Messaging is a powerful tool to engage with your users and provide them with relevant information. The following is an example utilizing the [AWS Cloud Development Kit (AWS CDK)](https://docs.aws.amazon.com/cdk/latest/guide/home.html) to create the In-App Messaging resource powered by [Amazon Pinpoint](https://aws.amazon.com/pinpoint/).
-
-```ts title="amplify/backend.ts"
-import {
- CfnApp,
- CfnInAppTemplate,
- CfnCampaign,
- CfnSegment,
-} from "aws-cdk-lib/aws-pinpoint";
-import { Policy, PolicyStatement } from "aws-cdk-lib/aws-iam";
-import { Stack } from "aws-cdk-lib";
-
-const backend = defineBackend({
- auth,
- data,
- // additional resources
-});
-
-const inAppMessagingStack = backend.createStack("inAppMessaging-stack");
-
-// create a Pinpoint app
-const pinpoint = new CfnApp(inAppMessagingStack, "Pinpoint", {
- name: "myPinpointApp",
-});
-
-// create a segment
-const mySegment = new CfnSegment(inAppMessagingStack, "Segment", {
- applicationId: pinpoint.ref,
- name: "mySegment",
-});
-
-// create a campaign with event and in-app message template
-new CfnCampaign(inAppMessagingStack, "MyCampaign", {
- applicationId: pinpoint.ref,
- name: "MyCampaign",
- segmentId: mySegment.attrSegmentId,
- schedule: {
- // ensure the start and end time are in the future
- startTime: "2024-02-23T14:39:34Z",
- endTime: "2024-02-29T14:32:40Z",
- frequency: "IN_APP_EVENT",
- eventFilter: {
- dimensions: {
- eventType: {
- dimensionType: "INCLUSIVE",
- values: ["PURCHASE"],
- },
- },
- filterType: "ENDPOINT",
- },
- },
-
- messageConfiguration: {
- inAppMessage: {
- layout: "TOP_BANNER",
- content: [
- {
- // define the content of the in-app message
- bodyConfig: {
- alignment: "CENTER",
- body: "This is an example in-app message.",
- textColor: "#FFFFFF",
- },
- backgroundColor: "#000000",
- headerConfig: {
- alignment: "CENTER",
- header: "Welcome!",
- textColor: "#FFFFFF",
- },
- // optionally, define buttons, images, etc.
- },
- ],
- },
- },
-});
-
-//create an IAM policy to allow interacting with Pinpoint in-app messaging
-const pinpointPolicy = new Policy(inAppMessagingStack, "PinpointPolicy", {
- policyName: "PinpointPolicy",
- statements: [
- new PolicyStatement({
- actions: ["mobiletargeting:GetInAppMessages"],
- resources: [pinpoint.attrArn + "/*"],
- }),
- ],
-});
-
-// apply the policy to the authenticated and unauthenticated roles
-backend.auth.resources.authenticatedUserIamRole.attachInlinePolicy(pinpointPolicy);
-backend.auth.resources.unauthenticatedUserIamRole.attachInlinePolicy(pinpointPolicy);
-
-// patch the custom Pinpoint resource to the expected output configuration
-backend.addOutput({
- Notifications: {
- InAppMessaging: {
- AWSPinpoint: {
- appId: pinpoint.ref,
- region: Stack.of(pinpoint).region,
- },
- },
- },
-});
-```
-
-
-### Initialize In-App Messaging
-
-To initialize In-App Messaging you need to configure Amplify with `Amplify.configure()`
-
-
-### Working with In-App Messaging
-
-Refer to the [Amplify In-App Messaging documentation](/gen1/[platform]/build-a-backend/more-features/in-app-messaging/) to learn how to send in-app messages to your app users.
-
-### References
-
-[Amazon Pinpoint Construct Library](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_pinpoint-readme.html)
+
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/integrate-application/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/integrate-application/index.mdx
new file mode 100644
index 00000000000..6dfb17e2998
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/integrate-application/index.mdx
@@ -0,0 +1,228 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Integrate your application',
+ description: 'Learn how to integrate your application with In-app Messaging.',
+ platforms: [
+ 'javascript',
+ 'react-native',
+ 'angular',
+ 'nextjs',
+ 'react',
+ 'vue'
+ ],
+};
+
+export const getStaticPaths = async () => {
+ return getCustomStaticPath(meta.platforms);
+};
+
+export function getStaticProps(context) {
+ return {
+ props: {
+ platform: context.params.platform,
+ meta
+ }
+ };
+}
+
+
+### Install the Amplify React Native Package and other dependencies
+Installing the `@aws-amplify/react-native` will bring in the necessary polyfills.
+
+
+
+`@aws-amplify/react-native` requires a minimum iOS deployment target of `13.0` if you are using `react-native` version less than or equal to `0.72`. Open the _Podfile_ located in the _ios_ directory and update the `target` value:
+
+```diff showLineNumbers={false}
+- platform :ios, min_ios_version_supported
++ platform :ios, 13.0
+```
+
+
+
+```bash showLineNumbers={false}
+npm install @aws-amplify/react-native @react-native-community/netinfo @react-native-async-storage/async-storage
+```
+
+### Install Amplify UI for React Native and its dependencies
+
+Although Amplify In-App Messaging can be used as a standalone JavaScript library, this guide will show you how to use it together with Amplify UI which currently supports integration with React and React Native to get started quickly.
+
+
+
+Learn more about Amplify In-App Messaging UI and how to fully unlock its capabilities here: [Amplify UI for In-App Messaging](https://ui.docs.amplify.aws/react-native/connected-components/in-app-messaging)
+
+
+
+```bash showLineNumbers={false}
+npm install @aws-amplify/ui-react-native react-native-safe-area-context
+```
+
+
+
+{/* TODO What should be done with this page for non-react frameworks */}
+
+### Install Amplify UI for React
+
+Although Amplify In-App Messaging can be used as a standalone JavaScript library, this guide will show you how to use it together with Amplify UI which currently supports integration with React and React Native to get started quickly.
+
+
+
+Learn more about Amplify In-App Messaging UI and how to fully unlock its capabilities here: [Amplify UI for In-App Messaging](https://ui.docs.amplify.aws/react/connected-components/in-app-messaging)
+
+
+
+```bash showLineNumbers={false}
+npm install @aws-amplify/ui-react @aws-amplify/ui-react-notifications
+```
+
+
+### Integrate Amplify UI
+
+Amplify UI provides a Higher-Order Component for ease of integrating the In-App Messaging UI with your application. Simply wrap your application root component in, for example, `App.js`.
+
+
+```js
+import { withInAppMessaging } from '@aws-amplify/ui-react-native';
+
+const App = () => (
+ {/* Your application code */}
+);
+
+export default withInAppMessaging(App);
+```
+
+
+
+{/* TODO in-app validate the library here. What should this be for things other than React */}
+
+```js
+import { withInAppMessaging } from '@aws-amplify/ui-react-notifications';
+
+import '@aws-amplify/ui-react/styles.css';
+
+const App = () => (
+ {/* Your application code */}
+);
+
+export default withInAppMessaging(App);
+```
+
+
+Below is an example of what your entry file should look like:
+
+```jsx
+import React, { useEffect } from 'react';
+import { Button, View } from 'react-native';
+import {
+ initializeInAppMessaging,
+ syncMessages,
+ dispatchEvent
+} from 'aws-amplify/in-app-messaging';
+import { withInAppMessaging } from '@aws-amplify/ui-react-native';
+import { record } from 'aws-amplify/analytics';
+import amplifyconfig from '../amplifyconfiguration.json';
+
+Amplify.configure(amplifyconfig);
+initializeInAppMessaging();
+
+// To display your in-app message, make sure this event name matches one you created
+// in an In-App Messaging campaign!
+const myFirstEvent = { name: 'my_first_event' };
+
+const App = () => {
+ useEffect(() => {
+ // Messages from your campaigns need to be synced from the backend before they
+ // can be displayed. You can trigger this anywhere in your app. Here you are
+ // syncing just once when this component (your app) renders for the first time.
+ syncMessages();
+ }, []);
+
+ return (
+
+ {/* This button has an example of an analytics event triggering the in-app message. */}
+
+ );
+};
+
+export default withInAppMessaging(App);
+```
+
+
+
+
+{/* TODO in-app validate the library here. What should this be for things other than React */}
+
+```jsx
+import React, { useEffect } from 'react';
+import {
+ initializeInAppMessaging,
+ syncMessages,
+ dispatchEvent
+} from 'aws-amplify/in-app-messaging';
+import { Button, View } from '@aws-amplify/ui-react';
+import { withInAppMessaging } from '@aws-amplify/ui-react-notifications';
+import { record } from 'aws-amplify/analytics';
+import '@aws-amplify/ui-react/styles.css';
+import amplifyconfig from '../amplifyconfiguration.json';
+
+Amplify.configure(amplifyconfig);
+initializeInAppMessaging();
+
+// To display your in-app message, make sure this event name matches one you created
+// in an In-App Messaging campaign!
+const myFirstEvent = { name: 'my_first_event' };
+
+const App = () => {
+ useEffect(() => {
+ // Messages from your campaigns need to be synced from the backend before they
+ // can be displayed. You can trigger this anywhere in your app. Here you are
+ // syncing just once when this component (your app) renders for the first time.
+ syncMessages();
+ }, []);
+
+ return (
+
+ {/* This button has an example of an analytics event triggering the in-app message. */}
+ {
+ record(myFirstEvent);
+ }}
+ >
+ Record Analytics Event
+
+
+ {/* This button has an example of an In-app Messaging event triggering the in-app message.*/}
+ {
+ dispatchEvent(myFirstEvent);
+ }}
+ >
+ Send In-App Messaging Event
+
+
+ );
+};
+
+export default withInAppMessaging(App);
+```
+
+
+{/* TODO What would happen for frameworks other than React? Would they NOT see this popup? what should we do for them? */}
+
+You can now build and run your app in your terminal. If you click on one of the buttons shown in the above example, the in-app message you defined in the Pinpoint console should be displayed in your app.
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/resolve-conflicts/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/resolve-conflicts/index.mdx
new file mode 100644
index 00000000000..32edd541286
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/resolve-conflicts/index.mdx
@@ -0,0 +1,50 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Resolve conflicts',
+ description: 'Learn how to resolve conflicts when an event is sent and meets the criteria set forth by multiple in-app messages.',
+ platforms: [
+ 'javascript',
+ 'react-native',
+ 'angular',
+ 'nextjs',
+ 'react',
+ 'vue'
+ ],
+};
+
+export const getStaticPaths = async () => {
+ return getCustomStaticPath(meta.platforms);
+};
+
+export function getStaticProps(context) {
+ return {
+ props: {
+ platform: context.params.platform,
+ meta
+ }
+ };
+}
+
+In the rare case where an event is sent and meets the criteria set forth by multiple in-app messages, the library needs to decide which message to return. If such a conflict should arise, In-App Messaging will choose a message by:
+
+1. Sorting the messages in order of campaign expiration
+2. Returning the top message sorted (the closest message to expiry)
+
+However, this may not be how you wish to resolve such conflicts so you may want to set your own conflict handler.
+
+```js
+import { setConflictHandler } from 'aws-amplify/in-app-messaging';
+
+/**
+ * Regardless of your conflict resolution strategy the handler must always accept
+ * an array of in-app messages and return a single in-app message.
+ */
+const myConflictHandler = (messages) => {
+ // Return a random message
+ const randomIndex = Math.floor(Math.random() * messages.length);
+ return messages[randomIndex];
+};
+
+setConflictHandler(myConflictHandler);
+```
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/respond-interaction-events/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/respond-interaction-events/index.mdx
new file mode 100644
index 00000000000..e7d81ed620c
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/respond-interaction-events/index.mdx
@@ -0,0 +1,114 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Respond to interaction events',
+ description: 'Learn how to respond with additional behavior to your users interacting with in-app messages by adding interaction event listeners.',
+ platforms: [
+ 'javascript',
+ 'react-native',
+ 'angular',
+ 'nextjs',
+ 'react',
+ 'vue'
+ ],
+};
+
+export const getStaticPaths = async () => {
+ return getCustomStaticPath(meta.platforms);
+};
+
+export function getStaticProps(context) {
+ return {
+ props: {
+ platform: context.params.platform,
+ meta
+ }
+ };
+}
+
+Your code can respond with additional behavior to your users interacting with in-app messages by adding interaction event listeners.
+
+## Message received
+
+Add `onMessageReceived` listeners to respond to an in-app message being received from the library as the result of an event matching the criteria of a synced in-app message. This is required if you are implementing a custom UI so that your UI can respond to event-triggered campaign messages but you may also find it helpful to listen for these messages for any other reason your application requires.
+
+```js
+import { onMessageReceived } from 'aws-amplify/in-app-messaging';
+
+const myMessageReceivedHandler = (message) => {
+ // Do something with the received message
+};
+
+const listener = onMessageReceived(myMessageReceivedHandler);
+
+listener.remove(); // Remember to remove the listener when it is no longer needed
+```
+
+## Message displayed
+
+Add `onMessageDisplayed` listeners to respond to an in-app message being displayed to your user.
+
+```js
+import { onMessageDisplayed } from 'aws-amplify/in-app-messaging';
+
+const myMessageDisplayedHandler = (message) => {
+ // Do something with the displayed message
+};
+
+const listener = onMessageDisplayed(myMessageDisplayedHandler);
+
+listener.remove(); // Remember to remove the listener when it is no longer needed
+```
+
+## Message dismissed
+
+Add `onMessageDismissed` listeners to respond to an in-app message being dismissed by your user.
+
+```js
+import { onMessageDismissed } from 'aws-amplify/in-app-messaging';
+
+const myMessageDismissedHandler = (message) => {
+ // Do something with the dismissed message
+};
+
+const listener = onMessageDismissed(myMessageDismissedHandler);
+
+listener.remove(); // Remember to remove the listener when it is no longer needed
+```
+
+## Message action taken
+
+Add `onMessageActionTaken` listeners to respond to an action being taken on an in-app message. Typically, this means that the user has tapped or clicked a button on an in-app message.
+
+```js
+import { onMessageActionTaken } from 'aws-amplify/in-app-messaging';
+
+const myMessageActionTakenHandler = (message) => {
+ // Do something with the message action was taken against
+};
+
+const listener = onMessageActionTaken(myMessageActionTakenHandler);
+
+listener.remove(); // Remember to remove the listener when it is no longer needed
+```
+
+## Notifying listeners
+
+If you are using the Amplify In-App Messaging UI, interaction events notifications are already wired up for you. However, if you are implementing your own UI, it is highly recommended to notify listeners of interaction events through your UI code so that the library can take further actions prescribed by the installed provider (for example, automatically recording corresponding Analytics events).
+
+```ts
+import { notifyMessageInteraction } from 'aws-amplify/in-app-messaging';
+
+const message = {
+ // In-app message that you want to record an interaction on
+}
+
+/**
+ * Interaction events that can be notified correspond to their respective listeners:
+ * 'messageReceived'
+ * 'messageDisplayed'
+ * 'messageDismissed'
+ * 'messageActionTaken'
+ */
+notifyMessageInteraction({ message, type: 'messageDisplayed' });
+```
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/set-up-in-app-messaging/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/set-up-in-app-messaging/index.mdx
new file mode 100644
index 00000000000..e80f15fb897
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/set-up-in-app-messaging/index.mdx
@@ -0,0 +1,190 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Set up in-app messaging',
+ description: 'Learn how to get started with in-app messaging.',
+ platforms: [
+ 'javascript',
+ 'react-native',
+ 'angular',
+ 'nextjs',
+ 'react',
+ 'vue'
+ ],
+};
+
+export const getStaticPaths = async () => {
+ return getCustomStaticPath(meta.platforms);
+};
+
+export function getStaticProps(context) {
+ return {
+ props: {
+ platform: context.params.platform,
+ meta
+ }
+ };
+}
+
+Amplify allows interacting with In-App Messaging APIs, which enables you to send messages to your app users. In-App Messaging is a powerful tool to engage with your users and provide them with relevant information.
+A campaign is a messaging initiative that engages a specific audience segment. A campaign sends tailored messages according to a schedule that you define. You can use the [AWS Cloud Development Kit (AWS CDK)](https://docs.aws.amazon.com/cdk/latest/guide/home.html) to create a campaign that sends messages through any single channel that is supported by Amazon Pinpoint: Mobile Push, In-App, Email, SMS or Custom channels.
+
+The following is an example utilizing the AWS CDK to create the In-App Messaging resource powered by [Amazon Pinpoint](https://aws.amazon.com/pinpoint/). But do note there are no official hand-written (L2) constructs for this service yet.
+
+
+
+**Note:** Campaign start time must be at least 15 minutes in future. In-app messages can only be synced to local device once the campaign becomes active (Status should be "In Progress" in the campaigns screen of the Pinpoint console).
+
+
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from "@aws-amplify/backend";
+import { auth } from "./auth/resource";
+import { data } from "./data/resource";
+import {
+ CfnApp,
+ CfnCampaign,
+ CfnSegment,
+} from "aws-cdk-lib/aws-pinpoint";
+import { Policy, PolicyStatement } from "aws-cdk-lib/aws-iam";
+import { Stack } from "aws-cdk-lib/core";
+
+
+const backend = defineBackend({
+ auth,
+ data,
+ // additional resources
+});
+
+const inAppMessagingStack = backend.createStack("inAppMessaging-stack");
+
+// create a Pinpoint app
+const pinpoint = new CfnApp(inAppMessagingStack, "Pinpoint", {
+ name: "myPinpointApp",
+});
+
+// create a segment
+const mySegment = new CfnSegment(inAppMessagingStack, "Segment", {
+ applicationId: pinpoint.ref,
+ name: "mySegment",
+});
+
+// create a campaign with event and in-app message template
+new CfnCampaign(inAppMessagingStack, "Campaign", {
+ applicationId: pinpoint.ref,
+ name: "MyCampaign",
+ segmentId: mySegment.attrSegmentId,
+ schedule: {
+ // ensure the start and end time are in the future
+ startTime: "2024-02-23T14:39:34Z",
+ endTime: "2024-02-29T14:32:40Z",
+ frequency: "IN_APP_EVENT",
+ eventFilter: {
+ dimensions: {
+ eventType: {
+ dimensionType: "INCLUSIVE",
+ values: ["my_first_event"],
+ },
+ },
+ filterType: "ENDPOINT",
+ },
+ },
+
+ messageConfiguration: {
+ inAppMessage: {
+ layout: "TOP_BANNER",
+ content: [
+ {
+ // define the content of the in-app message
+ bodyConfig: {
+ alignment: "CENTER",
+ body: "This is an example in-app message.",
+ textColor: "#FFFFFF",
+ },
+ backgroundColor: "#000000",
+ headerConfig: {
+ alignment: "CENTER",
+ header: "Welcome!",
+ textColor: "#FFFFFF",
+ },
+ // optionally, define buttons, images, etc.
+ },
+ ],
+ },
+ },
+});
+
+//create an IAM policy to allow interacting with Pinpoint in-app messaging
+const pinpointPolicy = new Policy(inAppMessagingStack, "PinpointPolicy", {
+ policyName: "PinpointPolicy",
+ statements: [
+ new PolicyStatement({
+ actions: [
+ "mobiletargeting:GetInAppMessages",
+ "mobiletargeting:UpdateEndpoint",
+ "mobiletargeting:PutEvents",
+ ],
+ resources: [pinpoint.attrArn + "/*", pinpoint.attrArn],
+ }),
+ ],
+});
+
+// apply the policy to the authenticated and unauthenticated roles
+backend.auth.resources.authenticatedUserIamRole.attachInlinePolicy(pinpointPolicy);
+backend.auth.resources.unauthenticatedUserIamRole.attachInlinePolicy(pinpointPolicy);
+
+// patch the custom Pinpoint resource to the expected output configuration
+backend.addOutput({
+ notifications: {
+ amazon_pinpoint_app_id: pinpoint.ref,
+ aws_region: Stack.of(pinpoint).region,
+ channels: ["IN_APP_MESSAGING"],
+ },
+});
+```
+
+## Install Amplify Libraries
+
+First, install the `aws-amplify` library:
+
+```sh showLineNumbers={false}
+npm install aws-amplify
+```
+
+### Initialize In-App Messaging
+
+To finish setting up your application with Amplify, you need to configure it using the `configure` API. Next, to interact with In-App Messaging APIs, you need to first initialize In-App Messaging by calling the `initializeInAppMessaging` API directly imported from the `in-app-messaging` sub-path. This is required to be called as early as possible in the app lifecycle.
+
+
+```js
+import { Amplify } from 'aws-amplify';
+import { initializeInAppMessaging } from 'aws-amplify/in-app-messaging';
+import amplifyconfig from '../amplifyconfiguration.json';
+
+Amplify.configure(amplifyconfig);
+initializeInAppMessaging();
+```
+
+
+
+```js
+import { Amplify } from 'aws-amplify';
+import { initializeInAppMessaging } from 'aws-amplify/in-app-messaging';
+import amplifyconfig from '@/amplifyconfiguration.json';
+
+Amplify.configure(amplifyconfig);
+initializeInAppMessaging();
+```
+
+
+
+
+Make sure you call `Amplify.configure` as early as possible in your application’s life-cycle. A missing configuration or `NoCredentials` error is thrown if `Amplify.configure` has not been called before other Amplify JavaScript APIs.
+
+
+
+{/* [Todo] add link to the troubleshooting doc when its moved over https://docs.amplify.aws/react/build-a-backend/troubleshooting/library-not-configured/ */}
+
+### References
+
+[Amazon Pinpoint Construct Library](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_pinpoint-readme.html)
diff --git a/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/sync-messages/index.mdx b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/sync-messages/index.mdx
new file mode 100644
index 00000000000..b37611432d6
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/add-aws-services/in-app-messaging/sync-messages/index.mdx
@@ -0,0 +1,41 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Sync messages',
+ description: "Learn how to sync in-app messages to your user's local device. Synced messages will be displayed when a matching event is triggered.",
+ platforms: [
+ 'javascript',
+ 'react-native',
+ 'angular',
+ 'nextjs',
+ 'react',
+ 'vue'
+ ],
+};
+
+export const getStaticPaths = async () => {
+ return getCustomStaticPath(meta.platforms);
+};
+
+export function getStaticProps(context) {
+ return {
+ props: {
+ platform: context.params.platform,
+ meta
+ }
+ };
+}
+
+To trigger messages, you must sync them from your In-App Messaging campaigns to your users' devices. These messages are then triggered with an analytics or In-App Messaging event. You can control when and how often this sync is performed.
+
+```js
+import { syncMessages } from 'aws-amplify/in-app-messaging';
+
+await syncMessages();
+```
+
+
+
+**Note:** Syncing messages will always overwrite existing messages currently on the user's device so they are always up to date when the sync is performed.
+
+
diff --git a/src/pages/[platform]/build-a-backend/data/connect-to-API/index.mdx b/src/pages/[platform]/build-a-backend/data/connect-to-API/index.mdx
index 7ae2ee7465b..ec1f18ad6e8 100644
--- a/src/pages/[platform]/build-a-backend/data/connect-to-API/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/connect-to-API/index.mdx
@@ -111,7 +111,7 @@ const client = generateClient({
```
-
+
```ts
import { generateClient } from 'aws-amplify/data';
@@ -179,7 +179,7 @@ const { data: todos, errors } = await client.models.Todo.list({
```
-
+
```ts
const { data: todos, errors } = await client.models.Todo.list({
diff --git a/src/pages/[platform]/build-a-backend/data/custom-business-logic/index.mdx b/src/pages/[platform]/build-a-backend/data/custom-business-logic/index.mdx
index 7e33ff51bc3..f719db5ca8d 100644
--- a/src/pages/[platform]/build-a-backend/data/custom-business-logic/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/custom-business-logic/index.mdx
@@ -224,7 +224,7 @@ export type Schema = ClientSchema;
export const data = defineData({
schema,
authorizationModes: {
- defaultAuthorizationMode: 'apiKey',
+ defaultAuthorizationMode: 'userPool',
apiKeyAuthorizationMode: {
expiresInDays: 30
}
diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/configure-custom-identity-and-group-claim/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/configure-custom-identity-and-group-claim/index.mdx
index ebc73ec5f8f..b7c5a16a72b 100644
--- a/src/pages/[platform]/build-a-backend/data/customize-authz/configure-custom-identity-and-group-claim/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/customize-authz/configure-custom-identity-and-group-claim/index.mdx
@@ -32,7 +32,7 @@ Amplify Data supports using custom identity and group claims if you do not wish
To use custom claims specify `identityClaim` or `groupClaim` as appropriate. In the example below, the `identityClaim` is specified and the record owner will check against this `user_id` claim. Similarly, if the `user_groups` claim contains a "Moderator" string then access will be granted.
-```ts
+```ts title="amplify/data/resource.ts"
import { a, defineData, type ClientSchema } from '@aws-amplify/backend';
const schema = a.schema({
@@ -54,3 +54,24 @@ export type Schema = ClientSchema;
export const data = defineData({ schema });
```
+
+In your application, you can perform CRUD operations against the model using `client.models.` with the `userPool` auth mode.
+
+```ts
+import { generateClient } from 'aws-amplify/data';
+import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
+
+const client = generateClient();
+
+const { errors, data: newTodo } = await client.models.Todo.create(
+ {
+ postname: 'My New Post'
+ content: 'My post content',
+ },
+ // highlight-start
+ {
+ authMode: 'userPool',
+ }
+ // highlight-end
+);
+```
diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/custom-data-access-patterns/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/custom-data-access-patterns/index.mdx
index 384ec24a6b8..2722fbc0846 100644
--- a/src/pages/[platform]/build-a-backend/data/customize-authz/custom-data-access-patterns/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/customize-authz/custom-data-access-patterns/index.mdx
@@ -30,7 +30,7 @@ export function getStaticProps(context) {
You can define your own custom authorization rule with a Lambda function.
-```ts
+```ts title="amplify/data/resource.ts"
import {
type ClientSchema,
a,
@@ -68,6 +68,26 @@ export const data = defineData({
});
```
+In your application, you can perform CRUD operations against the model using `client.models.` with the `lambda` auth mode.
+
+```ts
+import { generateClient } from 'aws-amplify/data';
+import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
+
+const client = generateClient();
+
+const { errors, data: newTodo } = await client.models.Todo.create(
+ {
+ content: 'My new todo',
+ },
+ // highlight-start
+ {
+ authMode: 'lambda',
+ }
+ // highlight-end
+);
+```
+
The Lambda function of choice will receive an authorization token from the client and execute the desired authorization logic. The AppSync GraphQL API will receive a payload from Lambda after invocation to allow or deny the API call accordingly.
To configure a Lambda function as the authorization mode, create a new file `amplify/data/custom-authorizer.ts`. You can use this Lambda function code template as a starting point for your authorization handler code:
diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx
index 7166c4474be..aace23f453f 100644
--- a/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/customize-authz/index.mdx
@@ -57,9 +57,9 @@ Use the guide below to select the correct authorization strategy for your use ca
| **Recommended use case** | **Strategy** | **Provider** |
|---|---|---|
| [Public data access where users or devices are anonymous. Anyone with the AppSync API key is granted access.](/[platform]/build-a-backend/data/customize-authz/public-data-access) | `public` | `apiKey` |
-| [Recommended for production environment's public data access. Public data access where unauthenticated users or devices are granted permissions using AWS IAM controls.](/[platform]/build-a-backend/data/customize-authz/public-data-access/#add-public-authorization-rule-using-iam-authentication) | `public` | `iam` |
+| [Recommended for production environment's public data access. Public data access where unauthenticated users or devices are granted permissions using Amazon Cognito identity pool's role for unauthenticated identities.]( /[platform]/build-a-backend/data/customize-authz/public-data-access/#add-public-authorization-rule-using-iam-authentication) | `public` | `identityPool` |
| [Per user data access. Access is restricted to the "owner" of a record. Leverages `amplify/auth/resource.ts` Cognito user pool by default.](/[platform]/build-a-backend/data/customize-authz/per-user-per-owner-data-access) | `owner` | `userPools` / `oidc` |
-| [Any signed-in data access. Unlike owner-based access, **any** signed-in user has access.](/[platform]/build-a-backend/data/customize-authz/signed-in-user-data-access) | `private` | `userPools` / `oidc` / `iam` |
+| [Any signed-in data access. Unlike owner-based access, **any** signed-in user has access.](/[platform]/build-a-backend/data/customize-authz/signed-in-user-data-access) | `private` | `userPools` / `oidc` / `identityPool` |
| [Per user group data access. A specific or dynamically configured group of users has access.](/[platform]/build-a-backend/data/customize-authz/user-group-based-data-access) | `group` | `userPools` / `oidc` |
| [Define your own custom authorization rule within a serverless function.](/[platform]/build-a-backend/data/customize-authz/custom-data-access-patterns) | `custom` | `function` |
@@ -71,8 +71,6 @@ Amplify will always use the most specific authorization rule that is available.
If there are multiple authorization rules present, they will be logically OR'ed. Review [Configure multiple authorization rules](#configure-multiple-authorization-rules) to learn more.
-Finally, there are special "Admin IAM Roles" that allow you to overrule any authorization logic applied on the API and determine the API access completely via its IAM policy.
-
### Global authorization rule (only for getting started)
To help you get started, you can define an authorization rule on the data schema that will be applied to all data models that **do not** have a model-level authorization rule. Instead of having a global authorization rule for all production environments, we recommend creating specific authorization rules for each model or field.
@@ -149,7 +147,7 @@ const schema = a.schema({
### Configure multiple authorization rules
When combining multiple authorization rules, they are "logically OR"-ed. In the following example:
-- Any user (signed in or not, verified by IAM) is allowed to read all posts
+- Any user (using Amazon Cognito identity pool's unauthenticated roles) is allowed to read all posts
- Owners are allowed to create, read, update, and delete their own posts
```ts
@@ -158,7 +156,7 @@ const schema = a.schema({
title: a.string(),
content: a.string()
}).authorization([
- a.allow.public("iam").to(["read"]),
+ a.allow.public("identityPool").to(["read"]),
a.allow.owner()
])
})
@@ -179,7 +177,7 @@ const { data: newPostResult , errors } = await client.models.Post.create({
authMode: 'userPool',
});
-// Listing posts is available to all users (verified by IAM)
+// Listing posts is available to unauthenticated users (verified by Amazon Cognito identity pool's unauthenticated role)
const { data: listPostsResult , errors } = await client.models.Post.list({
query: queries.listPosts,
authMode: 'iam',
diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/multi-user-data-access/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/multi-user-data-access/index.mdx
index 0a690bdac89..67ec3d8e3b6 100644
--- a/src/pages/[platform]/build-a-backend/data/customize-authz/multi-user-data-access/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/customize-authz/multi-user-data-access/index.mdx
@@ -35,7 +35,7 @@ The `multipleOwners` rule grants a set of users access to a record by automatica
If you want to grant a set of users access to a record, you use the `multipleOwners` rule. This automatically creates a `owner: a.string().array()` field to store the allowed owners.
-```ts
+```ts title="amplify/data/resource.ts"
const schema = a.schema({
Todo: a
.model({
@@ -45,6 +45,41 @@ const schema = a.schema({
});
```
+In your application, you can perform CRUD operations against the model using `client.models.` with the `userPool` auth mode.
+
+```ts
+import { generateClient } from 'aws-amplify/data';
+import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
+
+const client = generateClient();
+
+// Create a record with current user as first owner
+const { errors, data: newTodo } = await client.models.Todo.create(
+ {
+ content: 'My new todo',
+ },
+ // highlight-start
+ {
+ authMode: 'userPool',
+ }
+ // highlight-end
+);
+```
+```ts
+// Add another user as an owner
+await client.models.Todo.update(
+ {
+ id: newTodo.id,
+ owner: [...(newTodo.owner as string[]), otherUserId],
+ },
+ // highlight-start
+ {
+ authMode: "userPool"
+ }
+ // highlight-end
+);
+```
+
## Override to a list of owners
You can override the `inField` to a list of owners. Use this if you want a dynamic set of users to have access to a record. In the example below, the `authors` list is populated with the creator of the record upon record creation. The creator can then update the `authors` field with additional users. Any user listed in the `authors` field can access the record.
diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/per-user-per-owner-data-access/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/per-user-per-owner-data-access/index.mdx
index 9f78802097d..3942e0c53f5 100644
--- a/src/pages/[platform]/build-a-backend/data/customize-authz/per-user-per-owner-data-access/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/customize-authz/per-user-per-owner-data-access/index.mdx
@@ -35,7 +35,8 @@ The `owner` authorization strategy restricts operations on a record to only the
You can use the `owner` authorization strategy to restrict a record's access to a specific user. When `owner` authorization is configured, only the record's `owner` is allowed the specified operations.
-```ts
+
+```ts title="amplify/data/resource.ts"
// The "owner" of a Todo is allowed to create, read, update, and delete their own todos
const schema = a.schema({
Todo: a
@@ -46,7 +47,7 @@ const schema = a.schema({
});
```
-```ts
+```ts title="amplify/data/resource.ts"
// The "owner" of a Todo record is only allowed to create, read, and update it.
// The "owner" of a Todo record is denied to delete it.
const schema = a.schema({
@@ -58,6 +59,26 @@ const schema = a.schema({
});
```
+In your application, you can perform CRUD operations against the model using `client.models.` with the `userPool` auth mode.
+
+```ts
+import { generateClient } from 'aws-amplify/data';
+import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
+
+const client = generateClient();
+
+const { errors, data: newTodo } = await client.models.Todo.create(
+ {
+ content: 'My new todo',
+ },
+ // highlight-start
+ {
+ authMode: 'userPool',
+ }
+ // highlight-end
+);
+```
+
Behind the scenes, Amplify will automatically add a `owner: a.string()` field to each record which contains the record owner's identity information upon record creation.
By default, the Cognito user pool's user information is populated into the `owner` field. The value saved includes `sub` and `username` in the format `::`. The API will authorize against the full value of `::` or `sub` / `username` separately and return `username`. You can alternatively configure [OpenID Connect as an authorization provider](/[platform]/build-a-backend/data/customize-authz/using-oidc-authorization-provider).
diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/public-data-access/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/public-data-access/index.mdx
index 6ad0a363634..7f95293923f 100644
--- a/src/pages/[platform]/build-a-backend/data/customize-authz/public-data-access/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/customize-authz/public-data-access/index.mdx
@@ -34,7 +34,7 @@ The public authorization strategy grants everyone access to the API, which is pr
To grant everyone access, use the `.public()` authorization strategy. Behind the scenes, the API will be protected with an API key.
-```ts
+```ts title="amplify/data/resource.ts"
const schema = a.schema({
Todo: a
.model({
@@ -44,16 +44,81 @@ const schema = a.schema({
});
```
-## Add public authorization rule using IAM authentication
-
-You can also override the authorization provider. In the example below, `iam` is specified as the provider which allows you to use an "Unauthenticated Role" from the Cognito identity pool for public access instead of an API key. Your Auth resources defined in `amplify/auth/resource.ts` generates scoped down IAM policies for the "Unauthenticated role" in the Cognito identity pool automatically.
+In your application, you can perform CRUD operations against the model using `client.models.` by specifying the `apiKey` auth mode.
```ts
+import { generateClient } from 'aws-amplify/data';
+import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
+
+const client = generateClient();
+
+const { errors, data: newTodo } = await client.models.Todo.create(
+ {
+ content: 'My new todo',
+ },
+ // highlight-start
+ {
+ authMode: 'apiKey',
+ }
+ // highlight-end
+);
+```
+
+## Add public authorization rule using Amazon Cognito identity pool's unauthenticated role
+
+You can also override the authorization provider. In the example below, `identityPool` is specified as the provider which allows you to use an "Unauthenticated Role" from the Cognito identity pool for public access instead of an API key. Your Auth resources defined in `amplify/auth/resource.ts` generates scoped down IAM policies for the "Unauthenticated role" in the Cognito identity pool automatically.
+
+```ts title="amplify/data/resource.ts"
const schema = a.schema({
Todo: a
.model({
content: a.string(),
})
- .authorization([a.allow.public('iam')]),
+ .authorization([a.allow.public('identityPool')]),
});
```
+
+In your application, you can perform CRUD operations against the model using `client.models.` with the `iam` auth mode.
+
+
+If you're not using the auto-generated **amplifyconfiguration.json** file, then you must set the Amplify Library resource configuration's `allowGuestAccess` flag to `true`. This lets the Amplify Library use the unauthenticated role from your Cognito identity pool when your user isn't logged in.
+
+
+```ts title="src/App.tsx"
+import { Amplify } from "aws-amplify";
+import config from "../amplifyconfiguration.json";
+
+Amplify.configure(
+ {
+ ...config,
+ Auth: {
+ Cognito: {
+ identityPoolId: config.aws_cognito_identity_pool_id,
+ userPoolClientId: config.aws_user_pools_web_client_id,
+ userPoolId: config.aws_user_pools_id,
+ allowGuestAccess: true,
+ },
+ },
+ }
+);
+```
+
+
+
+```ts title="src/App.tsx"
+import { generateClient } from 'aws-amplify/data';
+import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
+
+const client = generateClient();
+
+const { errors, data: newTodo } = await client.models.Todo.create(
+ {
+ content: 'My new todo',
+ },
+ // highlight-start
+ {
+ authMode: 'iam',
+ }
+ // highlight-end
+);
+```
diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/signed-in-user-data-access/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/signed-in-user-data-access/index.mdx
index 40f49e862f2..ef01b0f9a79 100644
--- a/src/pages/[platform]/build-a-backend/data/customize-authz/signed-in-user-data-access/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/customize-authz/signed-in-user-data-access/index.mdx
@@ -40,7 +40,7 @@ You can use the `private` authorization strategy to restrict a record's access t
In the example below, anyone with a valid JWT token from the Cognito user pool is allowed access to all Todos.
-```ts
+```ts title="amplify/data/resource.ts"
const schema = a.schema({
Todo: a
.model({
@@ -50,18 +50,63 @@ const schema = a.schema({
});
```
-## Override the authentication provider
-
-You can also override the authorization provider. In the example below, `iam` is specified as the provider which allows you to use an "Unauthenticated Role" from the Cognito identity pool for public access instead of an API key. Your Auth resources defined in `amplify/auth/resource.ts` generates scoped down IAM policies for the "Unauthenticated role" in the Cognito identity pool automatically.
+In your application, you can perform CRUD operations against the model using `client.models.` with the `userPool` auth mode.
```ts
+import { generateClient } from 'aws-amplify/data';
+import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
+
+const client = generateClient();
+
+const { errors, data: newTodo } = await client.models.Todo.create(
+ {
+ content: 'My new todo',
+ },
+ // highlight-start
+ {
+ authMode: 'userPool',
+ }
+ // highlight-end
+);
+```
+
+## Use identity pool for signed-in user authentication
+
+You can also override the authorization provider. In the example below, `identityPool` is specified as the provider which allows you to use an "Unauthenticated Role" from the Cognito identity pool for public access instead of an API key. Your Auth resources defined in `amplify/auth/resource.ts` generates scoped down IAM policies for the "Unauthenticated role" in the Cognito identity pool automatically.
+
+
+```ts title="amplify/data/resource.ts"
const schema = a.schema({
Todo: a
.model({
content: a.string(),
})
- .authorization([a.allow.private('iam')]),
+ .authorization([a.allow.private('identityPool')]),
});
```
+In your application, you can perform CRUD operations against the model using `client.models.` with the `iam` auth mode.
+
+
+ The user must be logged in for the Amplify Library to use the authenticated role from your Cognito identity pool.
+
+
+```ts
+import { generateClient } from 'aws-amplify/data';
+import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
+
+const client = generateClient();
+
+const { errors, data: newTodo } = await client.models.Todo.create(
+ {
+ content: 'My new todo',
+ },
+ // highlight-start
+ {
+ authMode: 'iam',
+ }
+ // highlight-end
+);
+```
+
In addition, you can also use OpenID Connect with `private` authorization. See [OpenID Connect as an authorization provider](/[platform]/build-a-backend/data/customize-authz/using-oidc-authorization-provider/).
diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/user-group-based-data-access/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/user-group-based-data-access/index.mdx
index c19019e0366..9241f16729b 100644
--- a/src/pages/[platform]/build-a-backend/data/customize-authz/user-group-based-data-access/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/customize-authz/user-group-based-data-access/index.mdx
@@ -34,7 +34,7 @@ You can use the `group` authorization strategy to restrict access based on user
When you want to restrict access to a specific set of user groups, provide the group names in the `groups` parameter. In the example below, only users that are part of the "Admin" user group are granted access to the Salary model.
-```ts
+```ts title="amplify/data/resource.ts"
// allow one specific group
const schema = a.schema({
Salary: a
@@ -46,6 +46,28 @@ const schema = a.schema({
});
```
+In your application, you can perform CRUD operations against the model using `client.models.` with the `userPool` auth mode.
+
+```ts
+import { generateClient } from 'aws-amplify/data';
+import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
+
+const client = generateClient();
+
+// As a signed-in user that belongs to the 'Admin' User Pool Group
+const { errors, data: newSalary } = await client.models.Salary.create(
+ {
+ wage: 50.25,
+ currency: 'USD'
+ },
+ // highlight-start
+ {
+ authMode: 'userPool',
+ }
+ // highlight-end
+);
+```
+
This can then be updated to allow access to multiple defined groups; in this example below we added access for "Leadership".
```ts
diff --git a/src/pages/[platform]/build-a-backend/data/customize-authz/using-oidc-authorization-provider/index.mdx b/src/pages/[platform]/build-a-backend/data/customize-authz/using-oidc-authorization-provider/index.mdx
index afe24ca38ca..4f32e5e2ef6 100644
--- a/src/pages/[platform]/build-a-backend/data/customize-authz/using-oidc-authorization-provider/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/customize-authz/using-oidc-authorization-provider/index.mdx
@@ -66,3 +66,18 @@ export const data = defineData({
},
});
```
+
+In your application, you can perform CRUD operations against the model using `client.models.` by specifying the `oidc` auth mode.
+
+```ts
+import { generateClient } from 'aws-amplify/data';
+import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
+
+const client = generateClient();
+
+const { errors, data: todos } = await client.models.Todo.list({
+ // highlight-start
+ authMode: "oidc",
+ // highlight-end
+});
+```
diff --git a/src/pages/[platform]/build-a-backend/data/data-modeling/secondary-index/index.mdx b/src/pages/[platform]/build-a-backend/data/data-modeling/secondary-index/index.mdx
index e32e4194071..86001fa817a 100644
--- a/src/pages/[platform]/build-a-backend/data/data-modeling/secondary-index/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/data-modeling/secondary-index/index.mdx
@@ -31,44 +31,41 @@ export function getStaticProps(context) {
You can optimize your list queries based on "secondary indexes". For example, if you have a **Customer** model, you can query based on the customer's **id** identifier field by default but you can add a secondary index based on the **accountRepresentativeId** to get list customers for a given account representative.
-A secondary index consists of a "hash key" and, optionally, a "sort key". Use the "hash key" to perform strict equality and the "sort key" for greater than (gt), greater than or equal to (ge), less than (lt), less than or equal to (le), equals (eq), begins with, and between operations.
+A secondary index consists of a "hash key" and, optionally, a "sort key". Use the "hash key" to perform strict equality and the "sort key" for greater than (gt), greater than or equal to (ge), less than (lt), less than or equal to (le), equals (eq), begins with, and between operations.
-```ts
+```ts title="amplify/data/resource.ts"
export const schema = a.schema({
- Customer: a.model({
- name: a.string(),
- phoneNumber: a.phone(),
- accountRepresentativeId: a.id().required()
- // highlight-start
- }).secondaryIndexes(index => [
- a.index('accountRepresentativeId')
- ])
- // highlight-end
- .authorization([a.allow.public()]),
+ Customer: a
+ .model({
+ name: a.string(),
+ phoneNumber: a.phone(),
+ accountRepresentativeId: a.id().required(),
+ })
+ // highlight-next-line
+ .secondaryIndexes((index) => [index("accountRepresentativeId")])
+ .authorization([a.allow.public()]),
});
```
The example client query below allows you to query for "Customer" records based on their `accountRepresentativeId`:
-```ts
+```ts title="src/App.tsx"
import { type Schema } from '../amplify/data/resource';
import { generateClient } from 'aws-amplify/data';
const client = generateClient();
-const {
- data,
- errors
+const { data, errors } =
// highlight-start
-} = await client.models.Customer.listByAccountRepresentativeId({
- accountRepresentativeId: "YOUR_REP_ID"
-});
- // highlight-end
+ await client.models.Customer.listByAccountRepresentativeId({
+ accountRepresentativeId: "YOUR_REP_ID",
+ });
+// highlight-end
```
-Amplify uses Amazon DynamoDB tables as the default data source for `a.model()`. For key-value databases, it is critical to model your access patterns with "secondary indexes". Use the `.index()` modifier to configure a secondary index.
+Amplify uses Amazon DynamoDB tables as the default data source for `a.model()`. For key-value databases, it is critical to model your access patterns with "secondary indexes". Use the `.index()` modifier to configure a secondary index.
**Amazon DynamoDB** is a key-value and document database that delivers single-digit millisecond performance at any scale but making it work for your access patterns requires a bit of forethought. DynamoDB query operations may use at most two attributes to efficiently query data. The first query argument passed to a query (the hash key) must use strict equality and the second attribute (the sort key) may use gt, ge, lt, le, eq, beginsWith, and between. DynamoDB can effectively implement a wide variety of access patterns that are powerful enough for the majority of applications.
@@ -76,35 +73,39 @@ Amplify uses Amazon DynamoDB tables as the default data source for `a.model()`.
## Add sort keys to secondary indexes
-You can define "sort keys" to add a set of flexible filters to your query, such as "greater than" (gt), "greater than or equal to" (ge), "less than" (lt), "less than or equal to" (le), "equals" (eq), "begins with" (beginsWith), and "between" operations.
+You can define "sort keys" to add a set of flexible filters to your query, such as "greater than" (gt), "greater than or equal to" (ge), "less than" (lt), "less than or equal to" (le), "equals" (eq), "begins with" (beginsWith), and "between" operations.
```ts title="amplify/data/resource.ts"
-const schema = a.schema({
- Customer: a.model({
- name: a.string(),
- phoneNumber: a.phone().required(),
- accountRepresentativeId: a.id().required(),
- }).secondaryIndexes(index => [
- a.index('accountRepresentativeId')
- // highlight-next-line
- .sortKeys(["name"]),
- ])
-}).authorization([a.allow.owner()]);
+export const schema = a.schema({
+ Customer: a
+ .model({
+ name: a.string(),
+ phoneNumber: a.phone(),
+ accountRepresentativeId: a.id().required(),
+ })
+ .secondaryIndexes((index) => [
+ index("accountRepresentativeId")
+ // highlight-next-line
+ .sortKeys(["name"]),
+ ])
+ .authorization([a.allow.owner()]),
+});
```
On the client side, you should find a new `listBy...` query that's named after hash key and sort keys. For example, in this case: `listByAccountRepresentativeIdAndName`. You can supply the filter as part of this new list query:
-```ts
+```ts title="src/App.tsx"
const {
data,
errors
- // highlight-next-line
-} = await client.models.Customer.listByAccountRepresentativeIdAndName({
- accountRepresentativeId: 'YOUR_REP_ID',
- name: {
- beginsWith: 'Rene',
- },
-});
+} =
+// highlight-next-line
+ await client.models.Customer.listByAccountRepresentativeIdAndName({
+ accountRepresentativeId: 'YOUR_REP_ID',
+ name: {
+ beginsWith: 'Rene',
+ },
+ });
```
## Customize the query field for secondary indexes
@@ -113,21 +114,24 @@ You can also customize the auto-generated query name under `client.models. [
- a.index('accountRepresentativeId')
- // highlight-next-line
- .queryField("listByRep"),
- ]),
-}).authorization([a.allow.owner()]);
+ Customer: a
+ .model({
+ name: a.string(),
+ phoneNumber: a.phone(),
+ accountRepresentativeId: a.id().required(),
+ })
+ .secondaryIndexes((index) => [
+ index("accountRepresentativeId")
+ // highlight-next-line
+ .queryField("listByRep"),
+ ])
+ .authorization([a.allow.owner()]),
+});
```
In your client app code, you'll see query updated under the Data client:
-```ts
+```ts title="src/App.tsx"
const {
data,
errors
@@ -141,16 +145,19 @@ const {
To customize the underlying DynamoDB's index name, you can optionally provide the `name()` modifier.
-```ts
+```ts title="amplify/data/resource.ts"
const schema = a.schema({
- Customer: a.model({
- name: a.string(),
- phoneNumber: a.phone(),
- accountRepresentativeId: a.id().required(),
- }).secondaryIndexes(index => [
- a.index('accountRepresentativeId')
- // highlight-next-line
- .name("MyCustomIndexName"),
- ])
-}).authorization([a.allow.owner()]);
+ Customer: a
+ .model({
+ name: a.string(),
+ phoneNumber: a.phone(),
+ accountRepresentativeId: a.id().required(),
+ })
+ .secondaryIndexes((index) => [
+ index("accountRepresentativeId")
+ // highlight-next-line
+ .name("MyCustomIndexName"),
+ ])
+ .authorization([a.allow.owner()]),
+});
```
diff --git a/src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx b/src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx
index 4712ae5db24..f6b32a04fd6 100644
--- a/src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx
+++ b/src/pages/[platform]/build-a-backend/data/set-up-data/index.mdx
@@ -45,13 +45,10 @@ With Amplify Data, you can build a secure, real-time API backed by a database in
If you've run `npm create amplify@beta` already, you should see an `amplify/data/resource.ts` file, which is the central location to configure your data backend. The most important element is the `schema` object, which defines your backend data models (`a.model()`) and custom queries (`a.query()`), mutations (`a.mutation()`), and subscriptions (`a.subscription()`).
```ts title="amplify/data/resource.ts"
-// amplify/data/resource.ts
-
import { a, defineData, type ClientSchema } from '@aws-amplify/backend';
const schema = a.schema({
- Todo: a
- .model({
+ Todo: a.model({
content: a.string(),
isDone: a.boolean()
})
@@ -81,10 +78,30 @@ The `a.allow.public()` rule designates that anyone authenticated using an API ke
To deploy these resources to your cloud sandbox, run the following CLI command in your terminal:
+
+
```bash
npx amplify sandbox
```
+
+
+
+
+```bash
+npx amplify sandbox --config-format json-mobile --config-out-dir
+```
+
+
+
+
+
+```bash
+npx amplify sandbox --config-format json-mobile --config-out-dir
+```
+
+
+
## Connect your application code to the data backend
Once the cloud sandbox is up and running, it will also create an `amplifyconfiguration.json` file, which includes the relevant connection information to your data backend, like your API endpoint URL and API key.
@@ -95,24 +112,170 @@ To connect your frontend code to your backend, you need to:
2. generate a new API client from the Amplify library
3. make an API request with end-to-end type-safety
-In your app's entry point, typically **main.tsx** for React apps created using Vite, make the following edits:
+First, install the Amplify client library to your project:
+
+
-```tsx
-// main.tsx
+```bash
+npm install aws-amplify
+```
+
+In your app's entry point, typically **main.tsx** for React apps created using Vite, make the following edits:
+```tsx title="src/main.tsx"
import { Amplify } from 'aws-amplify';
import config from '../amplifyconfiguration.json';
Amplify.configure(config);
```
+
+
+
+
+Under Gradle Scripts, open build.gradle (Module :app), add the following lines:
+
+```groovy title="build.gradle.kts"
+dependencies {
+ // Amplify API dependencies
+ // highlight-start
+ implementation("com.amplifyframework:aws-api:2.14.11")
+ implementation("com.amplifyframework:core:2.14.11")
+ // highlight-end
+ // ... other dependencies
+}
+```
+
+Click **Sync Now** in the notification bar above the file editor to sync these dependencies.
+
+Next, configure the Amplify client library with the generated `amplifyconfiguration.json` file to make it aware of the backend API endpoint. *Note: verify that the **amplifyconfiguration.json** file is present in your **res/raw/** folder.
+
+Create a new `MyAmplifyApp` class that inherits from `Application` with the following code:
+
+```kt
+package com.example.myapplication
+
+import android.app.Application
+import android.util.Log
+import com.amplifyframework.AmplifyException
+import com.amplifyframework.api.aws.AWSApiPlugin
+import com.amplifyframework.core.Amplify
+
+class MyAmplifyApp : Application() {
+ override fun onCreate() {
+ super.onCreate()
+
+ try {
+ // Adds the API plugin that is used to issue queries and mutations
+ // to your backend.
+ Amplify.addPlugin(AWSApiPlugin())
+ // Configures the client library to be aware of your backend API
+ // endpoint and authorization modes.
+ Amplify.configure(applicationContext)
+
+ Log.i("Tutorial", "Initialized Amplify")
+ } catch (error: AmplifyException) {
+ Log.e("Tutorial", "Could not initialize Amplify", error)
+ }
+ }
+}
+```
+
+This overrides the `onCreate()` to initialize Amplify when your application is launched.
+
+Next, configure your application to use your new custom Application class. Open **manifests** > **AndroidManifest.xml**, and add an `android:name` attribute with the value of your new class name:
+
+```xml
+
+
+
+
+
+
+```
+
+Build and run the application. In Logcat, you'll see a log line indicating success:
+
+``` title="Logcat" showLineNumbers={false}
+com.example.MyAmplifyApp I/MyAmplifyApp: Initialized Amplify
+```
+
+Finally, let's generate the GraphQL client code for your Android application. Amplify Data uses GraphQL under the hood to make query, mutation, and subscription requests. The generated GraphQL client code helps you to author fully-typed API requests without needing to hand-author GraphQL requests and manually map them to Kotlin or Java code.
+
+```bash
+npx amplify generate graphql-client-code --format modelgen --model-target java --out
+```
+
+
+
+
+
+Drag and drop the **amplifyconfiguration.json** file from the Finder into Xcode.
+
+Next, add Amplify Library for Swift through the Swift Package Manager. In Xcode, select **File** > **Add Packages...**.
+
+Then, enter the Amplify Library for Swift GitHub repo URL (https://github.com/aws-amplify/amplify-swift) into the search bar and hit **Enter**.
+
+Once the result is loaded, choose Up to **Next Major Version** as the **Dependency Rule**, then click **Add Package**.
+
+Choose which of the libraries you want added to your project. For this tutorial, select **AWSAPIPlugin** and **Amplify**, then click **Add Package**.
+
+Now let's add the necessary plugins into the Swift application by customizing the `init()` function of your app:
+
+```swift title="MyAmplifyApp"
+import SwiftUI
+// highlight-start
+import Amplify
+import AWSAPIPlugin
+// highlight-end
+
+@main
+struct MyAmplifyApp: App {
+
+ // highlight-start
+ init() {
+ let awsApiPlugin = AWSAPIPlugin(modelRegistration: AmplifyModels())
+ do {
+ try Amplify.add(plugin: awsApiPlugin)
+ try Amplify.configure()
+ print("Initialized Amplify");
+ } catch {
+ // simplified error handling for the tutorial
+ print("Could not initialize Amplify: \(error)")
+ }
+ }
+ // highlight-end
+
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ }
+ }
+}
+```
+
+Finally, let's generate the GraphQL client code for your Swift application. Amplify Data uses GraphQL under the hood to make query, mutation, and subscription requests. The generated GraphQL client code helps you to author fully-typed API requests without needing to hand-author GraphQL requests and manually map them to Swift code.
+
+```bash
+npx amplify generate graphql-client-code --format modelgen --model-target swift --out /AmplifyModels
+```
+
+Drag and drop the **AmplifyModels** folder into your Xcode project to add the generated files.
+
+
+
## Write data to your backend
-Let's first add a button to create a new todo item. To make a "create Todo" API request, generate the data client using `generateClient()` in your frontend code, and then call `.create()` operation for the Todo model. The Data client is a fully typed client that gives you in-IDE code completion. To enable this in-IDE code completion capability, pass in the `Schema` type to the `generateClient` function.
+
-```tsx title="TodoList.tsx"
-// TodoList.tsx
+Let's first add a button to create a new todo item. To make a "create Todo" API request, generate the data client using `generateClient()` in your frontend code, and then call `.create()` operation for the Todo model. The Data client is a fully typed client that gives you in-IDE code completion. To enable this in-IDE code completion capability, pass in the `Schema` type to the `generateClient` function.
+```tsx title="src/TodoList.tsx"
import type { Schema } from '../amplify/data/resource'
import { generateClient } from 'aws-amplify/data'
@@ -140,13 +303,120 @@ Try playing around with the code completion of `.update(...)` and `.delete(...)`
+
+
+
+In your MainActivity, add a button to create a new todo.
+
+```kt title="MainActivity.kt"
+// imports
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContent {
+ MyApplicationTheme {
+ // A surface container using the 'background' color from the theme
+ Surface(
+ modifier = Modifier.fillMaxSize(),
+ color = MaterialTheme.colorScheme.background
+ ) {
+ // highlight-start
+ Column {
+ Button(onClick = {
+ val todo = Todo.builder()
+ .content("My first todo")
+ .isDone(false)
+ .build()
+
+ Amplify.API.mutate(ModelMutation.create(todo),
+ { Log.i("MyAmplifyApp", "Added Todo with id: ${it.data.id}")},
+ { Log.e("MyAmplifyApp", "Create failed", it)},
+ )
+ }) {
+ Text(text = "Create Todo")
+ }
+ }
+ // highlight-end
+ }
+ }
+ }
+ }
+}
+```
+
+Build and run your app. Then, click on "Create Todo" on the app. Your Logcat should show you that a todo was successfully added:
+
+``` title="Logcat" showLineNumbers={false}
+com.example.MyAmplifyApp I/MyAmplifyApp: Added Todo with id: SOME_TODO_ID
+```
+
+
+
+
+
+Go to your **ContentView.swift** and add a button to create a new todo:
+
+```swift title="ContentView.swift"
+import SwiftUI
+// highlight-next-line
+import Amplify
+
+struct ContentView: View {
+
+ var body: some View {
+ // highlight-start
+ VStack {
+ Button(action: {
+ addNewTodo()
+ }) {
+ HStack {
+ Text("Add a New Todo")
+ Image(systemName: "plus")
+ }
+ }
+ .accessibilityLabel("New Todo")
+ }
+ // highlight-end
+ }
+
+ // highlight-start
+ private func addNewTodo() {
+ Task {
+ do {
+ let item = Todo(content: "Build iOS Application", isDone: false)
+ let result = try await Amplify.API.mutate(request: .create(item))
+ switch result {
+ case .success(let todo):
+ print("Successfully created todo: \(todo)")
+ case .failure(let error):
+ print("Got failed result with \(error.errorDescription)")
+ }
+ } catch {
+ print("Could not save item: \(error)")
+ }
+ }
+ }
+ // highlight-end
+}
+```
+
+Now if you run the application, and click on the "Create Todo" button, you should see a log indicating a todo was created:
+
+``` showLineNumbers={false}
+Successfully created todo: Todo(id: XYZ ...)
+```
+
+
+
## Read data from your backend
Next, list all your todos and then refetch the todos after a todo has been added:
-```tsx title="TodoList.tsx"
-// TodoList.tsx
+
+
+```tsx title="src/TodoList.tsx"
import { useState, useEffect } from "react";
import type { Schema } from "../amplify/data/resource";
import { generateClient } from "aws-amplify/data";
@@ -187,13 +457,106 @@ export default function TodoList() {
}
```
+
+
+
+Start by creating a new `TodoList` @Composable that fetches the data on the initial display of the TodoList:
+
+```kt title="MainActivity.kt"
+@Composable
+fun TodoList() {
+ var todoList by remember { mutableStateOf(emptyList()) }
+
+ LaunchedEffect(Unit) {
+ // API request to list all Todos
+ Amplify.API.query(ModelQuery.list(Todo::class.java),
+ {
+ todoList = it.data.items.toList()
+ },
+ { Log.e("MyAmplifyApp", "Failed to query.", it)})
+ }
+
+ LazyColumn {
+ items(todoList) { todo ->
+ Row {
+ // Render your activity item here
+ Checkbox(checked = todo.isDone, onCheckedChange = null)
+ Text(text = todo.content)
+ }
+ }
+ }
+}
+```
+
+If you build and rerun the application, you should see the todo that was created in the previous build. But notice how when you click on the "create Todo" button, it doesn't add any new todos to the list below until the next time your app relaunches. To solve this, let's add real-time updates to the todo list.
+
+
+
+
+Start by adding a new state that stores the todos. Then add a `fetchTodos()` function and display the todos in the view:
+
+```swift title="ContentView.swift"
+import SwiftUI
+import Amplify
+
+struct ContentView: View {
+ // highlight-next-line
+ @State private var todos: [Todo] = []
+
+ var body: some View {
+ VStack {
+ // highlight-start
+ List(todos, id: \.id) { todo in
+ Text(todo.content ?? "")
+ }
+ // highlight-end
+ Button(action: {
+ addNewTodo()
+ }) {
+ HStack {
+ Text("Add a New Todo")
+ Image(systemName: "plus")
+ }
+ }
+ .accessibilityLabel("New Todo")
+ }
+ // highlight-start
+ .task {
+ await fetchTodos()
+ }
+ // highlight-end
+ }
+
+ // highlight-start
+ private func fetchTodos() async {
+ do {
+ let request = GraphQLRequest.list(Todo.self)
+ let result = try await Amplify.API.query(request: request)
+ switch result {
+ case .success(let todos):
+ self.todos = todos.elements
+ print("Successfully retrieved list of todos: \(todos)")
+ case .failure(let error):
+ print("Got failed result with \(error.localizedDescription)")
+ }
+ } catch {
+ print("Failed to query list of todos: \(error)")
+ }
+ }
+ // highlight-end
+}
+
+```
+
+
+
## Subscribe to real-time updates
-You can also use `observeQuery` to subscribe to a live feed of your backend data. Let's refactor the code to use a real-time observeQuery instead.
+
-```tsx title="App.tsx"
-// App.tsx
+You can also use `observeQuery` to subscribe to a live feed of your backend data. Let's refactor the code to use a real-time observeQuery instead.
+```tsx title="src/App.tsx"
import type { Schema } from "../amplify/data/resource";
import { useState, useEffect } from "react";
import { generateClient } from "aws-amplify/data";
@@ -243,6 +606,138 @@ You can also use `.onCreate`, `.onUpdate`, or `.onDelete` to subscribe to specif
+
+
+
+To add real-time updates, you can use the subscription feature of Amplify Data. It allows to subscribe to `onCreate`, `onUpdate`, and `onDelete` events of the application. In our example, let's append the list every time a new todo is added.
+
+```kt title="MainActivity.kt"
+@Composable
+fun TodoList() {
+ var todoList by remember { mutableStateOf(emptyList()) }
+
+ LaunchedEffect(Unit) {
+ Amplify.API.query(ModelQuery.list(Todo::class.java),
+ {
+ todoList = it.data.items.toList()
+ },
+ { Log.e("MyAmplifyApp", "Failed to query.", it)})
+ // highlight-start
+ Amplify.API.subscribe(ModelSubscription.onCreate(Todo::class.java),
+ { Log.i("ApiQuickStart", "Subscription established") },
+ { Log.i("ApiQuickStart", "Todo create subscription received: ${it.data}")
+ todoList = todoList + it.data
+ },
+ { Log.e("ApiQuickStart", "Subscription failed", it) },
+ { Log.i("ApiQuickStart", "Subscription completed") }
+
+ )
+ // highlight-end
+ }
+
+ LazyColumn {
+ items(todoList) { todo ->
+ Row {
+ // Render your activity item here
+ Checkbox(checked = todo.isDone, onCheckedChange = null)
+ Text(text = todo.content)
+ }
+ }
+ }
+}
+```
+
+
+
+
+
+To add real-time updates, you can use the subscription feature of Amplify Data. It allows to subscribe to `onCreate`, `onUpdate`, and `onDelete` events of the application. In our example, let's append the list every time a new todo is added.
+
+First, add a private variable to store the subscription. Then, on `init()` establish the subscription and on disappear, cancel the subscription.
+
+```swift title="ContentView.swift"
+import SwiftUI
+import Amplify
+
+struct ContentView: View {
+ @State private var todos: [Todo] = []
+ // highlight-next-line
+ private var subscription: AmplifyAsyncThrowingSequence>
+
+ var body: some View {
+ VStack {
+ // ...
+ }
+ // highlight-start
+ .onDisappear {
+ self.subscription.cancel()
+ }
+ // highlight-end
+ .task {
+ // ...
+ }
+ }
+
+ // highlight-start
+ init() {
+ self.subscription = Amplify.API.subscribe(request: .subscription(of: Todo.self, type: .onCreate))
+ }
+ // highlight-end
+
+ // ... fetchTodos() and addNewTodo()
+}
+```
+
+Next, add a handler as new todo creation events are received:
+
+```swift title="ContentView.swift"
+// .. imports
+
+struct ContentView: View {
+ // ... state & subscription vars
+
+ var body: some View {
+ VStack {
+ // ...
+ }
+ .task {
+ await fetchTodos()
+ // highlight-start
+ do {
+ for try await subscriptionEvent in subscription {
+ handleSubscriptionEvent(subscriptionEvent)
+ }
+ } catch {
+ print("Subscription has terminated with \(error)")
+ }
+ // highlight-end
+ }
+ }
+
+ // highlight-start
+ private func handleSubscriptionEvent(_ subscriptionEvent: GraphQLSubscriptionEvent) {
+ switch subscriptionEvent {
+ case .connection(let subscriptionConnectionState):
+ print("Subscription connect state is \(subscriptionConnectionState)")
+ case .data(let result):
+ switch result {
+ case .success(let createdTodo):
+ print("Successfully got todo from subscription: \(createdTodo)")
+ todos.append(createdTodo)
+ case .failure(let error):
+ print("Got failed result with \(error.errorDescription)")
+ }
+ }
+ }
+ // highlight-end
+ // ... init(), fetchTodos(), and addNewTodo()
+}
+```
+
+Now if you rerun your app, a new todo should be appended to the list every time you create a new todo.
+
+
+
## Conclusion
Success! You've learned how to create your first real-time API and database with Amplify Data.
diff --git a/src/pages/[platform]/build-a-backend/functions/set-up-function/index.mdx b/src/pages/[platform]/build-a-backend/functions/define-function/index.mdx
similarity index 51%
rename from src/pages/[platform]/build-a-backend/functions/set-up-function/index.mdx
rename to src/pages/[platform]/build-a-backend/functions/define-function/index.mdx
index e5ce9abe6de..7ca4d2f704a 100644
--- a/src/pages/[platform]/build-a-backend/functions/set-up-function/index.mdx
+++ b/src/pages/[platform]/build-a-backend/functions/define-function/index.mdx
@@ -1,7 +1,7 @@
import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
export const meta = {
- title: 'Set up an Amplify Function',
+ title: 'Define an Amplify Function',
description:
'Use AWS Lambda functions to perform tasks and customize workflows.',
platforms: [
@@ -29,44 +29,49 @@ export function getStaticProps(context) {
};
}
-Amplify Functions are powered by [AWS Lambda](https://aws.amazon.com/lambda/), and allow you to perform a wide variety of customization through contained _functions_.
+Amplify Functions are powered by [AWS Lambda](https://aws.amazon.com/lambda/), and allow you to perform a wide variety of customization through self-contained _functions_. Functions can respond to events from other resources, execute some logic in-between events like an authentication flow, or act as standalone jobs. They are used in a variety of settings and use cases:
+
+- Authentication flow customizations (e.g. attribute validations, allowlisting email domains)
+- Resolvers for GraphQL APIs
+- Handlers for individual REST API routes, or to host an entire API
+- Scheduled jobs
## Define a Function
-To get started, create a new directory and a resource file, `amplify/functions/my-demo-function/resource.ts`. Then, define the Function with `defineFunction`:
+To get started, create a new directory and a resource file, `amplify/functions/say-hello/resource.ts`. Then, define the Function with `defineFunction`:
-```ts title="amplify/functions/my-demo-function/resource.ts"
+```ts title="amplify/functions/say-hello/resource.ts"
import { defineFunction } from '@aws-amplify/backend';
-export const myDemoFunction = defineFunction({
+export const sayHello = defineFunction({
// optionally specify a name for the Function (defaults to directory name)
- name: 'my-demo-function',
+ name: 'say-hello',
// optionally specify a path to your handler (defaults to "./handler.ts")
entry: './handler.ts'
});
```
-Next, create the corresponding handler file at `amplify/functions/my-demo-function/handler.ts`. This is where your function code will go.
+Next, create the corresponding handler file at `amplify/functions/say-hello/handler.ts`. This is where your function code will go.
-```ts title="amplify/functions/my-demo-function/handler.ts"
+```ts title="amplify/functions/say-hello/handler.ts"
export const handler = async (event) => {
// your function code goes here
- return 'You made a function!';
+ return 'Hello, World!';
};
```
-The handler file _must_ export an async function named "handler". This is the entry point to your function. For more information on writing functions, refer to the [AWS documentation for Lambda function handlers using Node.js](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html).
+The handler file _must_ export a function named "handler". This is the entry point to your function. For more information on writing functions, refer to the [AWS documentation for Lambda function handlers using Node.js](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html).
Lastly, this function needs to be added to your backend.
```ts title="amplify/backend.ts"
import { defineBackend } from '@aws-amplify/backend';
// highlight-next-line
-import { myDemoFunction } from './functions/my-demo-function/resource';
+import { sayHello } from './functions/say-hello/resource';
defineBackend({
// highlight-next-line
- myDemoFunction
+ sayHello
});
```
@@ -76,7 +81,7 @@ Now when you run `npx amplify sandbox` or deploy your app on Amplify, it will in
Now that you have completed setting up your first Function, you may also want to add some additional features or modify a few settings. We recommend you learn more about:
-- [Environment variables and secrets](../environment-variables-and-secrets/)
-- [Grant access to other resources](../grant-access-to-other-resources/)
-- [Explore example use cases](../examples/)
-- [Modifying underlying resources with CDK](../modify-resources-with-cdk/)
+- [Environment variables and secrets](/[platform]/build-a-backend/functions/environment-variables-and-secrets/)
+- [Grant access to other resources](/[platform]/build-a-backend/functions/grant-access-to-other-resources/)
+- [Explore example use cases](/[platform]/build-a-backend/functions/examples/)
+- [Modifying underlying resources with CDK](/[platform]/build-a-backend/functions/modify-resources-with-cdk/)
diff --git a/src/pages/[platform]/build-a-backend/functions/environment-variables-and-secrets/index.mdx b/src/pages/[platform]/build-a-backend/functions/environment-variables-and-secrets/index.mdx
index 8dccd761ac1..dc636f8370d 100644
--- a/src/pages/[platform]/build-a-backend/functions/environment-variables-and-secrets/index.mdx
+++ b/src/pages/[platform]/build-a-backend/functions/environment-variables-and-secrets/index.mdx
@@ -29,7 +29,7 @@ export function getStaticProps() {
};
}
-Amplify Gen 2 Functions support setting environment variables and secrets on the `environment` property of `defineFunction`.
+Amplify Functions support setting environment variables and secrets on the `environment` property of `defineFunction`.
@@ -41,25 +41,26 @@ Amplify Gen 2 Functions support setting environment variables and secrets on the
Environment variables can be configured in `defineFunction` using the `environment` property.
-```ts title="amplify/functions/my-demo-function/resource.ts"
+```ts title="amplify/functions/say-hello/resource.ts"
import { defineFunction } from '@aws-amplify/backend';
-export const myDemoFunction = defineFunction({
+export const sayHello = defineFunction({
environment: {
- ENV_VAR_NAME: 'someValueHere'
+ NAME: 'World'
}
});
```
Any environment variables specified here will be available to the function at runtime.
-Some environment variables are constant across all branches and deployments. But many environment values differ between deployment environments. [Branch-specific environment variables can be configured for Amplify hosting deployments](/gen2/deploy-and-host/fullstack-branching/secrets-and-vars/#set-environment-variables).
+Some environment variables are constant across all branches and deployments. But many environment values differ between deployment environments. [Branch-specific environment variables can be configured for Amplify hosting deployments](/[platform]/deploy-and-host/fullstack-branching/secrets-and-vars/).
Suppose you created a branch-specific environment variable in hosting called "API_ENDPOINT" which had a different value for your "staging" vs "prod" branch. If you wanted that value to be available to your function you can pass it to the function using
-```ts title="amplify/functions/my-demo-function/resource.ts"
-export const myDemoFunction = defineFunction({
+```ts title="amplify/functions/say-hello/resource.ts"
+export const sayHello = defineFunction({
environment: {
+ NAME: "World",
API_ENDPOINT: process.env.API_ENDPOINT
}
});
@@ -69,13 +70,13 @@ export const myDemoFunction = defineFunction({
Within your function handler, you can access environment variables using the normal `process.env` global object provided by the Node runtime. However, this does not make it easy to discover what environment variables will be available at runtime. Amplify generates an `env` symbol that can be used in your function handler and provides typings for all variables that will be available at runtime. Copy the following code to use it.
-```ts title="amplify/functions/my-demo-function/handler.ts"
+```ts title="amplify/functions/say-hello/handler.ts"
// highlight-next-line
-import { env } from '$amplify/env/my-demo-function'; // the import is '$amplify/env/'
+import { env } from '$amplify/env/say-hello'; // the import is '$amplify/env/'
export const handler = async (event) => {
- env. // the env object has intellisense for all environment variables that are available to the function
- return 'You made a function!';
+ // the env object has intellisense for all environment variables that are available to the function
+ return `Hello, ${env.NAME}!`;
};
```
@@ -103,25 +104,33 @@ If you did not, you will need to manually configure your project. Within your `a
Sometimes it is necessary to provide a secret value to a function. For example, it may need a database password or an API key to perform some business use case. Environment variables should NOT be used for this because environment variable values are included in plaintext in the function configuration. Instead, secret access can be used.
-Before using a secret in a function, you need to [define a secret](/gen2/deploy-and-host/fullstack-branching/secrets-and-vars/#set-secrets). After you have defined a secret, you can reference it in your function config.
+Before using a secret in a function, you need to [define a secret](/[platform]/deploy-and-host/fullstack-branching/secrets-and-vars/#set-secrets). After you have defined a secret, you can reference it in your function config.
-```ts title="amplify/functions/my-demo-function/resource.ts"
+```ts title="amplify/functions/say-hello/resource.ts"
import { defineFunction, secret } from '@aws-amplify/backend';
-export const myDemoFunction = defineFunction({
+export const sayHello = defineFunction({
environment: {
- API_KEY: secret('myApiKey') // this assumes you created a secret named "myApiKey"
+ NAME: "World",
+ API_ENDPOINT: process.env.API_ENDPOINT,
+ API_KEY: secret('MY_API_KEY') // this assumes you created a secret named "MY_API_KEY"
}
});
```
You can use this secret value at runtime in your function the same as any other environment variable. However, you will notice that the value of the environment variable is not stored as part of the function configuration. Instead, the value is fetched when your function runs and is provided in memory.
-```ts title="amplify/functions/my-demo-function/handler.ts"
-import { env } from '$amplify/env/my-demo-function';
+```ts title="amplify/functions/say-hello/handler.ts"
+import { env } from '$amplify/env/say-hello';
export const handler = async (event) => {
- env.API_KEY; // this is the value of secret named "myApiKey"
- return 'You made a function!';
+ const request = new Request(env.API_ENDPOINT, {
+ headers: {
+ // this is the value of secret named "MY_API_KEY"
+ Authorization: `Bearer ${env.API_KEY}`
+ }
+ })
+ // ...
+ return `Hello, ${env.NAME}!`;
};
```
diff --git a/src/pages/[platform]/build-a-backend/functions/examples/dynamo-db-stream/index.mdx b/src/pages/[platform]/build-a-backend/functions/examples/dynamo-db-stream/index.mdx
new file mode 100644
index 00000000000..78ac096eac0
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/functions/examples/dynamo-db-stream/index.mdx
@@ -0,0 +1,98 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'DynamoDB stream',
+ description:
+ 'Create a Lambda event source using Amazon DynamoDB Streams to trigger a Lambda function in response to real-time events.',
+ platforms: [
+ 'android',
+ 'angular',
+ 'flutter',
+ 'javascript',
+ 'nextjs',
+ 'react',
+ 'react-native',
+ 'swift',
+ 'vue'
+ ]
+};
+
+export function getStaticPaths() {
+ return getCustomStaticPath(meta.platforms);
+}
+
+export function getStaticProps() {
+ return {
+ props: {
+ meta
+ }
+ };
+}
+
+With AWS Lambda, you can seamlessly integrate various event sources, such as Amazon DynamoDB, Amazon SQS, and others, to trigger Lambda functions in response to real-time events. This feature enables you to build responsive, event-driven applications that react to changes in data or system state without the need for polling services.
+
+In this guide, lets configure a Lambda function with an Amazon DynamoDB stream as an event source. The Lambda function is automatically triggered whenever an item is added, updated, or deleted from the table, enabling you to build real-time applications that react to changes in your data. In this example, we will use a `Todo` table created by a data model on the GraphQL API.
+
+To get started, install the AWS Lambda Powertools Logger package, which provides a structured logging capabilities for your Lambda function.
+
+```bash title="Terminal" showLineNumbers={false}
+npm add @aws-lambda-powertools/logger
+```
+
+Second, create a new directory and a resource file, `amplify/functions/dynamoDB-function/resource.ts`. Then, define the Function with `defineFunction`:
+
+```ts title="amplify/functions/dynamoDB-function/resource.ts"
+import { defineFunction } from "@aws-amplify/backend";
+
+export const myDynamoDBFunction = defineFunction({
+ name: "dynamoDB-function",
+});
+```
+
+Third, create the corresponding handler file, `amplify/functions/dynamoDB-function/handler.ts`, file with the following contents:
+
+```ts title="amplify/functions/dynamoDB-function/resource.ts"
+import type { DynamoDBStreamHandler } from "aws-lambda";
+import { Logger } from "@aws-lambda-powertools/logger";
+
+const logger = new Logger({
+ logLevel: "INFO",
+ serviceName: "dynamodb-stream-handler",
+});
+
+export const handler: DynamoDBStreamHandler = async (event) => {
+ for (const record of event.Records) {
+ logger.info(`Processing record: ${record.eventID}`);
+ logger.info(`Event Type: ${record.eventName}`);
+
+ if (record.eventName === "INSERT") {
+ // business logic to process new records
+ logger.info(`New Image: ${JSON.stringify(record.dynamodb?.NewImage)}`);
+ }
+ }
+ logger.info(`Successfully processed ${event.Records.length} records.`);
+};
+```
+
+Lastly, create DynamoDB table as event source in the `amplify/backend.ts` file:
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from "@aws-amplify/backend";
+import { StartingPosition } from "aws-cdk-lib/aws-lambda";
+import { DynamoEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
+import { auth } from "./auth/resource";
+import { data } from "./data/resource";
+import { myDynamoDBFunction } from "./functions/kinesis-function/resource";
+
+const backend = defineBackend({
+ auth,
+ data,
+ myDynamoDBFunction,
+});
+
+const eventSource = new DynamoEventSource(backend.data.resources.tables["Todo"], {
+ startingPosition: StartingPosition.LATEST,
+});
+
+backend.myDynamoDBFunction.resources.lambda.addEventSource(eventSource);
+```
diff --git a/src/pages/[platform]/build-a-backend/functions/examples/kinesis-stream/index.mdx b/src/pages/[platform]/build-a-backend/functions/examples/kinesis-stream/index.mdx
new file mode 100644
index 00000000000..b863c486263
--- /dev/null
+++ b/src/pages/[platform]/build-a-backend/functions/examples/kinesis-stream/index.mdx
@@ -0,0 +1,132 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Kinesis stream',
+ description:
+ 'Create a Lambda event source for a Amazon Kinesis stream to trigger Lambda functions in response to real-time events',
+ platforms: [
+ 'android',
+ 'angular',
+ 'flutter',
+ 'javascript',
+ 'nextjs',
+ 'react',
+ 'react-native',
+ 'swift',
+ 'vue'
+ ]
+};
+
+export function getStaticPaths() {
+ return getCustomStaticPath(meta.platforms);
+}
+
+export function getStaticProps() {
+ return {
+ props: {
+ meta
+ }
+ };
+}
+
+With AWS Lambda, you can seamlessly integrate various event sources, such as Amazon Kinesis, Amazon SQS, and others, to trigger Lambda functions in response to real-time events. This feature enables you to build responsive, event-driven applications that react to changes in data or system state without the need for polling services.
+
+In this guide, lets configure a Lambda function with an Amazon Kinesis stream as an event source. The Lambda function is automatically triggered whenever new data is published to the stream, whether you're processing streaming data, reacting to application events, or automating workflows.
+
+To get started, install the AWS Lambda Powertools Logger package, which provides a structured logging capabilities for your Lambda function.
+
+```bash title="Terminal" showLineNumbers={false}
+npm add @aws-lambda-powertools/logger
+```
+
+Second, create a new directory and a resource file, `amplify/functions/kinesis-function/resource.ts`. Then, define the Function with `defineFunction`:
+
+```ts title="amplify/functions/kinesis-function/resource.ts"
+import { defineFunction } from "@aws-amplify/backend";
+
+export const myKinesisFunction = defineFunction({
+ name: "kinesis-function",
+});
+```
+
+Third, create the corresponding handler file, `amplify/functions/kinesis-function/handler.ts`, file with the following contents:
+
+```ts title="amplify/functions/kinesis-function/handler.ts"
+import type {
+ KinesisStreamBatchResponse,
+ KinesisStreamHandler,
+ KinesisStreamRecordPayload,
+} from "aws-lambda";
+import { Buffer } from "node:buffer";
+import { Logger } from "@aws-lambda-powertools/logger";
+
+const logger = new Logger({
+ logLevel: "INFO",
+ serviceName: "kinesis-stream-handler",
+});
+
+export const handler: KinesisStreamHandler = async (
+ event,
+ context
+): Promise => {
+ for (const record of event.Records) {
+ try {
+ logger.info(`Processed Kinesis Event - EventID: ${record.eventID}`);
+ const recordData = await getRecordDataAsync(record.kinesis);
+ logger.info(`Record Data: ${recordData}`);
+ } catch (err) {
+ logger.error(`An error occurred ${err}`);
+ /**
+ * When processing stream data, if any item fails, returning the failed item's position immediately
+ * prompts Lambda to retry from this item forward, ensuring continuous processing without skipping data.
+ */
+ return {
+ batchItemFailures: [{ itemIdentifier: record.kinesis.sequenceNumber }],
+ };
+ }
+ }
+ logger.info(`Successfully processed ${event.Records.length} records.`);
+ return { batchItemFailures: [] };
+};
+
+async function getRecordDataAsync(
+ payload: KinesisStreamRecordPayload
+): Promise {
+ const data = Buffer.from(payload.data, "base64").toString("utf-8");
+ await Promise.resolve(1); // Placeholder for an async process
+ return data;
+}
+```
+
+Lastly, create the Kinesis stream and add it as a event source in the `amplify/backend.ts` file:
+
+```ts title="amplify/backend.ts"
+import { defineBackend } from "@aws-amplify/backend";
+import { KinesisEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
+import { StartingPosition } from "aws-cdk-lib/aws-lambda";
+import { auth } from "./auth/resource";
+import { data } from "./data/resource";
+import { myKinesisFunction } from "./functions/kinesis-function/resource";
+
+const backend = defineBackend({
+ auth,
+ data,
+ myKinesisFunction,
+});
+
+const kinesisStack = backend.createStack("kinesis-stack");
+
+const kinesisStream = new Stream(kinesisStack, "KinesisStream", {
+ streamName: "myKinesisStream",
+ shardCount: 1,
+});
+
+const eventSource = new KinesisEventSource(kinesisStream, {
+ startingPosition: StartingPosition.LATEST,
+ reportBatchItemFailures: true,
+});
+
+backend.myKinesisFunction.resources.lambda.addEventSource(eventSource);
+```
+
+For an example of streaming analytics data to the Amazon Kinesis stream from your frontend, see the [Streaming analytics data documentation](/[platform]/build-a-backend/add-aws-services/analytics/streaming-data/)
diff --git a/src/pages/[platform]/build-a-backend/functions/index.mdx b/src/pages/[platform]/build-a-backend/functions/index.mdx
index db809f42567..cd471e808a4 100644
--- a/src/pages/[platform]/build-a-backend/functions/index.mdx
+++ b/src/pages/[platform]/build-a-backend/functions/index.mdx
@@ -35,7 +35,7 @@ export function getStaticProps() {
-**Under active development:** The Functions experience for Amplify Gen 2 is under active development. The experience may change between versions of `@aws-amplify/backend`. Try it out and provide feedback at https://github.com/aws-amplify/amplify-backend/issues/new/choose
+**Under active development:** The Functions experience for Amplify is under active development. The experience may change between versions of `@aws-amplify/backend`. Try it out and provide feedback at https://github.com/aws-amplify/amplify-backend/issues/new/choose
diff --git a/src/pages/[platform]/build-a-backend/storage/define-storage/index.mdx b/src/pages/[platform]/build-a-backend/storage/define-storage/index.mdx
index 4cdb2e72604..def07197d33 100644
--- a/src/pages/[platform]/build-a-backend/storage/define-storage/index.mdx
+++ b/src/pages/[platform]/build-a-backend/storage/define-storage/index.mdx
@@ -113,7 +113,7 @@ export const storage = defineStorage({
name: 'myProjectFiles',
access: (allow) => ({
'public/*': [
- allow.guest.to(['read'])
+ allow.guest.to(['read']),
allow.authenticated.to(['read', 'write', 'delete']),
],
'protected/{entity_id}/*': [
diff --git a/src/pages/[platform]/how-amplify-works/concepts/index.mdx b/src/pages/[platform]/how-amplify-works/concepts/index.mdx
index fee684f4572..cc2c9084e93 100644
--- a/src/pages/[platform]/how-amplify-works/concepts/index.mdx
+++ b/src/pages/[platform]/how-amplify-works/concepts/index.mdx
@@ -30,11 +30,11 @@ export function getStaticProps(context) {
}
-AWS Amplify Gen 2 introduces a TypeScript-based, code-first developer experience (DX) for defining backends. The Gen 2 DX offers a unified Amplify developer experience with the same hosting, backend, and UI-building capabilities previously available in CLI and Studio, but with a code-first approach. Amplify empowers frontend developers to deploy cloud infrastructure by simply expressing their app’s data model, business logic, authentication, and authorization rules completely in TypeScript. Amplify automatically configures the correct cloud resources and removes the requirement to stitch together underlying AWS services.
+AWS Amplify Gen 2 uses a TypeScript-based, code-first developer experience (DX) for defining backends. The Gen 2 DX offers a unified Amplify developer experience with hosting, backend, and UI-building capabilities and a code-first approach. Amplify empowers frontend developers to deploy cloud infrastructure by simply expressing their app’s data model, business logic, authentication, and authorization rules completely in TypeScript. Amplify automatically configures the correct cloud resources and removes the requirement to stitch together underlying AWS services.
## Capabilities
-Just like with the CLI and Studio in Gen 1, you can use Amplify for end-to-end fullstack development, but with major differences in the developer experience.
+You can use Amplify for end-to-end fullstack development.
### Build fullstack apps with TypeScript
@@ -50,13 +50,13 @@ Per-developer cloud sandbox environments are optimized for faster iterations. Ea
### Fullstack Git-based environments
-With Gen 2, all shared environments (such as `production`, `staging`, `gamma`) map 1:1 to Git branches in your repository. New features can be tested in ephemeral environments with pull request previews (or feature branches) before they are merged into production. Unlike the Gen 1 experience, which requires users to configure a number of steps in the CLI or Console to set up a fullstack environment, the Gen 2 experience is zero-config. Because of our code-first approach, the Git repository is always the source of truth for the state of the fullstack app—all backend resources are defined as code for reproducibility and portability across branches. This, along with central management of environment variables and secrets, simplifies the promotion workflow from lower to upper environments.
+All shared environments (such as `production`, `staging`, `gamma`) map 1:1 to Git branches in your repository. New features can be tested in ephemeral environments with pull request previews (or feature branches) before they are merged into production. Unlike the Gen 1 experience, which requires users to configure a number of steps in the CLI or Console to set up a fullstack environment, the Gen 2 experience is zero-config. Because of our code-first approach, the Git repository is always the source of truth for the state of the fullstack app—all backend resources are defined as code for reproducibility and portability across branches. This, along with central management of environment variables and secrets, simplifies the promotion workflow from lower to upper environments.

### Unified management console
-All branches can be managed in the new Amplify console. The Gen 2 Amplify console consolidates the console experiences across Studio and Hosting, providing a single place for you to manage your builds, hosting settings (such as custom domains), deployed resources (such as data browser or user management), and environment variables and secrets. Even though you can access deployed resources directly in other AWS service consoles, the Amplify console will offer a first-party experience for the categories almost every app needs—data, auth, storage, and functions. For example, with Data, Amplify offers an API playground and a data manager (coming soon) with relationship building, seed data generation, and file upload capabilities.
+All branches can be managed in the new Amplify console. The Amplify Gen 2 console provides a single place for you to manage your builds, hosting settings (such as custom domains), deployed resources (such as data browser or user management), and environment variables and secrets. Even though you can access deployed resources directly in other AWS service consoles, the Amplify console will offer a first-party experience for the categories almost every app needs—data, auth, storage, and functions. For example, with Data, Amplify offers an API playground and a data manager (coming soon) with relationship building, seed data generation, and file upload capabilities.
+
+
+
In addition, you can also use OpenID Connect with `private` authorization. See [OpenID Connect as an authorization provider](#using-oidc-authorization-provider).
**Note:** If you have a connected child model that allows `private` level access, any user authorized to fetch it from the parent model will be able to read the connected child model. For example,
@@ -672,12 +692,11 @@ userPools:owner:owner
### Use IAM authorization within the AppSync console
-IAM-based `@auth` rules are scoped down to only work with Amplify-generated IAM roles. To access the GraphQL API with IAM authorization within your AppSync console, you need to explicitly allow list the IAM user's name.
-Add the allow-listed IAM users by adding them to `amplify/backend/api//custom-roles.json`. (Create the `custom-roles.json` file if it doesn't exist). Append the `adminRoleNames` array with the IAM role or user names:
+IAM-based `@auth` rules are scoped down to only work with Amplify-generated IAM roles. To access the GraphQL API with IAM authorization within your AppSync console, you need to explicitly allow list the IAM user's name. Add the allow-listed IAM users by adding them to `amplify/backend/api//custom-roles.json`. (Create the `custom-roles.json` file if it doesn't exist). Append the `adminRoleNames` array with the IAM role or user names:
```json
{
@@ -688,7 +707,7 @@ Add the allow-listed IAM users by adding them to `amplify/backend/api/
-To grant an external AWS Resource or an IAM role access to this GraphQL API in CDK, you need to explicitly list the IAM role by adding them to `adminRoles` property.
+To grant any IAM principal (AWS Resource, IAM role, IAM user, etc) access, **with the exception of Amazon Cognito identity pool roles**, to this GraphQL API in CDK, you need to enable IAM authorization mode via the `iamConfig` property of the CDK construct.
```typescript
const userRole = Role.fromRoleName(
@@ -706,7 +725,10 @@ const amplifyApi = new AmplifyGraphqlApi(this, 'MyNewApi', {
apiKeyConfig: {
expires: cdk.Duration.days(30)
},
- adminRoles: [userRole] // <-- pass in the role of the console user into here to grant it access via IAM
+ iamConfig: {
+ // Set this value to true.
+ enableIamAuthorizationMode: true
+ }
}
});
```
@@ -811,7 +833,7 @@ Once you grant a function access to the GraphQL API, it is required to redeploy
-To grant an external AWS Resource or an IAM role access to this GraphQL API in CDK, you need to explicitly list the IAM role by adding them to `adminRoles` property.
+To grant any IAM principal (AWS Resource, IAM role, IAM user, etc), **with the exception of Amazon Cognito identity pool roles**, to this GraphQL API in CDK, you need to enable IAM authorization mode on the CDK construct.
```typescript
const amplifyApi = new AmplifyGraphqlApi(this, 'MyNewApi', {
@@ -823,9 +845,10 @@ const amplifyApi = new AmplifyGraphqlApi(this, 'MyNewApi', {
apiKeyConfig: {
expires: cdk.Duration.days(30)
},
- adminRoles: [
- myFunction.role // <- Add your function's role here to grant it access to issue queries, mutations, and subscriptions
- ]
+ iamConfig: {
+ // Must be set to `true`. Then grant your Lambda function's execution role access to the API
+ enableIamAuthorizationMode: true
+ }
}
});
```
diff --git a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/mutate-data/index.mdx b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/mutate-data/index.mdx
index d4491622aeb..867bec5bdc9 100644
--- a/src/pages/gen1/[platform]/build-a-backend/graphqlapi/mutate-data/index.mdx
+++ b/src/pages/gen1/[platform]/build-a-backend/graphqlapi/mutate-data/index.mdx
@@ -322,7 +322,7 @@ const updatedTodo = await client.graphql({
To update data, replace the request with `.update`.
```swift
-try await Amplify.API.mutate(request: .create(todo))
+try await Amplify.API.mutate(request: .update(todo))
```
diff --git a/src/pages/gen1/[platform]/tools/cli/migration/iam-auth-updates-for-cdk-construct/index.mdx b/src/pages/gen1/[platform]/tools/cli/migration/iam-auth-updates-for-cdk-construct/index.mdx
new file mode 100644
index 00000000000..ed556f89364
--- /dev/null
+++ b/src/pages/gen1/[platform]/tools/cli/migration/iam-auth-updates-for-cdk-construct/index.mdx
@@ -0,0 +1,72 @@
+import { getCustomStaticPath } from '@/utils/getCustomStaticPath';
+
+export const meta = {
+ title: 'Improved IAM authorization when using GraphQL API CDK construct',
+ description: 'This reference documents the behavioral improvements coming to IAM authorization when you deploy your GraphQL API using the Amplify GraphQL CDK construct.',
+ platforms: [
+ 'android',
+ 'angular',
+ 'flutter',
+ 'javascript',
+ 'nextjs',
+ 'react',
+ 'react-native',
+ 'swift',
+ 'vue'
+ ],
+};
+
+export const getStaticPaths = async () => {
+ return getCustomStaticPath(meta.platforms);
+};
+
+export function getStaticProps(context) {
+ return {
+ props: {
+ platform: context.params.platform,
+ meta
+ }
+ };
+}
+
+
+## What is changing?
+
+In an effort to improve the usability of the GraphQL API CDK construct with other AWS resources, such as AWS Lambda functions, we're providing a new way to configure IAM authorization. This change does not affect customers using the Amplify CLI (Gen 1) to build and deploy their GraphQL APIs (amplify add api).
+
+### How did IAM authorization work before this improvement?
+
+There are two use cases for IAM auth with the Amplify GraphQL CDK construct.
+
+**Use case 1: Provide a deny-by-default authorization pattern for Amazon Cognito identity pool's unauthenticated and authenticated role access to the API.** We wanted to ensure if you want any unauthenticated roles to access a model, you must explicit allow-list that behavior. For example: `@auth(rules: [{ allow: public, provider: iam }])`.
+
+**Use case 2: Provide access to the GraphQL API from other IAM principals, such as AWS Lambda functions' execution role, or to use the GraphQL query explorer from the AWS AppSync console.** In this case, despite these IAM roles having the required IAM policies to access the GraphQL API, you needed to also supply these IAM roles into the Amplify GraphQL API CDK construct's `allowListedRoles` properties. This often led to circular dependency issues that are difficult to untangle.
+
+### How does IAM authorization work after this improvement?
+
+We'll issue a non-breaking feature improvement that'll make the use case clearer for customers.
+
+**Changes to use case 1:** To make the API more descriptive and clarify its intended behavior, we're renaming the `provider: iam` variable to `provider: identityPool` in the `@auth` rules. At the same time, we're introducing a `identityPoolConfig` property on the CDK construct that'll accept the existing values for (`identityPoolId`, `authenticatedUserRole`, `unauthenticatedUserRole`).
+
+**Changes to use case 2:** Instead of explicitly setting the `allowListedRoles`, you now only need to set the `enableIamAuthorizationMode: true` under the `iamConfig` property. Now all resource access to the API with the exception of Amazon Cognito identity pool roles are governed by the resources' IAM role and policies.
+
+### How do I take advantage of this improvement?
+
+To take advantage of this improvement, follow these steps:
+
+1. Upgrade to the latest version of the Amplify GraphQL API CDK construct by running `npm install @aws-amplify/graphql-api-construct@latest`
+2. Set the `enableIamAuthorizationMode` to `true` under `iamConfig`.
+3. Move the existing values for `identityPoolId`, `authenticatedUserRole`, `unauthenticatedUserRole` from `iamConfig` to `identityPoolConfig`.
+4. Validate that all IAM roles has the appropriate permissions to access the GraphQL API. **If you have configured prior overly permissive policies, modify the policies accordingly.**
+5. Unset the values for `allowListedRoles`. Your `iamConfig` should only have a `enableIamAuthorizationMode: true` value at this point.
+6. Deploy your GraphQL API with the updated configuration via `cdk deploy`.
+
+## Is this a breaking change?
+
+No. Your existing IAM authorization behavior will continue to work but we plan on deprecating the old behavior in the future, thus we highly recommend you to upgrade to the new behavior. If the following values under `iamConfig` are present, then the behavior remains as before: `identityPoolId`, `authenticatedUserRole`, `unauthenticatedUserRole`, `allowListedRoles`.
+
+## Who can take advantage of this improvement?
+
+Only customers using the [Amplify GraphQL API CDK construct](https://constructs.dev/packages/@aws-amplify/graphql-api-construct/v/1.6.0?lang=typescript) will be able to take advantage of this improvement.
+
+If you use the Amplify CLI (Gen 1) to deploy your GraphQL API (`amplify add api`), this improvement **does not** affect you.
diff --git a/src/styles/code.scss b/src/styles/code.scss
index 0eb017eac8d..0d61a1526f7 100644
--- a/src/styles/code.scss
+++ b/src/styles/code.scss
@@ -131,6 +131,48 @@ code:not([class]) {
width: 1.8rem;
}
+.highlight-copy-block {
+ all: unset;
+ width: 100%;
+ cursor: pointer;
+ position: relative;
+}
+
+.highlight-copy-block-hint {
+ position: absolute;
+ top: 0;
+ right: 1.8rem;
+ color: white;
+}
+
+.highlight-copy-block .highlight-c4py-block-hint {
+ display: none;
+}
+
+.highlight-copy-block:focus .highlight-copy-block-hint {
+ display: block;
+}
+
+.highlight-copy-block:hover .highlight-copy-block-hint {
+ display: block;
+}
+
+.highlight-copy-block:focus .line-highlight::before {
+ background-color: var(--amplify-colors-primary-80);
+
+ @include darkMode {
+ background-color: var(--amplify-colors-neutral-40);
+ }
+}
+
+.highlight-copy-block:hover .line-highlight::before {
+ background-color: var(--amplify-colors-primary-90);
+
+ @include darkMode {
+ background-color: var(--amplify-colors-primary-10);
+ }
+}
+
.code-copy {
--code-copy-hover-background-color: var(--amplify-colors-neutral-90);
--code-copy-focus-background-color: var(--amplify-colors-neutral-90);