Skip to content

digicroz/node-backend-utils

Repository files navigation

@digicroz/node-backend-utils

Backend utilities for Node.js applications with TypeScript support. This package provides robust, production-ready utilities for common backend operations.

Features

  • 🚀 Redis Client Wrapper - Simplified Redis operations with automatic connection management
  • 🔒 Type-Safe - Full TypeScript support with comprehensive type definitions
  • 🌳 Tree-Shakeable - Import only what you need
  • 📦 ESM & CommonJS - Supports both module systems
  • Production Ready - Battle-tested utilities with graceful error handling

Installation

npm install @digicroz/node-backend-utils

Redis Utilities

Quick Start

import { redisBase, createRedisClient } from "@digicroz/node-backend-utils"

// Initialize Redis connection
await redisBase.initialize()

// Create a client with namespace prefix
const userCache = createRedisClient("user", true)

// Use the client
await userCache.set("john", "John Doe")
const user = await userCache.get("john")

Redis Base Client

The base singleton Redis client with automatic connection management:

import { redisBase } from "@digicroz/node-backend-utils/redis"

// Initialize (call once at app startup)
await redisBase.initialize()

// Check connection status
const isConnected = redisBase.isClientConnected()

// Get client for advanced operations
const client = redisBase.getClient()

// Safe execution with error handling
const result = await redisBase.safeExecute(async (client) => {
  return await client.get("mykey")
})

// Disconnect when shutting down
await redisBase.disconnect()

Environment Variables:

  • REDIS_URL - Redis connection URL (e.g., redis://localhost:6379)

Redis Generic Client

A feature-rich Redis client with namespace prefixing and type-safe object storage:

import { createRedisClient } from "@digicroz/node-backend-utils/redis"

// Create a namespaced client
const cache = createRedisClient("myapp", true)

// String operations
await cache.set("key", "value")
await cache.setEx("key", 3600, "value") // with expiration
const value = await cache.get("key")

// Object operations (automatic JSON serialization)
await cache.setObj("user:1", { name: "John", age: 30 })
await cache.setObjEx("user:2", 3600, { name: "Jane", age: 25 })
const user = await cache.getObj<User>("user:1")

// Key operations
await cache.del("key")
await cache.delMultiple(["key1", "key2"])
await cache.exists("key")
await cache.expire("key", 3600)
await cache.ttl("key")

// Counter operations
await cache.incr("counter")
await cache.incrBy("counter", 5)
await cache.decr("counter")

// Pattern matching
const keys = await cache.keys("user:*")

// Hash operations
await cache.hSet("hash", "field", "value")
await cache.hGet("hash", "field")
await cache.hGetAll("hash")
await cache.hDel("hash", "field")

// List operations
await cache.lPush("list", "item1", "item2")
await cache.rPush("list", "item3")
await cache.lPop("list")
await cache.rPop("list")
await cache.lRange("list", 0, -1)

// Set operations
await cache.sAdd("set", "member1", "member2")
await cache.sMembers("set")
await cache.sRem("set", "member1")

// Custom operations with prefix support
const result = await cache.safeExecute(async (client, addPrefix) => {
  const key = addPrefix("mykey")
  return await client.get(key)
})

Features:

  • ✅ Automatic namespace prefixing
  • ✅ Object serialization/deserialization
  • ✅ Graceful error handling (returns null on errors)
  • ✅ Enable/disable without code changes
  • ✅ Full TypeScript support

Usage Examples

Basic Setup

// app.ts
import { redisBase } from "@digicroz/node-backend-utils"

async function startServer() {
  // Initialize Redis at startup
  await redisBase.initialize()

  // Your app initialization...
}

startServer()

User Session Cache

import { createRedisClient } from "@digicroz/node-backend-utils"

const sessionCache = createRedisClient("session", true)

interface Session {
  userId: string
  email: string
  loginTime: number
}

// Store session with 1 hour expiration
async function createSession(sessionId: string, userId: string, email: string) {
  const session: Session = {
    userId,
    email,
    loginTime: Date.now(),
  }
  await sessionCache.setObjEx(sessionId, 3600, session)
}

// Get session
async function getSession(sessionId: string) {
  return await sessionCache.getObj<Session>(sessionId)
}

Rate Limiting

import { createRedisClient } from "@digicroz/node-backend-utils"

const rateLimitCache = createRedisClient("ratelimit", true)

async function checkRateLimit(userId: string, maxRequests: number = 100) {
  const key = `${userId}:requests`
  const count = await rateLimitCache.incr(key)

  if (count === 1) {
    // First request, set expiration to 1 minute
    await rateLimitCache.expire(key, 60)
  }

  return count && count <= maxRequests
}

Feature Flags

import { createRedisClient } from "@digicroz/node-backend-utils"

const featureFlags = createRedisClient("feature", true)

interface FeatureFlag {
  enabled: boolean
  rolloutPercentage: number
  enabledUsers?: string[]
}

async function isFeatureEnabled(featureName: string, userId: string) {
  const flag = await featureFlags.getObj<FeatureFlag>(featureName)

  if (!flag || !flag.enabled) return false

  if (flag.enabledUsers?.includes(userId)) return true

  // Implement percentage-based rollout
  const hash = userId
    .split("")
    .reduce((acc, char) => acc + char.charCodeAt(0), 0)
  return hash % 100 < flag.rolloutPercentage
}

API Reference

redisBase

  • initialize() - Initialize Redis connection
  • getClient() - Get the raw Redis client
  • isClientConnected() - Check connection status
  • disconnect() - Close the connection
  • safeExecute(operation) - Execute operation with error handling
  • getStatus() - Get connection status details

createRedisClient(prefix, isEnabled)

Creates a new Redis client instance with the given prefix.

Parameters:

  • prefix - Namespace prefix for all keys
  • isEnabled - Enable/disable Redis operations (default: true)

Returns: RedisGenericClient instance

RedisGenericClient Methods

All methods return null if the client is disabled or on error.

String Operations

  • set(key, value) - Set a string value
  • setEx(key, seconds, value) - Set with expiration
  • get(key) - Get a string value

Object Operations

  • setObj<T>(key, value) - Set an object (auto-serialized)
  • setObjEx<T>(key, seconds, value) - Set object with expiration
  • getObj<T>(key) - Get an object (auto-deserialized)

Key Operations

  • del(key) - Delete a key
  • delMultiple(keys) - Delete multiple keys
  • exists(key) - Check if key exists
  • expire(key, seconds) - Set expiration
  • ttl(key) - Get time to live
  • keys(pattern) - Find keys by pattern

Counter Operations

  • incr(key) - Increment by 1
  • incrBy(key, amount) - Increment by amount
  • decr(key) - Decrement by 1

Hash Operations

  • hSet(key, field, value) - Set hash field
  • hGet(key, field) - Get hash field
  • hGetAll(key) - Get all hash fields
  • hDel(key, fields) - Delete hash fields

List Operations

  • lPush(key, ...elements) - Push to left
  • rPush(key, ...elements) - Push to right
  • lPop(key) - Pop from left
  • rPop(key) - Pop from right
  • lRange(key, start, stop) - Get range

Set Operations

  • sAdd(key, ...members) - Add members
  • sMembers(key) - Get all members
  • sRem(key, ...members) - Remove members

Environment Variables

REDIS_URL=redis://localhost:6379

Best Practices

  1. Initialize Once - Call redisBase.initialize() at application startup
  2. Use Prefixes - Use meaningful prefixes to organize your keys
  3. Set Expirations - Always set TTL for cache data
  4. Handle Nulls - All methods can return null, always check results
  5. Graceful Degradation - The client is designed to fail gracefully

License

MIT

Author

Adarsh Hatkar - GitHub

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published