Build a Basic Web Application

TUTORIAL

Task 3: Create a Data Table

In this task, you will create a data model to persist data using a GraphQL API and Amazon DynamoDB. 

Overview

In this task, you will create a data model to persist data using a GraphQL API and Amazon DynamoDB.  Additionally, you will use AWS Identity and Access Management (IAM) authorization to securely give our services the required permissions to interact with each other. You will also allow the Lambda function you created in the previous task to use the GraphQL API to write to your newly created DynamoDB table using an IAM policy.  

Key concepts

Amplify backend: Amplify Gen 2 uses a full stack TypeScript developer experience (DX) for defining backends. Simply author app requirements like data models, business logic, and auth rules in TypeScript. Amplify automatically configures the correct cloud resources and deploys them to per-developer cloud sandbox environments for fast, local iteration.

Implementation

 Minimum time to complete

5 minutes

 Services used

  • 1. On your local machine, navigate to the amplify/data/resource.ts file and update it with the following code. Then, save the file.

    • The following code will define the schema for the UserProfile data model using a per-owner authorization rule allow.owner() to restrict the expense record’s access to the creator of the record.
    • It also uses the field profileOwner to track the ownership, and configures the authorization rule to allow the postConfirmation resource. 
    • Granting access to resources creates environment variables for your function, such as the GraphQL API endpoint.
    import { type ClientSchema, a, defineData } from "@aws-amplify/backend";
    import { postConfirmation } from "../auth/post-confirmation/resource";
    
    const schema = a
      .schema({
        UserProfile: a
          .model({
            email: a.string(),
            profileOwner: a.string(),
          })
          .authorization((allow) => [
            allow.ownerDefinedIn("profileOwner"),
          ]),
      })
      .authorization((allow) => [allow.resource(postConfirmation)]);
    export type Schema = ClientSchema<typeof schema>;
    
    export const data = defineData({
      schema,
      authorizationModes: {
        defaultAuthorizationMode: "apiKey",
        apiKeyAuthorizationMode: {
          expiresInDays: 30,
        },
      },
    });

    2. Open a new terminal window, navigate to your app's root folder (profilesapp), and run the following command to deploy cloud resources into an isolated development space so you can iterate fast.

    npx ampx sandbox

    3. Once the cloud sandbox has been fully deployed, your terminal will display a confirmation message and the amplify_outputs.json file will be generated and added to your project.

    4. Open a new terminal window, navigate to your app's root folder(profilesapp), and run the following command to generate the GraphQL client code to call your data backend.

    Note: You will need to update the following command to use the path to the post-confirmation folder that you created in the previous step. For example: npx ampx generate graphql-client-code --out amplify/auth/post-confirmation/graphql.

    npx ampx generate graphql-client-code --out <path-to-post-confirmation-handler-dir>/graphql
    • Amplify will create the folder amplify/auth/post-confirmation/graphql where you will find the client code to connect to the GraphQL API.
  • 1. On your local machine, navigate to the amplify/auth/post-confirmation/handler.ts file and replace the code with the following code. Then, save the file.

    • The following code configures the Amplify using the env variables and sets the authorization to use IAM. It then generates a data client using the generateClient() function. Finally, it uses the data client to create a user profile by setting the email and owner based on the attributes of the signed-up user.
    import type { PostConfirmationTriggerHandler } from "aws-lambda";
    import { type Schema } from "../../data/resource";
    import { Amplify } from "aws-amplify";
    import { generateClient } from "aws-amplify/data";
    import { env } from "$amplify/env/post-confirmation";
    import { createUserProfile } from "./graphql/mutations";
    
    Amplify.configure(
      {
        API: {
          GraphQL: {
            endpoint: env.AMPLIFY_DATA_GRAPHQL_ENDPOINT,
            region: env.AWS_REGION,
            defaultAuthMode: "iam",
          },
        },
      },
      {
        Auth: {
          credentialsProvider: {
            getCredentialsAndIdentityId: async () => ({
              credentials: {
                accessKeyId: env.AWS_ACCESS_KEY_ID,
                secretAccessKey: env.AWS_SECRET_ACCESS_KEY,
                sessionToken: env.AWS_SESSION_TOKEN,
              },
            }),
            clearCredentialsAndIdentityId: () => {
              /* noop */
            },
          },
        },
      }
    );
    
    const client = generateClient<Schema>({
      authMode: "iam",
    });
    
    export const handler: PostConfirmationTriggerHandler = async (event) => {
      await client.graphql({
        query: createUserProfile,
        variables: {
          input: {
            email: event.request.userAttributes.email,
            profileOwner: `${event.request.userAttributes.sub}::${event.userName}`,
          },
        },
      });
    
      return event;
    };

Conclusion

You have created a data table and configured a GraphQL API to persist data in an Amazon DynamoDB database. Then, you updated the Lambda function to use the API.

Was this page helpful?

Link a Serverless Function to a Web App