Pagination in AdonisJS

AdonisJS provides a standard way to handle pagination and query only a pre-defined number of records in your query result.

A typical controller without any pagination looks like the below -

// TodoController.js
const Todo = use("App/Models/Todo");

class TodoController {
  async index({ request, response, view }) {
    return await Todo.query().fetch();
  }
}

The index method outlined in the code block just queries all records and returns everything to caller.

This is good as long as you have limited set of records within your database. If the to do records are in hundreds, thousands or more, you have a problem on your hand.

  • Bad user experience - hundreds of records are not of much help without a good way to filter everything
  • Performance issues - limit records retrieved from database and share controlled data sets instead of unlimited records

Pagination limits the number of records fetched from database.

// TodoController.js
const Todo = use("App/Models/Todo");

class TodoController {
  async index({ request, response, view }) {
    let { page } = request.all();
    page = page ? page : 1;
    return await TodoQuery.paginate(page ? page : 1, 10);
  }
}

As compared to the previous example, the changes are simple -

  1. Retrieve a page parameter value from URL. This is requested by the caller (and passed as-is to the controller as part of the request). Caller can include a specific page
  2. If page is not found, set page to 1. This is just a precautionary measure
  3. Use paginate() instead of using fetch. Paginate fetches exactly 10 records in the specified page

Client will call the below URL -

GET http://localhost:3333/todo?page=1

Output -

{
  "total": 2,
  "perPage": 10,
  "page": 1,
  "lastPage": 1,
  "data": [
    {
      "description": "Create Adonis Todo App",
      "date": "2019-01-01",
      "status": "Done",
      "created_at": "2019-01-01 12:46:09",
      "updated_at": "2019-01-01 12:46:09"
    }
    {
      "description": "Update Todo App",
      "date": "2019-01-01",
      "status": "In Progress",
      "created_at": "2019-01-01 12:52:01",
      "updated_at": "2019-01-01 12:52:01"
    }
  ]
}

You can see the difference in structure as compared to a normal fetch (as seen before).

The client has to be designed to consume the above pagination data, and based on user action, send specific page numbers to receive the specific set of 10 records.

How pagination works?

The entire data set in todos table is virtually divided into pages.

<number of pages> = <total records> / <records per page>

When the client requests for a specific page, Adonis (specifically the ORM) will send a query to the database that says -

  1. Get me the first 10 records - if page is not defined / or given as 1
  2. For a specific page requested by client (say p): skip the first (p - 1) * 10 and return the next 10 records

This may seem too many things to do to accomplish a simple use case, but you hardly notice it once you start writing programs in the real world.

comments powered by Disqus