1
votes

I apologize if this question is documented already, please point me to those resources.

I have a nodejs app making an api call to Untappd and per most public APIs, I'm restricted to a max number of items returned in the call, in this case 50 is the max. I'd like to set up the pagination using Offset (Skip) so that I could move through the 600+ items instead of just the 50.

What Works I currently have the pagination working to view the first 50 items through these different pieces...

API call on server.js

const untappdAPI = { method: 'GET',
url: 'https://api.untappd.com/v4/user/beers/username',
  qs: 
   { access_token: 'abc123'
    ,limit:'50'
     }    
  };

app.get with pagination on server.js

app.get('/untappd', function (req, res) {
  try {
    request(untappdAPI, function (error, response, body) {
        if (error) throw new Error(error);
        const untappdBeers = JSON.parse(body);
        const utBeerList = untappdBeers.response.beers.items.map(item => item );
//pagination
const perPage = 5;
let currentPage = 1;
const totalBeerList = utBeerList.length;
const pageCount = Math.ceil(totalBeerList / perPage);

if(req.query.page) {
  currentPage = parseInt(req.query.page, 10);
}
const start = (currentPage - 1) * perPage;
const end = currentPage * perPage;
        res.render('untappd.ejs', {
          utBeerList:utBeerList.slice(start, end),
          perPage: perPage,
          pageCount: pageCount,
          currentPage: currentPage,
        });
    });   
  } catch(e) {
    console.log("Something went wrong", e)
  }
  });

And then the items render on a page called untappd.ejs and the working pagination is provided with this code

EJS Client Pagination on untappd.ejs

<div id="pagination">
<% if (pageCount > 1) { %>
    <ul class="pagination">
        <% if (currentPage > 1) { %>
            <li><a href="?page=1">&laquo;</a></li>
        <% } %>
        <% var i = 1;
        if (currentPage > 5) {
            i = +currentPage - 4;
        } %>
        <% if (i !== 1) { %>
            <li><a href="#">...</a></li>
        <% } %>
        <% for (i; i<=pageCount; i++) { %>
            <% if (currentPage == i) { %>
                <li class="active"><span><%= i %> <span class="sr-only">(current)</span></span></li>
            <% } else { %>
                <li><a href="?page=<%= i %>"><%= i %></a></li>
            <% } %>

            <% if (i == (+currentPage + 4)) { %>
                <li><a href="#">...</a></li>
            <% break; } %>
        <% } %>
        <% if (currentPage != pageCount) { %>
            <li><a href="?page=<%= pageCount %>">&raquo;</a></li>
        <% } %>
    </ul>
<% } %>
</div>

Again, the above code is all well and good, I get functioning pagination with 5 items per page and 10 pages to paginate through, but I am limited to these 50 items. From what I've read about offset, it seems offset would allow me to cycle through the entire set of 600+ items, but I can't find documentation/help that fits this particular scenario.

How do I incorporate 'offset' into what I'm working with in order to paginate through the full list of 600+ items?

Many thanks for your help!

Red

1
but the documentation says you can pass parameters such as offset and limit... if you want to get the beers from 0 to 50 then offset: 0, limit: 50 if you want from 51 to 100, then offset: 50, limit: 50, and so on... why aren't you passing that info to the query? and why the .map(item => item)? makes no sense 🤔 – balexandre

1 Answers

0
votes

The documentation is quite straight forward (UNLESS you are trying something else... but I'm assuming /v4/search/beer), all you need to do is use the offset and limit that the API provides, that would work like:

offset (int, optional) - The numeric offset that you what results to start
limit (int, optional) - The number of results to return, max of 50, default is 25

this means that

  • if you want to search beers from 0 to 50, set: offset: 0, limit: 50
  • if you want to search beers from 51 to 100, set offset: 50, limit: 50
  • if you want to search beers from 101 to 150, set offset: 100, limit: 50

I would change your code as:

const untappdAPI = (name, currentPage, perPage) => ({ method: 'GET',
  url: 'https://api.untappd.com/v4/search/beer',
  qs: { 
    q: name,
    access_token: 'abc123',
    limit: perPage, // 50
    offset: currentPage * perPage  // 0*50 = 0 | 1*50 = 50 | 2*50 = 100
  }    
})

having that as a function, will allow you to simply pass parameters such as

app.get('/untappd', function(req, res) {

  const { search, currentPage, perPage } = req.query
  const url = untappdAPI(search, currentPage, perPage) // (currentPage - 1) if you start with 1

  try {
    request(url, (error, response, body) => {
      if (error) throw new Error(error)

      const apiRes = JSON.parse(body).response
      const beers = apiRes.beers.items
      const total = apiRes.found // outputs in the API, first item in the response

      res.render('untappd.ejs', {
        utBeerList: beers,
        perPage: perPage,
        pageCount: Math.ceil(total / perPage),
        currentPage: currentPage,
      })
    })
  } catch (err) {
    console.log("Something went wrong", err.message)
  }
});

The only thing left to do, is update the HTML, as you can see from the call, we need 3 parameters (you can make some static and do not give the user the option to change, for example, items per page, and always display 50 at a time...

<a href="?page=<%= pageCount %>&currentPage=<%= currentPage %>&perPage=50">&raquo;</a>

Note

in your code, you are outputting const pageCount = Math.ceil(totalBeerList / perPage); but the API response gives you the total items that can be retrieved in the first item in the documentation response as the found variable


P.S. I've request access to the API to verify if all this works, I will update the answer soon I have a client id and a secret