Build and Deploy a GraphQL API to the Edge with MySQL and PlanetScale — Part 9
Add cursor-based pagination to the fetch all products query
Fetching everything from the database once it grows will become very expensive and add unnecessary load to your backend. Let's instead explore adding cursor-based pagination to the products
query.
We'll first update the products
query to accept multiple arguments;
first
last
before
after
We can use these arguments to fetch the first
or last
X
records before
or after
an entry. The value of first
and last
will be the ID of the record.
g.query('products', {
args: {
first: g.int().optional(),
last: g.int().optional(),
before: g.string().optional(),
after: g.string().optional()
},
resolver: 'products/all',
returns: g.ref(product).optional().list().optional()
})
Next, we will update the ProductsAll
function to destructure first
, last
, before
and after
from the args and execute the applicable SQL statement depending on what combination of arguments are passed to the query.
import { connect } from '@planetscale/database'
import { GraphQLError } from 'graphql'
import { config, options } from '../../lib'
const conn = connect(config)
export default async function ProductsAll(_, { first, last, before, after }) {
try {
let results
if (first !== undefined && after !== undefined) {
results = await conn.execute(
'SELECT * FROM products WHERE id > ? ORDER BY id ASC LIMIT ?',
[after, first],
options
)
} else if (last !== undefined && before !== undefined) {
results = await conn.execute(
`SELECT * FROM (
SELECT * FROM products WHERE id < ? ORDER BY id DESC LIMIT ?
) AS sub ORDER BY id ASC`,
[before, last],
options
)
} else if (first !== undefined) {
results = await conn.execute(
'SELECT * FROM products ORDER BY id ASC LIMIT ?',
[first],
options
)
} else if (last !== undefined) {
results = await conn.execute(
`SELECT * FROM (
SELECT * FROM products ORDER BY id DESC LIMIT ?
) AS sub ORDER BY id ASC`,
[last],
options
)
} else {
throw new GraphQLError(
'You must provide one of the following arguments: first, last, (first and after), or (last and before)'
)
}
return results?.rows || []
} catch (error) {
console.log(error)
return []
}
}
Give it a try! You will now need to pass the argument first
when querying for products
:
{
products(first: 5) {
id
name
slug
price
onSale
}
}
Update the query to fetch the first
5 products after the ID 2
:
{
products(first: 5, after: "2") {
id
name
slug
price
onSale
}
}
That's it! We've successfully built a GraphQL API using MySQL and PlanetScale.