Enhancing CodeStash with Unkey’s Ratelimiter

Devansh Baghel - Oct 11 - - Dev Community

Recently, I made a platform called CodeStash that allows developers to upload, store, and share code snippets. It combines the best of Reddit and Stack Overflow with features like voting, commenting, and AI-driven code explanations.

I am getting these AI generated code explanations from Google Gemini 1.5 flash that only allows me to make 15 requests per minute in the free tier (not a problem for my zero user app), but I still thought it would be pretty neat if I could implement a basic level of rate-limiting on that specific route.

In this blog post, I'll show you how to add rate-limiting to your express app using Unkey's ratelimiter.

Overview of the AI feature

User goes to the post that they want the AI explanation of (Bubble sort in Java snippet in this case) and clicks the "Explain this" button.

Post on CodeStash about bubble sort in java

Then a request is made to the backend endpoint /api/v1/ai/explain and the controller that handles that request looks something like:

export const getAiAnswer = asyncHandler(async (req: UserRequest, res) => {
  const { postId } = req.query;

  if (!postId) return new ApiError(400, "Post id is required to get comments");

  const post = await Post.findById(postId);

  if (!post) throw new ApiError(404, "Post with this id does not exist");

  const apiKey = process.env.GEMINI_API_KEY!;
  const genAI = new GoogleGenerativeAI(apiKey);

  const model = genAI.getGenerativeModel({
    model: "gemini-1.5-flash",
  });

  const generationConfig = {
    temperature: 1,
    topP: 0.95,
    topK: 64,
    maxOutputTokens: 8192,
    responseMimeType: "text/plain",
  };

  const chatSession = model.startChat({
    generationConfig,
    // safetySettings: Adjust safety settings
    // See https://ai.google.dev/gemini-api/docs/safety-settings
    history: [],
  });

  const prompt = `I am providing you a code snippet, please explain me this code snippet, only give small and consice explanation, only give answers in valid markdown format, make sure to use markdown format extensively, if possible use indenting in the markdown in bullet points etc. The code snippet is: ${post.content}`;

  const result = await chatSession.sendMessage(prompt);
  const aiAnswer = result.response.text();

  return res
    .status(200)
    .json(new ApiResponse(200, { aiAnswer }, "AI answer sent successfully"));
});
Enter fullscreen mode Exit fullscreen mode

And this endpoint then sends a response which we display to the user.

AI explanation of the post on CodeStash about bubble sort in java

Integrating Unkey's ratelimiter

First we need to install @unkey/ratelimit package.

pnpm add @unkey/ratelimit
Enter fullscreen mode Exit fullscreen mode

Then we need to set our root key.

UNKEY_ROOT_KEY="YOUR_KEY"
Enter fullscreen mode Exit fullscreen mode

Then create a new file utils/ratelimit.ts.

import { Ratelimit } from "@unkey/ratelimit";

if (!process.env.UNKEY_ROOT_KEY) {
  throw new Error("UNKEY_ROOT_KEY is not set");
}

export const limiter = new Ratelimit({
  namespace: "codestash",
  limit: 10,
  duration: "60s",
  rootKey: process.env.UNKEY_ROOT_KEY,
});
Enter fullscreen mode Exit fullscreen mode

Replace the namespace, limit and duration with whatever you want.

Now all we need to do is add these 3 lines into any endpoint that you want to be ratelimited.

const identifier = req.ip;

const ratelimit = await limiter.limit(identifier);
if (!ratelimit.success) throw new ApiError(429, "Too many requests");
Enter fullscreen mode Exit fullscreen mode

So in my case I added it to /api/v1/ai/explain.

export const getAiAnswer = asyncHandler(async (req: UserRequest, res) => {
  const { postId } = req.query;
  const identifier = req.ip;

  const ratelimit = await limiter.limit(identifier);
  if (!ratelimit.success) throw new ApiError(429, "Too many requests");

  if (!postId) return new ApiError(400, "Post id is required to get comments");

  const post = await Post.findById(postId);

  if (!post) throw new ApiError(404, "Post with this id does not exist");

  const apiKey = process.env.GEMINI_API_KEY!;
  const genAI = new GoogleGenerativeAI(apiKey);

  const model = genAI.getGenerativeModel({
    model: "gemini-1.5-flash",
  });

  const generationConfig = {
    temperature: 1,
    topP: 0.95,
    topK: 64,
    maxOutputTokens: 8192,
    responseMimeType: "text/plain",
  };

  const chatSession = model.startChat({
    generationConfig,
    // safetySettings: Adjust safety settings
    // See https://ai.google.dev/gemini-api/docs/safety-settings
    history: [],
  });

  const prompt = `I am providing you a code snippet, please explain me this code snippet, only give small and consice explanation, only give answers in valid markdown format, make sure to use markdown format extensively, if possible use indenting in the markdown in bullet points etc. The code snippet is: ${post.content}`;

  const result = await chatSession.sendMessage(prompt);
  const aiAnswer = result.response.text();

  return res
    .status(200)
    .json(new ApiResponse(200, { aiAnswer }, "AI answer sent successfully"));
});
Enter fullscreen mode Exit fullscreen mode

And done, That's it! We have successfully added rate-limiting to our express API.


Thanks for reading! I hope this post gave you insight into how you can leverage Unkey’s ratelimiter to enhance your own applications.

For more information on Unkey, visit their official website.

Also leave a star on CodeStash's github repo if you like the project.

.
Terabox Video Player