## Using Amplify GraphQL Client

The API category provides a GraphQL client for working with queries, mutations, and subscriptions.

### Query Declarations

The Amplify CLI codegen automatically generates all possible GraphQL statements (queries, mutations and subscriptions) and for JavaScript applications saves it in `src/graphql` folder

```javascript
import * as queries from './graphql/queries';
import * as mutations from './graphql/mutations';
import * as subscriptions from './graphql/subscriptions';
```

### Simple Query

Running a GraphQL query is simple. Import the generated query and execute it with `API.graphql`:

<BlockSwitcher>
<Block name="TypeScript">

```ts
import { API } from 'aws-amplify';
import * as queries from './graphql/queries';
import { GraphQLQuery } from '@aws-amplify/api';
import { ListTodosQuery, GetTodoQuery } from './API';

// Simple query
const allTodos = await API.graphql<GraphQLQuery<ListTodosQuery>>(
  { query: queries.listTodos }
);
console.log(allTodos); // result: { "data": { "listTodos": { "items": [/* ..... */] } } }

// Fetch a single record by its identifier
const oneTodo = await API.graphql<GraphQLQuery<GetTodoQuery>>({
  query: queries.getTodo,
  variables: { id: 'some id' }
});
```

</Block>

<Block name="JavaScript">

```js
import { API } from 'aws-amplify';
import * as queries from './graphql/queries';

// Simple query
const allTodos = await API.graphql({ query: queries.listTodos });
console.log(allTodos); // result: { "data": { "listTodos": { "items": [/* ..... */] } } }

Fetch a single record by its identifier
const oneTodo = await API.graphql({
  query: queries.getTodo,
  variables: { id: 'some id' }
});
```

</Block>
</BlockSwitcher>

You can optionally import the `graphqlOperation` helper function to help you construct this argument object:

<BlockSwitcher>
<Block name="TypeScript">

```ts
import { API, graphqlOperation } from 'aws-amplify';
import { GraphQLQuery } from '@aws-amplify/api';
import { GetTodoQuery } from './API';
// ...

const oneTodo = await API.graphql<GraphQLQuery<GetTodoQuery>>(
  graphqlOperation(queries.getTodo, { id: 'some id' })
);
```

</Block>

<Block name="JavaScript">

```js
import { API, graphqlOperation } from 'aws-amplify';
// ...

const oneTodo = await API.graphql(
  graphqlOperation(queries.getTodo, { id: 'some id' })
);
```

</Block>
</BlockSwitcher>

### Custom authorization mode

By default, each AppSync API will be set with a default authorization mode when you configure your app. If you would like to override the default authorization mode, you can do so by passing in an `authMode` property. For example, this is useful when you have public reads via API Key auth and authenticated reads via IAM auth.

#### Query with custom authorization mode

<BlockSwitcher>
<Block name="TypeScript">

```ts
import { API } from 'aws-amplify';
import { GraphQLQuery, GRAPHQL_AUTH_MODE } from '@aws-amplify/api';
import * as queries from './graphql/queries';
import { GetTodoQuery } from './API';

const todos = await API.graphql<GraphQLQuery<GetTodoQuery>>({
  query: queries.listTodos,
  authMode: GRAPHQL_AUTH_MODE.AWS_IAM
});
```

</Block>

<Block name="JavaScript">

```js
import { API } from 'aws-amplify';
import { GRAPHQL_AUTH_MODE } from '@aws-amplify/api';
import * as queries from './graphql/queries';


const todos = await API.graphql({
  query: queries.listTodos,
  authMode: GRAPHQL_AUTH_MODE.AWS_IAM
});
```

</Block>
</BlockSwitcher>

## Filtered and Paginated Queries

As your data grows, you will want to do pagination and filtering at the AppSync level instead of on the client. Fortunately, this is already built in to `API.graphql`, but you need to understand the schema of these queries. [This is explained in the AppSync docs](https://docs.aws.amazon.com/appsync/latest/devguide/using-your-api.html), but here you will translate them to the `API.graphql` equivalent.

You can find the input schemas in the Docs pane of the GraphQL explorer or inside your autogenerated `/graphql` folder. They look like this:

```graphql
listTodos(
  filter: ModelTodoFilterInput
  limit: Int
  nextToken: String): ModelTodoConnection

input ModelTodoFilterInput {
	id: ModelIDInput
	priority: ModelIntInput
	# ... all your other Todo fields here
	and: [ModelTodoFilterInput]
	or: [ModelTodoFilterInput]
	not: ModelTodoFilterInput
}
```

### Filtering Queries

Those input types in your schema indicate what kinds of filtering you can perform on them. For example, an integer field like `ModelIntInput` has this schema:

```graphql
input ModelIntInput {
  ne: Int # "not equal to"
  eq: Int # "equal to"
  le: Int # "less than or equal to"
  lt: Int # "less than"
  ge: Int # "greater than or equal to"
  gt: Int # "greater than"
  between: [Int]
  attributeExists: Boolean
  attributeType: ModelAttributeTypes
}
```

These vary based on the type of the field, but are linked to corresponding [DynamoDB queries](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html).

<BlockSwitcher>
<Block name="TypeScript">

```ts
import { ListTodosQueryVariables, ListTodosQuery } from './API';

const variables: ListTodosQueryVariables = {
  filter: {
    priority: {
      eq: 1
    }
  }
};

await API.graphql<GraphQLQuery<ListTodosQuery>>({ 
  query: listTodos, variables: variables 
});
```

</Block>

<Block name="JavaScript">

```js
const variables = {
  filter: {
    priority: {
      eq: 1
    }
  }
};

await API.graphql({ 
  query: listTodos, variables: variables 
});;
```

</Block>
</BlockSwitcher>

### Compound Filters

You can combine filters with `and`, `or`, and `not` boolean logic. Observe, in the autogenerated schema above, that `ModelTodoFilterInput` is recursive in respect to those fields. So if, for example, you wanted to filter for `priority` values of 1 OR 2, you would do this:

<BlockSwitcher>
<Block name="TypeScript">

```ts
import { ListTodosQueryVariables, ListTodosQuery } from './API';

const variables: ListTodosQueryVariables = {
  filter: {
    or: [
      { priority: { eq:1 } },
      { priority: { eq:2 } }
    ]
  }
};

await API.graphql<GraphQLQuery<ListTodosQuery>>({ 
  query: listTodos, variables: variables 
});
```

</Block>

<Block name="JavaScript">

```js
const variables = {
  filter: {
    or: [
      { priority: { eq:1 } },
      { priority: { eq:2 } }
    ]
  }
};

await API.graphql({ 
  query: listTodos, variables: variables 
});;
```

</Block>
</BlockSwitcher>

Note that querying for `priority` of 1 AND 2 would return no results, because this is boolean logic instead of natural language.

### Paginating Queries

Pagination in AppSync is done by making a request with a `limit`, and getting back a `nextToken` in order to get a cursor for the next page in your query:

<BlockSwitcher>
<Block name="TypeScript">

```ts
import { ListTodosQueryVariables, ListTodosQuery } from './API';

// Fetch first 20 records
const variables: ListTodosQueryVariables = {
  limit: 20, 
  // add filter as needed
};

const res = await API.graphql<GraphQLQuery<ListTodosQuery>({ 
  query: listTodos, variables: variables
});

const { items: itemsPage1, nextToken } = res.data?.listTodos;

// Fetch the next 20 records
variables.nextToken = nextToken;

const res = await API.graphql<GraphQLQuery<ListTodosQuery>({ 
  query: listTodos, variables: variables 
});

const { items: itemsPage2 } = res.data?.listTodos;
```

</Block>

<Block name="JavaScript">

```js
// Fetch first 20 records
const variables = {
  limit: 20, 
  // add filter as needed
};

const res = await API.graphql({ 
  query: listTodos, variables: variables
});

const { items: itemsPage1, nextToken } = res.data.listTodos;

// Fetch the next 20 records
variables.nextToken = nextToken;

const res = await API.graphql({ 
  query: listTodos, variables: variables
});

const { items: itemsPage2 } = res.data.listTodos;
```

</Block>
</BlockSwitcher>

A `nextToken` is a very long string that looks like `"eyJ2ZXJzaW9uejE1a2RPanZPQzFCMlFTdGNxdUFBQUJxekNDQWFjR0NTcUdTSWIzRFFFSEJxQ0NBWmd3Z2dHVUFnRUFNSUlCalFZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5eEtWQjUvTlJxS2o5ZHBYc0NBUkNBZ2dGZUZFNW1MbTRkb25BOUg0U0FpOGhSZ1lucmRndmQz"` which represents the cursor to the starting item of the next query made with these filters.

### Frequently Asked Questions

- There is no API to get a total page count at this time. Note that scanning all items is a [potentially expensive operation](https://github.com/aws-amplify/amplify-js/issues/2901).
- Sorting is [available in DataStore](https://docs.amplify.aws/lib/datastore/data-access/q/platform/js#predicates) but not in AppSync.
- AppSync schemas do not follow the edges/nodes of the [Relay spec](https://relay.dev/docs/guides/graphql-server-specification) but are spiritually similar.
- You [cannot query by `page` number](https://github.com/aws-amplify/amplify-cli/issues/5086), you have to query by `nextToken`.
