Built by

perseidesjs

Category

Other

Version

1.0.1

Last updated

Jun 24, 2024, 18:38:13 PM3 months ago

@perseidesjs/medusa-plugin-rate-limit

Website
|
Medusa

A simple rate-limit plugin for Medusa.

Installation

npm install @perseidesjs/medusa-plugin-rate-limit

Usage

This plugin uses Redis under the hood, this plugin will also work in a development environment thanks to the fake Redis instance created by Medusa, remember to use Redis in production, by just passing the Copy to clipboardredis_url option to the Copy to clipboardmedusa-config.js > projectConfig object.

Plugin configuration

You need to add the plugin to your Medusa configuration before you can use the rate limitting service. To do this, import the plugin as follows:
const plugins = [
`medusa-fulfillment-manual`,
`medusa-payment-manual`,
`@perseidesjs/medusa-plugin-rate-limit`,
]
You can also override the default configuration by passing an object to the plugin as follows:
const plugins = [
`medusa-fulfillment-manual`,
`medusa-payment-manual`,
{
resolve: `@perseidesjs/medusa-plugin-rate-limit`,
/** @type {import('@perseidesjs/medusa-plugin-rate-limit').PluginOptions} */
options: {
limit: 5,
window: 60,
},
},
]

Default configuration


OptionTypeDefaultDescription
limitCopy to clipboardNumberCopy to clipboard5The number of requests allowed in the given time window
windowCopy to clipboardNumberCopy to clipboard60The time window in seconds

How to use

If you want to start restricting certain routes, you can resolve the Copy to clipboardRateLimitService from the Medusa container, and then create middleware as shown below :
// src/middlewares/rate-limit.ts
import { type MedusaRequest, type MedusaResponse } from '@medusajs/medusa'
import type { NextFunction } from 'express'
import type { RateLimitService } from '@perseidesjs/medusa-plugin-rate-limit'
/**
* A simple rate limiter middleware based on the RateLimitService
* @param limit {number} - Number of requests allowed per window
* @param window {number} - Number of seconds to wait before allowing requests again
* @returns
*/
export default async function rateLimit(
req: MedusaRequest,
res: MedusaResponse,
next: NextFunction,
) {
try {
// 1️⃣ We resolve the RateLimitService from the container
const rateLimitService = req.scope.resolve<RateLimitService>('rateLimitService')
// 2️⃣ We create a key for the current request based on the IP address for example
const key = req.ip
const rateLimitKey = `rate_limit:${key}`
const allowed = await rateLimitService.limit(rateLimitKey)
// 3️⃣ If the request is not allowed, we return a 429 status code and a JSON response with an error message
if (!allowed) {
const retryAfter = await rateLimitService.ttl(rateLimitKey)
res.set('Retry-After', String(retryAfter))
res
.status(429)
.json({ error: 'Too many requests, please try again later.' })
return
}
// 4️⃣ Otherwise, we can continue, below I'm getting the remaining attempts for the current key for example
const remaining = await rateLimitService.getRemainingAttempts(rateLimitKey)
res.set('X-RateLimit-Limit', String(rateLimitService.getOptions().limit))
res.set('X-RateLimit-Remaining', String(remaining))
next()
} catch (error) {
next(error)
}
}
And then use it in your Copy to clipboardsrc/api/middlewares.ts file as follows:
import { MiddlewaresConfig } from '@medusajs/medusa'
import rateLimit from './middlewares/rate-limit'
export const config: MiddlewaresConfig = {
routes: [
{
// This will limit the number of requests to 5 per 60 seconds on the auth route
matcher: '/store/auth',
middlewares: [rateLimit],
},
],
}

More information

You can find the Copy to clipboardRateLimitService class in the src/services/rate-limit.ts file.

License

This project is licensed under the MIT License - see the LICENSE file for details

Build your own plugins

Develop your own plugins with our API to speed up your processes.

Make your plugin available via npm for it to be shared in our Plugin Library with the broader Medusa community.