Recentemente me deparei com o seguinte cenário no Onigiri Hardcore. Como posso mostrar para patrocinadores ou até mesmo para gestão de evento que o portal de notícias é um possível sucesso e que posso me cadastrar como imprensa ou algo do tipo? Sem depender de Analytics, sem depender de serviços prontos.
Para quem não sabe, o Onigiri Hardcore é um portal de notícias e já participou de diversos eventos em Campinas como imprensa, fazendo cobertura sobre o evento e tudo mais. Só que evoluímos de lá para cá e começamos a nos tornar independentes.
E como a gente faz essa métrica?
Existem diversas soluções para fazermos isso, como o Onigiri Hardcore utiliza de markdown - assim como esse blog - para criar as notícias, não temos um banco de dados. Então não faria sentido criar um banco só para isso. Mas, caso tivesse, era só criar uma collection ou referenciar e fazer o mesmo esquema, mas ao invés de ser uma publicação, só adicionaria +1 no banco utilizando um campo de visualizações ou algo do tipo.
Podemos utilizar do Github API para fazermos alterações no README, sempre que alguém acessar a página.
Podemos utilizar de outras APIs ou até mesmo APIs próprias para isso.
E uma das alternativas que me chegou é, utilize o Redis.
Eu já trabalhei com ele anteriormente em um projeto da Rocketseat, assim como já vi vários exemplos utilizando ele para fazer estilo de contador sem ficar sobrecarregando banco de dados e coisas do tipo, e eu pensei. Porque não?
Como usar o Redis para contar acessos em páginas estáticas
Inicialmente, se você não tiver um projeto em Next.js, crie um novo.
npx create-next-app@latest visit-counter
cd visit-counter
Por exemplo.
Instale o Redis nele e instale também - de forma global - a CLI do Redis - no caso, estou usando Ubuntu, então verifique a documentação oficial para entender como funciona a instalação no seu dispositivo.
npm install redis
sudo apt update
sudo apt install redis-server
sudo systemctl enable redis-server.service
sudo systemctl start redis-server.service
CLI instalada, Next configurado, vamos começar. Antes, de tudo, você também pode utilizar o Redis Insight para conseguir visualizar através de uma interface gráfica, o seu banco de dados.
Caso você não queira, você pode utilizar o Redis CLI, e executar o seguinte comando:
redis-cli
E em seguida para visualizar as informações em nosso cenário
get totalVisits
hgetall monthlyVisits
Vamos criar a conexão com o Redis em src/lib/redis.js
import { createClient } from 'redis';
const client = createClient({
url: process.env.REDIS_URL || 'redis://localhost:6379'
});
client.on('error', (err) => {
console.error('Redis client not connected to the server:', err);
});
client.on('connect', () => {
console.log('Redis client connected to the server');
});
client.connect();
export default client;
Depois, vamos criar uma Rota de API para registrar as visitas em pages/api/visit.js
import client from '../../src/lib/redis';
export default async function handler(req, res) {
if (req.method === 'POST') {
try {
// Garantir que o cliente está conectado
if (!client.isOpen) {
await client.connect();
}
const now = new Date();
const yearMonth = `${now.getFullYear()}-${now.getMonth() + 1}`;
await client.incr('totalVisits');
await client.hIncrBy('monthlyVisits', yearMonth, 1);
console.log('Visit recorded');
res.status(200).json({ message: 'Visit recorded' });
} catch (error) {
console.error('Error recording visit', error);
res.status(500).json({ message: 'Internal Server Error' });
}
} else {
res.setHeader('Allow', ['POST']);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}
E em seguida, vamos criar a rota para obter as contagens de visitas em pages/api/visits.js
import redisClient from '../../src/lib/redis';
export default async function handler(req, res) {
if (req.method === 'GET') {
const totalVisits = await redisClient.get('totalVisits');
const monthlyVisits = await redisClient.hGetAll('monthlyVisits');
res.status(200).json({ totalVisits, monthlyVisits });
} else {
res.setHeader('Allow', ['GET']);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}
E após isso, registrar as visitas em pages/_app.js
para isso rodar independente da página
que for acessada.
import React, { useEffect } from 'react';
import '../styles/globals.css'
// eslint-disable-next-line react/prop-types
function MyApp({ Component, pageProps }) {
useEffect(() => {
fetch('/api/visit', {
method: 'POST',
});
}, []);
return (
<>
<Component {...pageProps} />
</>
)
}
export default MyApp
Bacana, não é mesmo? Dessa maneira, conseguimos ter as seguintes informações, por enquanto.
- Total de visitas realizadas naquele mês
- Total de visitas realizadas separadas por mês.
Claro que existe alguns problemas ainda e otimizações a serem feitas, mas essa é apenas a ponta do iceberg para você ter noção do que é o Redis e sua funncionalidade.
Que tipos de situações temos que adicionar ainda? Por exemplo, a cada F5, a atualização sobe e eu não gostaria que isso acontecesse, pois o usuário pode simplesmente ficar apertando F5 várias e várias vezes para ganhar visualização e isso não é o ideal.
Assim como também queremos filtrar qual é a página em que o usuário está acessando, seria bacana, não é mesmo? Saber que em determinada página tem X acessos e na outra Y e assim por diante. São algumas costumizações a serem feitas.
E como faço para rodar esse projeto?
Inicialmente, suba o projeto na Vercel com a sua conta cadastrada e configure seu ambiente de desenvolvimento para receber as variáveis de ambiente como:
REDIS_URL=redis://your_redis_cloud_url
Em seguida, crie uma conta no Redis Cloud e configura sua nova instância gratuita para conseguir ter
acesso e registro no banco em que cadastramos. Pegue a URL
da instância e grave no seu .env.local
dentro do REDIS_URL
.
Essas adaptações ainda irão ser alterada para o cenário do Onigiri Hardcore, aonde você pode estar acompanhando através do repositório oficial do Github. Caso queira ajudar, fique à vontade para criar uma pull request e mandar sua alteração/sugestão.
Se tiver com alguma dúvida ou dificuldade, não hesite em me chamar no X/Twitter.
Obrigado por ler até aqui!