-
My intent is to add a ratelimiter to a next.js 14 app and though i could make a plugin which runs before executing any graphql and adds headers with some information about the ratelimiting. my code is as follows: import { redis } from "@/server/redis";
import { Plugin } from "graphql-yoga";
import { RateLimiterRedis } from "rate-limiter-flexible";
const maxRequestsPerMinute = 100;
const rateLimiter = new RateLimiterRedis({
storeClient: redis,
keyPrefix: "rl:",
points: maxRequestsPerMinute,
duration: 60, // 60 seconds
});
export function rateLimiterplugin(): Plugin {
return {
onRequest: async ({ request, requestHandler, fetchAPI, endResponse, }) => {
try {
const ip = request.headers.get("host") || "127.0.0.1";
const { msBeforeNext, remainingPoints, consumedPoints } =
await rateLimiter.consume(ip);
const headers = new Headers(request.headers);
headers.append("Retry-After", (msBeforeNext / 1000).toString());
headers.append("X-RateLimit-Limit", consumedPoints.toString());
headers.append("X-RateLimit-Remaining", remainingPoints.toString());
headers.append(
"X-RateLimit-Reset",
(Date.now() + msBeforeNext).toString()
);
const response = await requestHandler(request, {});
endResponse({
...response,
headers: {
...response.headers,
...headers,
},
});
} catch (err) {
console.log(err);
const url = new URL("/", request.url);
endResponse(
new fetchAPI.Response(null, {
status: 429,
headers: {
"Content-Type": "application/json",
},
})
);
}
},
};
} the error that i got is the following:
Which also made me wonder if the api's from next.js are available on the context/request object passed in the |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
First, the code above forwards request headers to the response directly. Please be careful with that. Second it doesn't work and you get Third, please never call the request handler manually like that inside hooks because it will break the entire lifecycle of Yoga. If you want to change the headers of the response, please use If you want to pass the data between hooks, you can use const fooByRequest = new WeakMap<Request, string>();
const plugin = {
onRequest({ request }) {
fooByRequest.set(request, 'foo');
},
onResponse({ request, response }) {
const fooFromRequest = fooByRequest.get(request); // foo
}
} |
Beta Was this translation helpful? Give feedback.
First, the code above forwards request headers to the response directly. Please be careful with that.
Second it doesn't work and you get
Ensure you return a 'Response' or a 'NextResponse' in all branches of your handler.
because the object lost itsResponse
prototype when you use a spread like...response
so instead you can modify the headers ofresponse
object like;response.headers.set('x-my-header', 'my-header-value')
Third, please never call the request handler manually like that inside hooks because it will break the entire lifecycle of Yoga. If you want to change the headers of the response, please use
onResponse
hook to modifyresponse.headers
.If you want to pass the data between …