Skip to content

Commit 0e1c52e

Browse files
committed
feat: add auth measure
1 parent b2bfe3f commit 0e1c52e

File tree

4 files changed

+104
-79
lines changed

4 files changed

+104
-79
lines changed

Diff for: bun.lockb

3.9 KB
Binary file not shown.

Diff for: package.json

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@fastify/cors": "^9.0.1",
1818
"@fastify/formbody": "^7.4.0",
1919
"@fastify/helmet": "^11.1.1",
20+
"@fastify/jwt": "^8.0.1",
2021
"@fastify/postgres": "^5.2.2",
2122
"@fastify/rate-limit": "^9.1.0",
2223
"@fastify/swagger": "^8.14.0",

Diff for: routes.js

+91-79
Original file line numberDiff line numberDiff line change
@@ -55,93 +55,105 @@ export default async function registerRoutes(app) {
5555
);
5656
}
5757

58-
app.post("/books", async (request, reply) => {
59-
const { name, url } = request.body;
60-
if (!name || !url) {
61-
reply.status(400).send("Missing name or url");
62-
return;
63-
}
64-
const client = await app.pg.connect();
65-
try {
66-
const response = await client.query(
67-
"INSERT INTO books (name, url) VALUES ($1, $2) RETURNing *",
68-
[name, url],
69-
);
70-
reply.send(response.rows[0]);
71-
} catch (error) {
72-
reply.status(500).send(error);
73-
} finally {
74-
client.release();
75-
}
76-
});
77-
78-
app.delete("/books/:id", async (request, reply) => {
79-
const { id } = request.params; // Extract the ID from the request parameters.
80-
81-
// Assuming app.pg.connect() is your method to get a database client.
82-
const client = await app.pg.connect();
83-
try {
84-
// Execute a SQL query to delete the book by its ID.
85-
// Ensure your query is protected against SQL injection by using parameterized queries.
86-
const result = await client.query(
87-
"DELETE FROM books WHERE id = $1 RETURNING *", // Returns the deleted book details.
88-
[id],
89-
);
90-
91-
// If no rows are returned, the book with the given ID does not exist.
92-
if (result.rows.length === 0) {
93-
reply.status(404).send({ message: "Book not found" });
58+
app.post(
59+
"/books",
60+
{ preValidation: app.authenticate },
61+
async (request, reply) => {
62+
const { name, url } = request.body;
63+
if (!name || !url) {
64+
reply.status(400).send("Missing name or url");
9465
return;
9566
}
67+
const client = await app.pg.connect();
68+
try {
69+
const response = await client.query(
70+
"INSERT INTO books (name, url) VALUES ($1, $2) RETURNing *",
71+
[name, url],
72+
);
73+
reply.send(response.rows[0]);
74+
} catch (error) {
75+
reply.status(500).send(error);
76+
} finally {
77+
client.release();
78+
}
79+
},
80+
);
9681

97-
// Send back the details of the deleted book.
98-
reply.send(result.rows[0]);
99-
} catch (error) {
100-
// Handle any errors that occur during the database operation.
101-
reply.status(500).send(error);
102-
} finally {
103-
// Release the client back to the pool.
104-
client.release();
105-
}
106-
});
82+
app.delete(
83+
"/books/:id",
84+
{ preValidation: app.authenticate },
85+
async (request, reply) => {
86+
const { id } = request.params; // Extract the ID from the request parameters.
87+
88+
// Assuming app.pg.connect() is your method to get a database client.
89+
const client = await app.pg.connect();
90+
try {
91+
// Execute a SQL query to delete the book by its ID.
92+
// Ensure your query is protected against SQL injection by using parameterized queries.
93+
const result = await client.query(
94+
"DELETE FROM books WHERE id = $1 RETURNING *", // Returns the deleted book details.
95+
[id],
96+
);
10797

108-
app.put("/books/:id", async (request, reply) => {
109-
const { id } = request.params; // Extract the ID from the route parameters.
110-
const { name, url } = request.body; // Extract the updated name and url from the request body.
98+
// If no rows are returned, the book with the given ID does not exist.
99+
if (result.rows.length === 0) {
100+
reply.status(404).send({ message: "Book not found" });
101+
return;
102+
}
111103

112-
// Input validation (optional but recommended)
113-
if (!name || !url) {
114-
reply
115-
.status(400)
116-
.send({ message: "Missing name or url in request body." });
117-
return;
118-
}
104+
// Send back the details of the deleted book.
105+
reply.send(result.rows[0]);
106+
} catch (error) {
107+
// Handle any errors that occur during the database operation.
108+
reply.status(500).send(error);
109+
} finally {
110+
// Release the client back to the pool.
111+
client.release();
112+
}
113+
},
114+
);
119115

120-
const client = await app.pg.connect(); // Assuming app.pg.connect() is your method to get a database client.
121-
try {
122-
// Execute a SQL query to update the book by its ID.
123-
// Ensure your query is protected against SQL injection by using parameterized queries.
124-
const result = await client.query(
125-
"UPDATE books SET name = $1, url = $2 WHERE id = $3 RETURNING *", // Returns the updated book details.
126-
[name, url, id],
127-
);
116+
app.put(
117+
"/books/:id",
118+
{ preValidation: app.authenticate },
119+
async (request, reply) => {
120+
const { id } = request.params; // Extract the ID from the route parameters.
121+
const { name, url } = request.body; // Extract the updated name and url from the request body.
128122

129-
// If no rows are returned, the book with the given ID does not exist.
130-
if (result.rows.length === 0) {
131-
reply.status(404).send({ message: "Book not found" });
123+
// Input validation (optional but recommended)
124+
if (!name || !url) {
125+
reply
126+
.status(400)
127+
.send({ message: "Missing name or url in request body." });
132128
return;
133129
}
134130

135-
// Send back the details of the updated book.
136-
reply.send(result.rows[0]);
137-
} catch (error) {
138-
// Handle any errors that occur during the database operation.
139-
reply
140-
.status(500)
141-
.send({ error: "An error occurred while updating the book." });
142-
} finally {
143-
// Release the client back to the pool.
144-
client.release();
145-
}
146-
});
131+
const client = await app.pg.connect(); // Assuming app.pg.connect() is your method to get a database client.
132+
try {
133+
// Execute a SQL query to update the book by its ID.
134+
// Ensure your query is protected against SQL injection by using parameterized queries.
135+
const result = await client.query(
136+
"UPDATE books SET name = $1, url = $2 WHERE id = $3 RETURNING *", // Returns the updated book details.
137+
[name, url, id],
138+
);
139+
140+
// If no rows are returned, the book with the given ID does not exist.
141+
if (result.rows.length === 0) {
142+
reply.status(404).send({ message: "Book not found" });
143+
return;
144+
}
145+
146+
// Send back the details of the updated book.
147+
reply.send(result.rows[0]);
148+
} catch (error) {
149+
// Handle any errors that occur during the database operation.
150+
reply
151+
.status(500)
152+
.send({ error: "An error occurred while updating the book." });
153+
} finally {
154+
// Release the client back to the pool.
155+
client.release();
156+
}
157+
},
158+
);
147159
}

Diff for: server.js

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import compress from "@fastify/compress";
22
import cors from "@fastify/cors";
33
import formbody from "@fastify/formbody";
44
import helmet from "@fastify/helmet";
5+
import jwt from "@fastify/jwt";
56
import postgres from "@fastify/postgres";
67
import rateLimit from "@fastify/rate-limit";
78
import swagger from "@fastify/swagger";
@@ -38,6 +39,17 @@ await app.register(compress, { encodings: ["gzip"] });
3839
await app.register(cors);
3940
await app.register(formbody);
4041
await app.register(helmet);
42+
await app.register(jwt, {
43+
secret: process.env.JWT_SECRET,
44+
})
45+
app.decorate("authenticate", async (request, reply) => {
46+
try {
47+
await request.jwtVerify();
48+
} catch (err) {
49+
reply.send(err);
50+
}
51+
});
52+
4153
await app.register(rateLimit, {
4254
max: 100,
4355
timeWindow: "1 minute",

0 commit comments

Comments
 (0)