## 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`:
```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>(
{ 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' }
});
```
```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' }
});
```
You can optionally import the `graphqlOperation` helper function to help you construct this argument object:
```ts
import { API, graphqlOperation } from 'aws-amplify';
import { GraphQLQuery } from '@aws-amplify/api';
import { GetTodoQuery } from './API';
// ...
const oneTodo = await API.graphql>(
graphqlOperation(queries.getTodo, { id: 'some id' })
);
```
```js
import { API, graphqlOperation } from 'aws-amplify';
// ...
const oneTodo = await API.graphql(
graphqlOperation(queries.getTodo, { id: 'some id' })
);
```
### 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
```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>({
query: queries.listTodos,
authMode: GRAPHQL_AUTH_MODE.AWS_IAM
});
```
```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
});
```
## 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).
```ts
import { ListTodosQueryVariables, ListTodosQuery } from './API';
const variables: ListTodosQueryVariables = {
filter: {
priority: {
eq: 1
}
}
};
await API.graphql>({
query: listTodos, variables: variables
});
```
```js
const variables = {
filter: {
priority: {
eq: 1
}
}
};
await API.graphql({
query: listTodos, variables: variables
});;
```
### 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:
```ts
import { ListTodosQueryVariables, ListTodosQuery } from './API';
const variables: ListTodosQueryVariables = {
filter: {
or: [
{ priority: { eq:1 } },
{ priority: { eq:2 } }
]
}
};
await API.graphql>({
query: listTodos, variables: variables
});
```
```js
const variables = {
filter: {
or: [
{ priority: { eq:1 } },
{ priority: { eq:2 } }
]
}
};
await API.graphql({
query: listTodos, variables: variables
});;
```
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:
```ts
import { ListTodosQueryVariables, ListTodosQuery } from './API';
// Fetch first 20 records
const variables: ListTodosQueryVariables = {
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;
```
```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;
```
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`.