Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add function to manually check rate limit (#346) #392

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

Charioteer
Copy link

@Charioteer Charioteer commented Nov 10, 2024

Hey fastify contributors,

Following on from issue #346 and my comment, I finally had some spare time to implement a draft version of my idea as suggested by @mcollina. I realized that any store (child) instance receives all the options provided to fastify.rateLimit when it is constructed, which is why I had to adjust my initial idea and come up with a slightly different solution.

I did not provide any documentation or additional tests yet (all existing tests run green tho), because I wanted to ask for your feedback first.

Please let me know what you think and as soon as everything looks good to you, I will finalize my PR with proper docs and tests.

Thanks and cheers
Patrick

How to Use

import Fastify from "fastify";
import { fastifyRateLimit } from "@fastify/rate-limit";

const fastify = Fastify();

await fastify.register(fastifyRateLimit, {
  global: false,
  max: 10,
  timeWindow: "10 seconds",
});

const checkRateLimit = fastify.createRateLimit(); // this will use the global options provided to fastifyRateLimit

fastify.get("/", async (request, reply) => {
  const limit = await checkRateLimit(request);

  if(!limit.isAllowed && limit.isExceeded) {
    return reply.code(429).send("Limit exceeded");
  }

  return reply.send("Hello world");
});


const checkCustomRateLimit = fastify.createRateLimit({ max: 100 }); // max provided to override global options

fastify.get("/custom", async (request, reply) => {
  const limit = await checkCustomRateLimit(request);

  if(!limit.isAllowed && limit.isExceeded) {
    return reply.code(429).send("Limit exceeded");
  }

  return reply.send("Hello world");
});

Checklist

@Fdawgs Fdawgs requested a review from Copilot November 20, 2024 19:40
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 2 out of 2 changed files in this pull request and generated no suggestions.

Comments skipped due to low confidence (3)

index.js:285

  • The variable timeWindowString is only assigned a value if params.timeWindow is a number. Ensure it is always defined or handle the undefined case properly.
timeWindowString = ms.format(params.timeWindow, true)

index.js:193

  • [nitpick] The function name createLimiterArgs is ambiguous. Consider renaming it to generateLimiterArguments for better clarity.
function createLimiterArgs (pluginComponent, globalParams, options) {

index.js:216

  • Ensure that the new behavior introduced by the applyRateLimit function is covered by tests.
async function applyRateLimit (pluginComponent, params, req) {

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Finish it up (be careful that CI is failing).

@Charioteer Charioteer marked this pull request as ready for review February 3, 2025 22:07
@Charioteer
Copy link
Author

Hi @mcollina,

after @umakantp has closed their PR #410 because of the "authorship problem", I thought of putting more pressure on myself to finally get this done. I added unit tests, type tests, as well as documentation about the usage of this feature. I also merged the latest commit of fastify-rate-limit to my fork already to avoid conflicts. LMKWYT.

At this point, I also would like to appreciate @umakantp again for continuing this PR and putting time and effort into it. Please excuse me if I caused any trouble on your side.

@umakantp
Copy link

Hi @mcollina If you can please take a look and merge if things are good?

@Charioteer Charioteer requested a review from mcollina February 18, 2025 22:21
@gurgunday
Copy link
Member

It looks interesting, I'll take a look at this tomorrow

Copy link
Member

@Eomm Eomm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically this change is awesome!

A minor suggestion, but LGTM!

if (!fastify.hasDecorator('createRateLimit')) {
fastify.decorate('createRateLimit', (options) => {
const args = createLimiterArgs(pluginComponent, globalParams, options)
return (req) => applyRateLimit(...args, req)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of decostruct args we can:

Suggested change
return (req) => applyRateLimit(...args, req)
return (req) => applyRateLimit.apply(this, args.concat(req))

(and even better, avoid the concat

Copy link
Member

@gurgunday gurgunday left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you run a benchmark using the basic example in the examples folder with autocannon?

https://github.com/fastify/fastify-rate-limit/blob/main/example/example-simple.mjs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants