Amplify has re-imagined the way frontend developers build fullstack applications. Develop and deploy without the hassle.

Page updated May 6, 2024

Connect your app code to API

In this guide, you will connect your application code to the backend API using the Amplify Libraries. Before you begin, you will need:

  • Your cloud sandbox with an Amplify Data resource up and running (npx ampx sandbox)
  • A frontend application set up with the Amplify library installed
  • npm installed

Configure the Amplify Library

When you deploy you're iterating on your backend (npx ampx sandbox), an amplify_outputs.json file is generated for you. This file contains your API's endpoint information and auth configurations. Add the following code to your app's entrypoint to initialize and configure the Amplify client library:

1import { Amplify } from 'aws-amplify';
2import outputs from '../amplify_outputs.json';
3
4Amplify.configure(outputs);

Generate the Amplify Data client

Once the Amplify library is configured, you can generate a "Data client" for your frontend code to make fully-typed API requests to your backend.

If you're using Amplify with a JavaScript-only frontend (i.e. not TypeScript), then you can still get a fully-typed data fetching experience by annotating the generated client with a JSDoc comment. Select the JavaScript in the code block below to see how.

To generate a new Data client, use the following code:

1import { generateClient } from 'aws-amplify/data';
2import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
3
4const client = generateClient<Schema>();
5
6// Now you should be able to make CRUDL operations with the
7// Data client
8const fetchTodos = async () => {
9 const { data: todos, errors } = await client.models.Todo.list();
10};
1import { generateClient } from 'aws-amplify/data';
2
3/**
4 * @type {import('aws-amplify/data').Client<import('../amplify/data/resource').Schema>}
5 */
6const client = generateClient();
7
8// Now you should be able to make CRUDL operations with the
9// Data client
10const fetchTodos = async () => {
11 const { data: todos, errors } = await client.models.Todo.list();
12};

Configure authorization mode

The Authorization Mode determines how a request should be authorized with the backend. By default, Amplify Data uses the "userPool" authorization which uses the signed-in user credentials to sign an API request. If you use a allow.publicApiKey() authorization rules for your data models, you need to use "apiKey" as an authorization mode. Review Customize your auth rules to learn more about which authorization modes to choose for which type of request. A Default Authorization Mode is provided as part of the amplify_outputs.json that is generated upon a successful deployment.

You can generate different Data clients with different authorization modes or pass in the authorization mode at the request time.

Set authorization mode on a per-client basis

To apply the same authorization mode on all requests from a Data client, specify the authMode parameter on the generateClient function.

Use "API Key" as your authorization mode when if defined the allow.publicApiKey() authorization rule.

1import { generateClient } from 'aws-amplify/data';
2import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
3
4const client = generateClient<Schema>({
5 authMode: 'apiKey',
6});

Use "userPool" as your authorization mode when using Amazon Cognito user pool-based authorization rules, such as allow.authenticated(), allow.owner(), allow.ownerDefinedIn(), allow.groupsDefinedIn(), or allow.groups().

1import { generateClient } from 'aws-amplify/data';
2import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
3
4const client = generateClient<Schema>({
5 authMode: 'userPool',
6});

Use "identityPool" as your authorization mode when using Amazon Cognito identity pool-based authorization rules, such as allow.guest() or allow.authenticated('identityPool').

1import { generateClient } from 'aws-amplify/data';
2import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
3
4const client = generateClient<Schema>({
5 authMode: 'identityPool',
6});

Use "oidc" as your authorization mode when connecting applications to a trusted identity provider. Private, owner, and group authorization can be configured with an OIDC authorization mode. Review the OIDC authorization docs to learn more.

1import { generateClient } from 'aws-amplify/data';
2import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
3
4const client = generateClient<Schema>({
5 authMode: 'oidc',
6});

Use "Lambda Authorizer" when using your own custom authorization logic via allow.custom(). Review Customize your auth rules to learn more about how to implement your authorization protocol.

1import { generateClient } from 'aws-amplify/data';
2import type { Schema } from '../amplify/data/resource'; // Path to your backend resource definition
3
4const getAuthToken = () => 'myAuthToken';
5const lambdaAuthToken = getAuthToken();
6
7const client = generateClient<Schema>({
8 authMode: 'lambda',
9 authToken: lambdaAuthToken,
10});

Set authorization mode on the request-level

You can also specify the authorization mode on each individual API request. This is useful if your application typically only uses one authorization mode with a small number of exceptions.

1const { data: todos, errors } = await client.models.Todo.list({
2 authMode: 'apiKey',
3});
1const { data: todos, errors } = await client.models.Todo.list({
2 authMode: 'userPool',
3});
1const { data: todos, errors } = await client.models.Todo.list({
2 authMode: 'identityPool',
3});
1const { data: todos, errors } = await client.models.Todo.list({
2 authMode: 'oidc',
3});

You can implement your own custom API authorization logic using a AWS Lambda function. Review Customize your auth rules to learn more about how to implement your authorization protocol with AWS Lambda.

1const getAuthToken = () => 'myAuthToken';
2const lambdaAuthToken = getAuthToken();
3
4const { data: todos, errors } = await client.models.Todo.list({
5 authMode: 'lambda',
6 authToken: lambdaAuthToken,
7});

Set custom request headers

When working with the Amplify Data endpoint, you may need to set request headers for authorization purposes or to pass additional metadata from your frontend to the backend API.

This is done by specifying a headers parameter into the configuration. You can define headers either on a per Data client-level or on a per-request level:

1import type { Schema } from '../amplify/data/resource';
2import { generateClient } from 'aws-amplify/data';
3
4const client = generateClient<Schema>({
5 headers: {
6 'My-Custom-Header': 'my value',
7 },
8});
1// same way for all CRUDL: .create, .get, .update, .delete, .list, .observeQuery
2const { data: blog, errors } = await client.models.Blog.get(
3 { id: 'myBlogId' },
4 {
5 headers: {
6 'My-Custom-Header': 'my value',
7 },
8 }
9);

The examples above show you how to set static headers but you can also programmatically set headers by specifying an async function for headers:

1import type { Schema } from '../amplify/data/resource';
2import { generateClient } from 'aws-amplify/data';
3
4const client = generateClient<Schema>({
5 headers: async (requestOptions) => {
6 console.log(requestOptions);
7 /* The request options allow you to customize your headers based on the request options such
8 as http method, headers, request URI, and query string. These options are typically used
9 to create a request signature.
10 {
11 method: '...',
12 headers: { },
13 uri: '/',
14 queryString: ""
15 }
16 */
17 return {
18 'My-Custom-Header': 'my value',
19 };
20 },
21});
1// same way for all CRUDL: .create, .get, .update, .delete, .list, .observeQuery
2const res = await client.models.Blog.get(
3 { id: 'myBlogId' },
4 {
5 headers: async (requestOptions) => {
6 console.log(requestOptions);
7 /* The request options allow you to customize your headers based on the request options such
8 as http method, headers, request URI, and query string. These options are typically used
9 to create a request signature.
10 {
11 method: '...',
12 headers: { },
13 uri: '/',
14 queryString: ""
15 }
16 */
17 return {
18 'My-Custom-Header': 'my value',
19 };
20 },
21 }
22);