Building a visit counter with Redis and React
Tags: redis, nextjs, react, database
Published: 2021-04-17 03:55:54

Redis as a database is huge overestimated these days. It is commonly used for caching systems but on its own is a very powerful database. It can be used as an alternative of a Firebase storage, even for a Mongodb too.

At this time I will show you how we can get advantage about his speed and data structure for craft a visit counter component.

## Setting Up the Redis database

We have to create an account in [Redis Labs](https://redislabs.com/try-free/) to start to configure the Redis database on the cloud.

Why did I choose Redis Labs?

- They are responsible for the development of Redis so it's normal that they have the best tooling and latest update of this database motor.
- 300MB storage to use without any cost. That is more than enough for what we need to use.
- 99,999% uptime, that it's crazy!
- Millisecond data processing.

When we have created the account, the next thing is to setup the Redis Cloud instance as a new subscription in your account. You can check [this video](https://www.youtube.com/watch?v=I9sPna1OOUg) for more details.

After you have ready the database, you need to go to the config tab and copy the Endpoint and Password values.

## Connecting to Redis instance from a serverless backend

We need now a npm library to work as a client between Redis and our app. I used ioredis library because it has async functions and the feature of sending multiple commands at the same time, that we'll see later. So the first thing is create a file with the basic setup to connect to our Redis instance.
`lib/redis.js`
```javascript
const redis = require("ioredis");

function Redis() {
  const conn = {
    port: process.env.REDIS_PORT,
    host: process.env.REDIS_URL,
    password: process.env.REDIS_PSW
  }
  return new redis(conn);
}

export default Redis;
```


## Exposing an api service

Now, we have to define the api route with his logic for store and retrieve the numbers of users who visit a specific page. I'll use Next so we are going to create the following file.
`pages/api/views/[slug].js`
```javascript
import client from 'lib/redis';
const redis = client();

export default async (req, res) => {
  const redis = client();
  const forwarded = req.headers['x-forwarded-for'];
  const ip = forwarded ? forwarded.split(/, /)[0] : req.connection.remoteAddress;
  let members = [];
  await redis
    .pipeline()
    .sadd(req.query.slug, ip)
    .smembers(req.query.slug)
    .exec((err, results) => {
      members = results[1][1];
    });
  redis.quit();
  const n = members.length;
  return res.status(200).json({
    total: n
  });
};
```

From the above, we can see a few things:

- `/api/views/:slug` — it'll we the API URL expose to our frontend. It returns the number of unique users who visited a specific URL (slug).
- We get the IP client to save it as a unique id and sum a visit on that page.
- We are using a pipeline function to send multiple commands to Redis in only one transaction.
- Redis has [multiple commands](https://redis.io/commands) to manipulate the data. 
We are using SADD to have a list of unique IPs for each page and not repeat the visit for each time that that user comes back to that page. And to retrieve the list we are using smembers.
- The IP list from a specific page is saving in the variable members when we call the function exec.
- Finally, we count the list of IPs from that page to know how many users visited it and return that number.

## Building the React component

The last thing is coding the component that will fetch the data and hit the visit number.
`PageviewsCounter.js`
```javascript
import useSWR from 'swr';
import { fetcher } from '@/lib/utils';

export default function PageviewsCounter({ slug }) {
  const { data } = useSWR(`/api/views/${slug}`, fetcher);
  const views = data?.total;

  if(views)
    return `${views} views`;
  return <><span className="line-through">999</span> views</>
}
```

As we can see, the component receives the slug of the page as a prop and it is using [SWR library](https://swr.vercel.app/) to improve the speed and cache for the fetch of the data.

## Conclusion 

So we had learned how in a few easy steps we can build a visit counter and save that data in our own backend as a Redis storage without depending on external services like Analytics. 

Also we did get advantage of commands like SADD where in a native way it supports creating a list of non repeatable values to save the ip's of the users who visit each page.

You can see working this component in [this site](https://agustinmaggi.com/), in the right corner below the headline of each post.