-
Notifications
You must be signed in to change notification settings - Fork 10
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
Fastify adapter #1076
Comments
Logging that we've had a user request for NestJS + Fastify. |
We had another request for Fastify. |
@davidmytton The Fastify Request object is not the same as the Node.js request object. They stash the Node.js request object on |
It didn't show as a type error when I tried this code, so this may not work properly with sensitive info detection then. |
You will rarely get a type error by stuffing different types of requests into the node adapter because we define the request type ourselves: interface ArcjetNodeRequest {
headers?: Record<string, string | string[] | undefined>;
socket?: Partial<{ remoteAddress: string; encrypted: boolean }>;
method?: string;
httpVersion?: string;
url?: string;
// Things needed for getting a body
body?: unknown;
on?: EventHandlerLike;
removeListener?: EventHandlerLike;
readable?: boolean;
} You'll notice that all the fields in the type are partial, which means the only type errors you will see are if the object you are passing in shares nothing in common or if a field conflicts, but not if some of these fields are missing. We define this ourselves because we don't want to be coupled to 1 version of the In addition to not knowing how body will be handled, the most significant thing here is that |
We had another request for this in Discord so I created an example that manually pulls the IP from the headers and tested it on Fly: // ESM
import Fastify from "fastify";
import ip from "@arcjet/ip";
const fastify = Fastify({
logger: true,
});
import arcjet, { detectBot, shield, tokenBucket } from "@arcjet/node";
const aj = arcjet({
key: process.env.ARCJET_KEY!, // Get your site key from https://app.arcjet.com
characteristics: ["ip.src"], // Track requests by IP
rules: [
// Shield protects your app from common attacks e.g. SQL injection
shield({ mode: "LIVE" }),
// Create a bot detection rule
detectBot({
mode: "LIVE", // Blocks requests. Use "DRY_RUN" to log only
// Block all bots except search engine crawlers. See
// https://arcjet.com/bot-list
allow: ["CATEGORY:SEARCH_ENGINE"],
}),
// Create a token bucket rate limit. Other algorithms are supported.
tokenBucket({
mode: "LIVE",
refillRate: 5, // Refill 5 tokens per interval
interval: 10, // Refill every 10 seconds
capacity: 10, // Bucket capacity of 10 tokens
}),
],
});
fastify.get("/", async (request, reply) => {
// Use the Arcjet utility package to extract the client IP address
// Installed with `npm install @arcjet/ip`
// Import with `import ip from "@arcjet/ip";`
// @ts-ignore
const clientIP = ip(request, request.headers);
// Construct a request object to send to Arcjet with the required fields
// until https://github.com/arcjet/arcjet-js/issues/1076 is resolved
const arcjetRequest = {
ip: clientIP,
method: request.method,
host: request.hostname,
url: request.url,
headers: request.headers,
};
console.log("Arcjet request", arcjetRequest);
const decision = await aj.protect(arcjetRequest, { requested: 5 }); // Deduct 5 tokens from the bucket
//console.log("Arcjet decision", decision);
if (decision.isDenied()) {
if (decision.reason.isRateLimit()) {
reply.code(429).send({ error: "Too many requests" });
} else if (decision.reason.isBot()) {
reply.code(403).send({ error: "No bots allowed" });
} else {
reply.code(403).send({ error: "Forbidden" });
}
}
return { hello: "world" };
});
/**
* Run the server!
*/
const start = async () => {
try {
await fastify.listen({ host: "0.0.0.0", port: 3000 });
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start(); {
"name": "fastify",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"dev": "npx tsx --env-file .env.local index.ts"
},
"author": "",
"type": "module",
"description": "",
"dependencies": {
"@arcjet/ip": "^1.0.0-alpha.28",
"@arcjet/node": "^1.0.0-alpha.28",
"fastify": "^5.1.0"
},
"devDependencies": {
"@types/node": "^22.9.0"
}
} |
@davidmytton I believe that usage of |
Ah, we missed updating the readme then: Line 40 in 44c1e8e
|
Good catch. I'll do that for today's release. |
We should create a fastify adapter.
One thing I noticed that would be cool is that fastify has an official plugin for generating swagger for your API, which we could convert to a postman collection and test the requests against an API.
The text was updated successfully, but these errors were encountered: