Skip to content

Commit 305d1ea

Browse files
[mabel] Shift descriptions from express basics to individual topics
1 parent e0af24c commit 305d1ea

File tree

5 files changed

+132
-143
lines changed

5 files changed

+132
-143
lines changed

docs/backend-web-development/express-basics.md

Lines changed: 0 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -33,123 +33,6 @@ const server = app.listen(PORT, () => {
3333
});
3434
```
3535

36-
## Routing
37-
38-
Routing is to add a handler function (a callback function) that is called when a user visit a particular route, for example the homepage `/` or `/books`. When you listen for connections on a route in Express, the handler function will be invoked when a request comes in.
39-
40-
The request object and response object are passed to the handler function when the handler function is called.
41-
42-
```js
43-
app.get("/", (req, res) => {
44-
res.send("Hello World!");
45-
});
46-
```
47-
48-
Routing is described in detail on another page.
49-
50-
## Request object
51-
52-
The Request object (req) passed to a callback function holds all the HTTP request information that was sent to your server like query strings.
53-
54-
It starts off as an instance of _http.IncomingMessage_, a core Node object. Express then extends the object to add further functionality.
55-
56-
These are the commonly used properties of the request object:
57-
58-
- `req.params`
59-
Added by Express. An array containing named route parameters. This will be further explained below.
60-
61-
- `req.query`
62-
Added by Express. An object containing querystring parameters as name/value pairs. This will also be further explained below.
63-
64-
- `req.url`
65-
The request URL string.
66-
67-
- `req.method`
68-
The HTTP method (GET, POST, PUT, DELETE).
69-
70-
These could be used for debugging.
71-
72-
```js
73-
console.log("Method: " + req.method);
74-
console.log("Path: " + req.url);
75-
```
76-
77-
You are unable to access the body of a request with `req.body` if the body is not parsed yet. This will be further explained in the [parsing request body](express-parsing-request-body) page.
78-
79-
## Response object
80-
81-
The Response object (res) passed to a callback function holds information that your server will respond with when the connection is ended with the client.
82-
83-
It starts off as an instance of _http.ServerResponse_, a core Node object. The res object is an enhanced version of the response object found in Node.js.
84-
85-
These are the commonly used properties or methods of the response object:
86-
87-
- `res.send()`
88-
Added by Express. Use it to send a response back to the client.
89-
90-
- `res.json()`
91-
Added by Express. Use it to send a JSON response back to the client.
92-
93-
- `res.status(statusCode)`
94-
Added by Express. Use it to set the status code of the response.
95-
96-
- `res.sendStatus(statusCode)`
97-
Added by Express. Shortcut for the above and sending the string representation of the status code as the response body.
98-
99-
- `res.end()`
100-
Send an empty response back to the client without any body.
101-
102-
## Middleware
103-
104-
Middleware functions are run by Express.js on the request before passing it on to the final handler function.
105-
106-
The request object, response object and the `next` function are passed to each middleware function. To move on to the `next` function to be run in the stack (could be a middleware function or handler function), the `next` function needs to be called.
107-
108-
```js
109-
app.use(function(req, res, next) {
110-
console.log("Method: " + req.method);
111-
console.log("Path: " + req.url);
112-
next();
113-
}
114-
```
115-
116-
Middleware is described in detail on another page.
117-
118-
## Routers
119-
120-
From Express.js [documentation for Router](https://expressjs.com/en/guide/routing.html#express-router),
121-
122-
> Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
123-
124-
In other words, routers are just like the root level app you created using `express()` so much so that they are mini-apps.
125-
126-
You can mount them to an app. For example, a router can be mounted to the `/empty` route of an app.
127-
128-
```js
129-
const router = express.Router();
130-
131-
router.get("/", (res, req) => res.end());
132-
router.post("/", (res, req) => res.end());
133-
134-
app.use("/empty", router);
135-
```
136-
137-
## Layer stack
138-
139-
How does all these work together?
140-
141-
When we call `app.use` or `app.get` etc, we are adding a layer into the app or router.
142-
Every app or router will have a layer stack - a stack of layers where every _Layer_ has its own _path_.
143-
144-
This layer can be a
145-
146-
- middleware
147-
- route
148-
- error handler
149-
- another router
150-
151-
See this [Medium article](https://medium.com/@viral_shah/express-middlewares-demystified-f0c2c37ea6a1) if you are curious to understand how this layer stack works.
152-
15336
## Testing the server
15437

15538
### cURL

docs/backend-web-development/express-error-handling.md

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Within an error handler, you typically need to do one of two things:
4040
- call `next(err)` to pass the execution to the next error handler
4141

4242
```js
43-
app.use(function(err, req, res, next) {
43+
app.use(function (err, req, res, next) {
4444
res.status(500);
4545
res.send(
4646
`Error: ${err} </br>
@@ -67,7 +67,7 @@ app.get("/", (req, res) => {
6767
Return the correct status code in the response header if `err.code` is defined. Else we will default to the error code `500`.
6868

6969
```js
70-
app.use(function(err, req, res, next) {
70+
app.use(function (err, req, res, next) {
7171
res.status(err.code || 500);
7272
res.send(
7373
`Error: ${err} </br>
@@ -84,7 +84,7 @@ Refer to the script: [Express.js playground: error_handler_example_3](https://gi
8484
If you call an asynchronous API in a route handler and you would like to handle errors returned/thrown by those asynchronous operations, you just need to call `next(err)` when some error happens. That is, you call the `next` callback (which is an argument of every middleware and route handler) with an instance of _Error_.
8585

8686
```js
87-
app.get("/", function(req, res, next) {
87+
app.get("/", function (req, res, next) {
8888
// assume some asynchronous error happens because of an network issue
8989
const err = new Error("Unexpected network error");
9090
next(err);
@@ -94,15 +94,15 @@ app.get("/", function(req, res, next) {
9494
Let's add a route handler that will not be called because it will be skipped when the error is thrown.
9595

9696
```js
97-
app.get("/", function(req, res, next) {
97+
app.get("/", function (req, res, next) {
9898
console.log("You should not see this line in the console 😡");
9999
});
100100
```
101101

102102
Add a custom error handler that will catch the error and then pass it on to the next error handler.
103103

104104
```js
105-
app.use(function(err, req, res, next) {
105+
app.use(function (err, req, res, next) {
106106
if (err.message === "Unexpected network error") {
107107
console.log("I don't know how to handle network error. Pass it on.");
108108
next(err);
@@ -116,7 +116,7 @@ app.use(function(err, req, res, next) {
116116
Add a final custom error handler that will return a response to the client.
117117

118118
```js
119-
app.use(function(err, req, res, next) {
119+
app.use(function (err, req, res, next) {
120120
res.status(500);
121121
res.send({ error: "internal server error" });
122122
});
@@ -127,8 +127,8 @@ An example of error handling with an asynchronous API is as follows:
127127
```js
128128
const fs = require("fs");
129129

130-
app.get("/", function(req, res, next) {
131-
fs.readFile("/file-does-not-exist", function(err, data) {
130+
app.get("/", function (req, res, next) {
131+
fs.readFile("/file-does-not-exist", function (err, data) {
132132
if (err) {
133133
next(err);
134134
} else {
@@ -145,8 +145,8 @@ To see the value of having error handling middleware, imagine having the followi
145145
```js
146146
const fs = require("fs");
147147

148-
app.get("/", function(req, res, next) {
149-
fs.readFile("/file-does-not-exist", function(err, data) {
148+
app.get("/", function (req, res, next) {
149+
fs.readFile("/file-does-not-exist", function (err, data) {
150150
if (err) {
151151
res.status(500).json({ error: error.toString() });
152152
} else {
@@ -192,3 +192,19 @@ You can see now that error handling middleware allows you to consolidate error h
192192
## Best practices
193193

194194
As a best practice, we should always declare a default error handler for all requests, to ensure we handle all unforeseeable error scenarios. You will define error-handling middleware last, after other app.use() and routes calls.
195+
196+
## Layer stack
197+
198+
How does middleware, route, error handler, routers work together?
199+
200+
When we call `app.use` or `app.get` etc, we are adding a layer into the app or router.
201+
Every app or router will have a layer stack - a stack of layers where every _Layer_ has its own _path_.
202+
203+
This layer can be a
204+
205+
- middleware
206+
- route
207+
- error handler
208+
- another router
209+
210+
See this [Medium article](https://medium.com/@viral_shah/express-middlewares-demystified-f0c2c37ea6a1) if you are curious to understand how this layer stack works.

docs/backend-web-development/express-middleware.md

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,27 @@
11
# Express.js middleware
22

3-
Middlewares are all the functions that are invoked by the Express.js routing layer before the final handler function is called. They sit in the middle between a raw request and the final intended route. We often refer to these functions as the middleware stack since they are always invoked in the order they are added.
3+
Middlewares are all the functions that are invoked by the Express.js routing layer on the request before the final handler function is called. They sit in the middle between a raw request and the final intended route. We often refer to these functions as the middleware stack since they are always invoked in the order they are added.
4+
45
The following diagram shows how the middlewares work together in a _pipeline_ like water flowing in a pipe:
56

67
<img src="backend-web-development/_media/middleware.png" alt="how middleware work together" width="700"/>
78

89
(image source: https://manuel-rauber.com)
910

11+
You could also imagine that it is a factory. For the request "assembly line", the request is passed from one middleware to another before it reaches the final handler function where the response is finally sent back to the client.
12+
13+
## Example
14+
15+
The request object, response object and the `next` function are passed to each middleware function. To move on to the `next` function to be run in the stack (could be a middleware function or handler function), the `next` function needs to be called.
16+
17+
```js
18+
app.use(function(req, res, next) {
19+
console.log("Method: " + req.method);
20+
console.log("Path: " + req.url);
21+
next();
22+
}
23+
```
24+
1025
## Why do we need middlewares?
1126
1227
Middlewares allow us to put logic with cross-cutting concerns (i.e. the logic that can be shared by multiple route handlers) into a common place and avoid duplicating the same logic in each route handler.
@@ -60,7 +75,7 @@ Refer to the script: [Express.js playground: middleware_example_1](https://githu
6075
Add a middleware function that will be called for all routes. It has no mount path.
6176
6277
```js
63-
app.use(function(req, res, next) {
78+
app.use(function (req, res, next) {
6479
console.log("common middleware function was called!");
6580
next();
6681
});
@@ -69,7 +84,7 @@ app.use(function(req, res, next) {
6984
Add a middleware function that will only be called if a request goes to the `/users` route.
7085
7186
```js
72-
app.use("/users", function(req, res, next) {
87+
app.use("/users", function (req, res, next) {
7388
console.log("middleware function for /users was called!");
7489
next();
7590
});
@@ -78,7 +93,7 @@ app.use("/users", function(req, res, next) {
7893
Add a middleware function that will only be called if a POST request goes to the `/users` route.
7994
8095
```js
81-
app.post("/users", function(req, res, next) {
96+
app.post("/users", function (req, res, next) {
8297
console.log("second middleware function for /users was called!");
8398
next();
8499
});
@@ -87,7 +102,7 @@ app.post("/users", function(req, res, next) {
87102
Add a middleware function that will only be called if a GET request goes to the `/users` route.
88103
89104
```js
90-
app.get("/users", function(req, res, next) {
105+
app.get("/users", function (req, res, next) {
91106
console.log("third middleware function for /users was called!");
92107
next();
93108
});

docs/backend-web-development/express-routers.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,20 @@
22

33
For a very small app, we can define all the API endpoints in one file, like what we did in the previous examples. However, as our application grows, it's a good idea to break the application into smaller modules. In terms of the API end points, it would be better to group API endpoints by their nature.
44

5-
Each Router is like a mini-app or subapplication, which means it can contain its own API endpoints, together with many other things such as middleware and error handlers, as you will notice later.
5+
Use the express.Router class to create modular, mountable route handlers.Each Router is like a mini-app or subapplication, which means it can contain its own API endpoints, together with many other things such as middleware and error handlers, as you will notice later.
6+
7+
## Example
8+
9+
You can mount them to an app. For example, a router can be mounted to the `/empty` route of an app.
10+
11+
```js
12+
const router = express.Router();
13+
14+
router.get("/", (res, req) => res.end());
15+
router.post("/", (res, req) => res.end());
16+
17+
app.use("/empty", router);
18+
```
619

720
## Implementation
821

@@ -14,8 +27,6 @@ const router = express.Router();
1427

1528
The difficult part is deciding / designing what to put in it.
1629

17-
## Exercises
18-
1930
For example, if we are implementing an API for a library system, the API endpoint for users and books can be put into their own routers / modules. We can refactor our basic example to use routers.
2031

2132
### Basic organisation of routes

0 commit comments

Comments
 (0)