Skip to content

Commit 3160e5d

Browse files
Merge pull request #199 from HackYourFuture-CPH/58-backend-nodejs-week2
[Backend] NodeJS - week 2
2 parents 9f16703 + 49fae84 commit 3160e5d

File tree

19 files changed

+2763
-57
lines changed

19 files changed

+2763
-57
lines changed

SUMMARY.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,25 @@
135135
- [Session Plan](courses/backend/databases/week2/session-plan.md)
136136
- [Assignment](courses/backend/databases/week2/assignment.md)
137137
- [Node](courses/backend/node/README.md)
138+
- [Week 1](courses/backend/node/week1/README.md)
139+
- [Session Materials](courses/backend/node/week1/session-materials/)
140+
- [1. Server](courses/backend/node/week1/session-materials/01-server.md)
141+
- [2. Schema](courses/backend/node/week1/session-materials/02-schema.md)
142+
- [3. Routing](courses/backend/node/week1/session-materials/03-routing.md)
143+
- [4. Database connection](courses/backend/node/week1/session-materials/04-database-connection.md)
144+
- [5. GET endpoints](courses/backend/node/week1/session-materials/05-get-endpoints.md)
145+
- [6. Auth](courses/backend/node/week1/session-materials/06-auth.md)
146+
- [Preparation](courses/backend/node/week1/preparation.md)
147+
- [Session Plan](courses/backend/node/week1/session-plan.md)
148+
- [Assignment](courses/backend/node/week1/assignment.md)
149+
- [Week 2](courses/backend/node/week2/README.md)
150+
- [Session Materials](courses/backend/node/week2/session-materials/)
151+
- [7. POST endpoints](courses/backend/node/week2/session-materials/07-post-endpoint.md)
152+
- [8. PUT endpoints](courses/backend/node/week2/session-materials/08-put-endpoint.md)
153+
- [9. DELETE endpoints](courses/backend/node/week2/session-materials/09-delete-endpoint.md)
154+
- [Preparation](courses/backend/node/week2/preparation.md)
155+
- [Session Plan](courses/backend/node/week2/session-plan.md)
156+
- [Assignment](courses/backend/node/week2/assignment.md)
138157
- [Final Backend Project](courses/backend/final-project/README.md)
139158

140159
- [Common Modules](shared-modules/README.md)

courses/backend/node/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ This module is part of the Backend specialism and focuses on using Node.js to bu
44

55
## Contents
66

7-
| Week | Topic | Preparation | Lesson Plan | Assignment |
8-
| ---- | ------------------------ | ----------------------------------- | ----------------------------------- | ------------------------------------- |
9-
| 1. | Express | [Preparation](week1/preparation.md) | [Assignment](./week1/assignment.md) | [Session plan](week1/session-plan.md) |
10-
| 2. | Database connection; API | [Preparation](week2/preparation.md) | [Assignment](./week1/assignment.md) | [Session plan](week2/session-plan.md) |
7+
| Week | Topic | Preparation | Session Plan | Assignment |
8+
| ---- | ------------------------ | ------------------------------------- | ----------------------------------------------------- | ----------------------------------- |
9+
| 1. | Express | [Preparation](./week1/preparation.md) | [Session plan](./week1/session-plan.md) (for mentors) | [Assignment](./week1/assignment.md) |
10+
| 2. | Database connection; API | [Preparation](./week2/preparation.md) | [Session plan](./week2/session-plan.md) (for mentors) | [Assignment](./week1/assignment.md) |
1111

1212
## Module Learning Goals
1313

@@ -16,6 +16,6 @@ By the end of this module, you will be able to:
1616
- [ ] Build web servers with Express.js
1717
- [ ] Design and implement APIs using HTTP methods following REST principles
1818
- [ ] Use middlewares for authentication, logging, and validation
19-
- [ ] Test APIs using Postman
2019
- [ ] Use logging and debugging tools to monitor and troubleshoot applications
2120
- [ ] Connect to databases and implement CRUD operations
21+
- [ ] Test APIs using Postman

courses/backend/node/week1/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ In this session we will focus on Express.js, which is an application framework f
1313
By the end of this session, you will be able to:
1414

1515
- [ ] Explain what Express is and describe why it is used for building backend applications.
16-
- [ ] Implement routing in Express to handle different HTTP requests and endpoints.
16+
- [ ] Implement routing in Express to handle `GET` HTTP requests, endpoints and parameters.
1717
- [ ] Use logging and debugging tools to monitor and troubleshoot Node.js applications.
1818
- [ ] Apply middleware functions in Express to process requests and responses.
19-
- [ ] Use Postman to test and debug APIs you have built.
19+
- [ ] Understand the importance of Authentication and various methods for implementing it.

courses/backend/node/week1/session-materials/06-auth.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,4 @@ It is left as an optional exercise to add the following routes:
116116
- `PUT /api/snippets/:id` to update a snippet
117117
- `DELETE /api/snippets/:id` to delete a snippet
118118

119-
Also, it could be a good idea to deny the request if the user making the request is not confirmed
119+
Also, it could be a good idea to deny the request if the user making the request is not confirmed.

courses/backend/node/week1/session-plan.md

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
11
# Session plan
22

3-
## Session Outline
4-
5-
- Express
6-
- What is Express (10 mins)
7-
- [Live coding: setup a server](./session-materials/01-server.md)
8-
- [Excercise: create a local project and database schema](./session-materials/02-schema.md)
9-
- Routing in Express (20 mins)
10-
- `app.use`
11-
- `app.get`
12-
- [Live coding: routing](#appget-vs-appuse)
13-
- [Excercise: Setup routing](./session-materials/03-routing.md) (10 mins)
14-
- URL parameters in Express (30 mins)
15-
- [Explanation and live coding](#query-parameters-vs-url-parameters)
16-
- [Excercise: connect to the database](./session-materials/04-database-connection.md)
17-
- [Excercise: GET endpoints](./session-materials/05-get-endpoints.md)
18-
- Route order (15 mins)
19-
- [Live coding: why route order matters](#route-order)
20-
- Logging and debugging
21-
- Middleware (15 mins)
22-
- [`next` method](https://expressjs.com/en/guide/using-middleware.html)
23-
- Modifying `request` and `response`
24-
- <https://fullstackopen.com/en/part3/node_js_and_express#express>
25-
- [Live coding: basic middleware example](#middleware)
26-
- Authentication (30 mins)
27-
- [Authentication explanation](#authentication-explanation)
28-
- [Excercise: implement authentication](./session-materials/06-auth.md)
3+
## Session outline
4+
5+
- What is Express (10 mins)
6+
- [Live coding: setup a server](./session-materials/01-server.md)
7+
- [Excercise: create a local project and database schema](./session-materials/02-schema.md)
8+
- Routing in Express (20 mins)
9+
- `app.use`
10+
- `app.get`
11+
- [Live coding: routing](#appget-vs-appuse)
12+
- [Excercise: Setup routing](./session-materials/03-routing.md) (10 mins)
13+
- URL parameters in Express (30 mins)
14+
- [Explanation and live coding](#query-parameters-vs-url-parameters)
15+
- [Excercise: connect to the database](./session-materials/04-database-connection.md)
16+
- [Excercise: GET endpoints](./session-materials/05-get-endpoints.md)
17+
- Route order (15 mins)
18+
- [Live coding: why route order matters](#route-order)
19+
- Logging and debugging
20+
- Middleware (15 mins)
21+
- [`next` method](https://expressjs.com/en/guide/using-middleware.html)
22+
- Modifying `request` and `response`
23+
- <https://fullstackopen.com/en/part3/node_js_and_express#express>
24+
- [Live coding: basic middleware example](#middleware)
25+
- Authentication (30 mins)
26+
- [Authentication explanation](#authentication-explanation)
27+
- [Excercise: implement authentication](./session-materials/06-auth.md)
2928

3029
## Exercises
3130

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Node (Week 2)
2+
3+
In this session we will focus on connecting to a database, building an API, and using Postman to test our API endpoints. We will also cover how to structure our code for better maintainability and scalability.
4+
5+
## Contents
6+
7+
- [Preparation](./preparation.md)
8+
- [Session Plan](./session-plan.md) (for mentors)
9+
- [Assignment](./assignment.md)
10+
11+
## Session Learning goals
12+
13+
By the end of this session, you will be able to:
14+
15+
- [ ] Manage advanced database interactions in your service
16+
- [ ] Understand what Knex is and why to use it
17+
- [ ] Set up connections to your database using Knex
18+
- [ ] Execute `select`, `create`, `delete` and `update` queries using Knex Query Builder
19+
- [ ] Implement all REST endpoints using Express
20+
- [ ] `POST`, `DELETE`, `PUT`
21+
- [ ] Use appropriate error handling to understand and debug issues
22+
- [ ] Configure Postman for advanced backend development
23+
- [ ] Creating collections and saving requests
24+
- [ ] Set up multiple environments
25+
- [ ] Managing secrets
26+
- [ ] Create basic test suites
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# Assignment
2+
3+
You'll set up and work with your own version of a simple Contacts API.
4+
5+
It will start with one endpoint (and you will add more throughout the task):
6+
7+
- `GET /api/contacts`
8+
9+
This endpoint accepts a query parameter `sort`. Here's how it should be possible to use it:
10+
11+
- `GET /api/contacts?sort=first_name%20ASC`
12+
- Sorts contacts by first name, ascending
13+
- `GET /api/contacts?sort=last_name%20DESC`
14+
- Sorts contacts by last name, descending
15+
16+
## Setup
17+
18+
1. Go to/create a `node/week2` directory in your `hyf-assignment` repo.
19+
2. Create yourself a new node application
20+
3. Create a database called `phonebook` with a `contacts` table, with the following schema and data:
21+
22+
```sql
23+
CREATE TABLE `contacts` (
24+
`id` int unsigned NOT NULL AUTO_INCREMENT,
25+
`first_name` varchar(255) NOT NULL,
26+
`last_name` varchar(255) NOT NULL,
27+
`email` varchar(255) DEFAULT NULL,
28+
`phone` varchar(255) DEFAULT NULL,
29+
PRIMARY KEY (`id`)
30+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
31+
32+
-- Sample data
33+
insert into contacts (id, first_name, last_name, email, phone) values (1, 'Selig', 'Matussov', '[email protected]', '176-630-4577');
34+
insert into contacts (id, first_name, last_name, email, phone) values (2, 'Kenny', 'Yerrington', null, null);
35+
insert into contacts (id, first_name, last_name, email, phone) values (3, 'Emilie', 'Gaitskell', null, null);
36+
insert into contacts (id, first_name, last_name, email, phone) values (4, 'Jordon', 'Tokell', null, null);
37+
insert into contacts (id, first_name, last_name, email, phone) values (5, 'Sallyann', 'Persse', '[email protected]', '219-157-2368');
38+
insert into contacts (id, first_name, last_name, email, phone) values (6, 'Berri', 'Bulter', null, null);
39+
insert into contacts (id, first_name, last_name, email, phone) values (7, 'Lanni', 'Ivanilov', '[email protected]', null);
40+
insert into contacts (id, first_name, last_name, email, phone) values (8, 'Dagny', 'Milnthorpe', null, null);
41+
insert into contacts (id, first_name, last_name, email, phone) values (9, 'Annadiane', 'Bansal', null, null);
42+
insert into contacts (id, first_name, last_name, email, phone) values (10, 'Tawsha', 'Hackley', null, null);
43+
insert into contacts (id, first_name, last_name, email, phone) values (11, 'Rubetta', 'Ozelton', null, null);
44+
insert into contacts (id, first_name, last_name, email, phone) values (12, 'Charles', 'Boughey', '[email protected]', '605-358-5664');
45+
insert into contacts (id, first_name, last_name, email, phone) values (13, 'Shantee', 'Robbe', null, null);
46+
insert into contacts (id, first_name, last_name, email, phone) values (14, 'Gleda', 'Peat', null, null);
47+
insert into contacts (id, first_name, last_name, email, phone) values (15, 'Arlinda', 'Ethersey', '[email protected]', '916-139-1300');
48+
insert into contacts (id, first_name, last_name, email, phone) values (16, 'Armando', 'Meachem', '[email protected]', '631-442-5339');
49+
insert into contacts (id, first_name, last_name, email, phone) values (17, 'Codi', 'Redhouse', null, '401-953-6897');
50+
insert into contacts (id, first_name, last_name, email, phone) values (18, 'Ann', 'Buncombe', '[email protected]', '210-338-0748');
51+
insert into contacts (id, first_name, last_name, email, phone) values (19, 'Louis', 'Matzkaitis', '[email protected]', '583-996-6979');
52+
insert into contacts (id, first_name, last_name, email, phone) values (20, 'Jessey', 'Pala', null, null);
53+
insert into contacts (id, first_name, last_name, email, phone) values (21, 'Archy', 'Scipsey', '[email protected]', '420-983-2426');
54+
insert into contacts (id, first_name, last_name, email, phone) values (22, 'Benoit', 'Mould', '[email protected]', '271-217-9218');
55+
insert into contacts (id, first_name, last_name, email, phone) values (23, 'Sherm', 'Girardey', '[email protected]', '916-999-2957');
56+
insert into contacts (id, first_name, last_name, email, phone) values (24, 'Raquel', 'Mudge', '[email protected]', '789-830-7473');
57+
insert into contacts (id, first_name, last_name, email, phone) values (25, 'Tabor', 'Reavey', null, null);
58+
```
59+
60+
4. Set up Express and an Sqlite connection in your node application. In your knex instance, make sure to set: `multipleStatements: true` - this is important!
61+
62+
5. Make sure you have an API router under the `/api` path set up like so:
63+
64+
```js
65+
app.use("/api", apiRouter);
66+
```
67+
68+
6. Create a contacts router at `/contacts`, and attach it to your API router.
69+
7. In your contacts API, create the following endpoint:
70+
71+
```js
72+
contactsAPIRouter.get("/", async (req, res) => {
73+
let query = knexInstance.select("*").from("contacts");
74+
75+
if ("sort" in req.query) {
76+
const orderBy = req.query.sort.toString();
77+
if (orderBy.length > 0) {
78+
query = query.orderByRaw(orderBy);
79+
}
80+
}
81+
82+
console.log("SQL", query.toSQL().sql);
83+
84+
try {
85+
const data = await query;
86+
res.json({ data });
87+
} catch (e) {
88+
console.error(e);
89+
res.status(500).json({ error: "Internal server error" });
90+
}
91+
});
92+
```
93+
94+
## The tasks
95+
96+
### Task 1 - Solve the SQL injection
97+
98+
The current implementation of the `sort` query parameter has introduced an SQL injection vulnerability.
99+
100+
First, you should demonstrate the SQL injection and that, for instance, it is possible to drop/delete the `contacts` table with the `sort` query parameter. Capture this demonstration with a screen recording, and attach it to your PR when you submit your assignment.
101+
102+
After having demonstrated the SQL injection vulnerability, your task is then to fix the issue. Your solution should be solved in the `app.js` file only. While the the `multipleStatements: true` configuration you used enables this vulnerability, it should not be changed in your solution.
103+
104+
### Task 2 - Improve your API
105+
106+
Create two additional endpoints to enable the following functionality:
107+
108+
1. Create new contacts
109+
2. Delete an existing contact
110+
111+
### Task 3 - Error handling
112+
113+
Update your endpoints with appropriate error handling. You should, at least, handle the following cases:
114+
115+
1. Successful requests
116+
2. Incorrect requests (e.g. an incorrectly formatted sort request)
117+
3. Server issues (e.g. a missing database table, or an offline database)
118+
4. A catch all for any other errors
119+
120+
Remember to:
121+
122+
1. Return the appropriate HTTP code
123+
2. Avoid sending any implementation or internal data to the client
124+
3. Log an appropriate message so you can debug issues that occur in your service
125+
126+
### Task 3 - Postman
127+
128+
1. Create a Postman collection to capture some example requests with your new API.
129+
2. Create a basic test suite that you can run to validate that everything is working correctly.
130+
131+
Share both a link to your Collection and a link to a test run showing your tests passing in your pull request.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Preparation
2+
3+
- [NodeJS Web API with KNEX and Express](https://www.youtube.com/watch?v=QNw9q4YXR4E) (15 min)
4+
- <https://fullstackopen.com/en/part3/node_js_and_express#rest> up until the `The Visual Studio Code REST client` section (15 min)
5+
- Familiarise yourself with the [Knex Cheatsheet](https://devhints.io/knex) (especially Select, Scheme and Modifying sections)
6+
- <https://jsonplaceholder.typicode.com/> - Free API for testing and prototyping. (5 min)

courses/backend/node/week2/session-materials/04-post-endpoint.md renamed to courses/backend/node/week2/session-materials/07-post-endpoint.md

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,20 @@
1-
# API
1+
# POST endpoint
22

33
## `POST /api/snippets`
44

55
Let's start with a simplified version of the `POST /api/snippets` route. First we add the POST route to `api/snippets.js`:
66

77
```js
8-
// Contents of api/snippets.js
9-
10-
import express from "express";
11-
import knex from "../database.js";
12-
13-
const router = express.Router();
14-
15-
// GET /api/snippets
16-
router.get("/", async (request, response) => {
17-
// TODO
18-
});
8+
// ...
199

2010
// POST /api/snippets
2111
router.post("/", async (request, response) => {
2212
// TODO
2313
});
2414

25-
// TODO: GET /api/snippets/:id
26-
27-
export default router;
15+
// ...
2816
```
2917

30-
---
31-
3218
To be able to insert a row into the `snippets` table, we need to have data in the `users` table. Create a user and note what the user ID is.
3319

3420
The POST request we want to make will look something like this:
@@ -42,9 +28,9 @@ POST /api/snippets
4228
}
4329
```
4430

45-
---
31+
### Exercise: Implement the POST endpoint
4632

47-
**Task:** when we now make a request like
33+
When we now make a request like:
4834

4935
```text
5036
POST /api/snippets
@@ -57,7 +43,4 @@ POST /api/snippets
5743

5844
you should insert a new row into the `snippets` table with the data from the request body.
5945

60-
Hints:
61-
62-
- [Insert with Knex](https://knexjs.org/guide/query-builder.html#insert)
63-
- When creating a snippet we also need to specify a `user_id`. For now, you can just pass in the `user_id` in the request body (alongside the other snippet data)
46+
When creating a snippet we also need to specify a `user_id`. For now, you can just pass in the `user_id` in the request body (alongside the other snippet data).
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# PUT endpoint
2+
3+
TODO

0 commit comments

Comments
 (0)