- Tejaya's Blog
- Posts
- 🎉 Build a New Year Resolutions Tracker with Node.js and Redis
🎉 Build a New Year Resolutions Tracker with Node.js and Redis
Happy New Year, tejaya.tech readers! 🎉 The New Year is a time for fresh starts, and many of us set resolutions to make the coming year even better. But how do you keep track of those resolutions and stay on top of them?
In this tutorial, we’ll build a New Year Resolutions Tracker API using Node.js, Redis, and queues to handle high user traffic and ensure fast, reliable performance. By the end, you’ll have a scalable backend service that lets users add, view, and check off their resolutions efficiently.
What We’ll Build
Our API will support:
Adding a resolution: Users can add their resolutions.
Viewing all resolutions: Retrieve a user’s list of resolutions.
Marking a resolution as complete: Users can update the status of a resolution.
Caching and queuing: Use Redis to store resolutions and handle tasks efficiently.
Step 1: Setting Up the Project
Start by initializing a new Node.js project and installing the required dependencies.
mkdir resolutions-tracker
cd resolutions-tracker
npm init -y
npm install express redis bull uuid
Step 2: Designing the API
Let’s design the API endpoints for managing resolutions:
POST /resolutions
: Add a new resolution.GET /resolutions
: View all resolutions.PATCH /resolutions/
🆔 Mark a resolution as complete.
Code Implementation
Here’s how we can implement the backend, index.js:
const express = require('express');
const redis = require('redis');
const { v4: uuidv4 } = require('uuid');
const Queue = require('bull');
const app = express();
app.use(express.json());
// Redis client
const redisClient = redis.createClient();
redisClient.on('error', (err) => console.error('Redis Error:', err));
// Queue for background tasks
const resolutionQueue = new Queue('resolutionQueue');
// Endpoint to add a new resolution
app.post('/resolutions', async (req, res) => {
const { userId, resolution } = req.body;
if (!userId || !resolution) {
return res.status(400).send('Missing userId or resolution');
}
const resolutionId = uuidv4();
const newResolution = {
id: resolutionId,
resolution,
completed: false,
};
// Add resolution to Redis
redisClient.rpush(`resolutions:${userId}`, JSON.stringify(newResolution), (err) => {
if (err) return res.status(500).send('Error adding resolution');
res.status(201).json({ message: 'Resolution added', resolution: newResolution });
});
});
// Endpoint to view all resolutions
app.get('/resolutions/:userId', async (req, res) => {
const { userId } = req.params;
// Check if cached resolutions exist
redisClient.lrange(`resolutions:${userId}`, 0, -1, (err, resolutions) => {
if (err) return res.status(500).send('Error fetching resolutions');
if (resolutions.length === 0) {
return res.status(404).send('No resolutions found');
}
// Parse and return the resolutions
const parsedResolutions = resolutions.map((r) => JSON.parse(r));
res.json(parsedResolutions);
});
});
// Endpoint to mark a resolution as complete
app.patch('/resolutions/:userId/:resolutionId', async (req, res) => {
const { userId, resolutionId } = req.params;
// Fetch all resolutions
redisClient.lrange(`resolutions:${userId}`, 0, -1, (err, resolutions) => {
if (err) return res.status(500).send('Error fetching resolutions');
// Find and update the specific resolution
const updatedResolutions = resolutions.map((r) => {
const resolution = JSON.parse(r);
if (resolution.id === resolutionId) {
resolution.completed = true;
}
return JSON.stringify(resolution);
});
// Save the updated resolutions back to Redis
redisClient.del(`resolutions:${userId}`, (err) => {
if (err) return res.status(500).send('Error updating resolutions');
redisClient.rpush(`resolutions:${userId}`, updatedResolutions, (err) => {
if (err) return res.status(500).send('Error saving updated resolutions');
res.json({ message: 'Resolution marked as complete' });
});
});
});
});
// Process background queue tasks
resolutionQueue.process(async (job, done) => {
console.log('Processing job:', job.data);
// Here, you could send reminders or analytics
done();
});
// Add background job example
app.post('/reminder', async (req, res) => {
const { userId, message } = req.body;
await resolutionQueue.add({ userId, message });
res.json({ message: 'Reminder added to the queue' });
});
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
Step 3: Testing the API
Here’s how you can test the API using tools like Postman or cURL:
Add a resolution:
curl -X POST http://localhost:3000/resolutions \
-H "Content-Type: application/json" \
-d '{"userId": "user1", "resolution": "Learn Node.js"}'
View all resolutions:
curl http://localhost:3000/resolutions/user1
Mark a resolution as complete:
curl -X PATCH http://localhost:3000/resolutions/user1/<resolutionId>
Conclusion
New Year is a great time to explore fresh ideas and projects. 🎉 This resolutions tracker is not just a fun exercise but a foundation for building real-world scalable systems. You can extend this project by:
Adding a React frontend for a user-friendly interface.
Implementing notification systems to remind users of incomplete resolutions.
Analyzing user habits to improve goal-setting strategies.
Here’s to a productive and fulfilling New Year! 🚀
Reply