Skip to content

Commit 24714b9

Browse files
committed
Use single GET request for search functionality
1 parent b29a774 commit 24714b9

File tree

1 file changed

+34
-25
lines changed

1 file changed

+34
-25
lines changed

nodeJS/express/forms_and_data_handling.md

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ Let's create a simple HTML form, with a single text field for collecting a full
1919
The HTML structure would look something like this:
2020

2121
```html
22-
<form action="/create" method="POST" >
22+
<form action="/create" method="POST">
2323
<label for="fullName">Full Name:</label>
24-
<input placeholder="John Doe" type="text" name="fullName" id="fullName">
24+
<input placeholder="John Doe" type="text" name="fullName" id="fullName" />
2525
<button type="submit">Submit</button>
2626
</form>
2727
```
@@ -39,7 +39,7 @@ The `form` attributes define how to communicate with the server:
3939
- `action`: The resource/URL where data is sent for processing when the form is submitted. If this is not set, or is an empty string, the form will be submitted back to the current page URL
4040
- `method`: Defines the HTTP method to use (`POST` or `GET`).
4141

42-
`POST` is generally more secure because it keeps sensitive information out of the URL, which means they won't show up in server logs, and is the standard choice for creating or updating data on the server side. `GET` is for forms that don't modify data, such as search forms, or when you want the form submission to be bookmarkable or shareable via URL.
42+
`POST` is generally more secure because it keeps sensitive information out of the URL, which means they won't show up in server logs, and is the standard choice for creating or updating data on the server side. `GET` is for forms that don't modify data, such as search forms, or when you want the form submission to be bookmarkable or shareable via URL. The form data here is sent as a query string as part of the request url.
4343

4444
#### Form handling process
4545

@@ -51,16 +51,16 @@ We then generate a new or updated view with the controller's response and redire
5151

5252
Before the data from a form is sent off to our server, we should consider two important steps:
5353

54-
- *Validation* ensures user input meets the specified criteria (e.g. required fields, correct format).
55-
- *Sanitization* cleans user input to prevent malicious data from being processed by removing or encoding potentially malicious characters.
54+
- _Validation_ ensures user input meets the specified criteria (e.g. required fields, correct format).
55+
- _Sanitization_ cleans user input to prevent malicious data from being processed by removing or encoding potentially malicious characters.
5656

5757
We don't always have to sanitize data right when we get it - sometimes it makes sense to sanitize just before we use it instead.
5858

5959
We'll be using a library called `express-validator` to help us out with both of these. While it makes these processes much simpler, it's important to understand the underlying concepts of these two operations.
6060

6161
#### Installing express-validator
6262

63-
We start as usual by installing the correct package in the *root* folder of our project.
63+
We start as usual by installing the correct package in the _root_ folder of our project.
6464

6565
```bash
6666
npm install express-validator
@@ -82,7 +82,7 @@ The `body()` function allows you to specify which fields in the request body sho
8282
[
8383
body("birthdate", "Must be a valid date.")
8484
.optional({ values: "falsy" })
85-
.isISO8601() // Enforce a YYYY-MM-DD format.
85+
.isISO8601(), // Enforce a YYYY-MM-DD format.
8686
];
8787
```
8888

@@ -99,7 +99,7 @@ You can also chain multiple validation methods, with unique error messages if th
9999
.notEmpty()
100100
.withMessage("Name can not be empty.")
101101
.isAlpha()
102-
.withMessage("Name must only contain alphabet letters."),
102+
.withMessage("Name must only contain alphabet letters."),
103103
];
104104
```
105105

@@ -122,11 +122,15 @@ When unescaped, this would be rendered into HTML as:
122122

123123
```html
124124
<div>
125-
About Me: <script>alert("Hacked!");</script>!
125+
About Me:
126+
<script>
127+
alert("Hacked!");
128+
</script>
129+
!
126130
</div>
127131
```
128132

129-
To prevent this [cross-site scripting (XSS) attack](https://en.wikipedia.org/wiki/Cross-site_scripting), we can *escape* the output (you may also see this referred to as *encoding*). Escaped HTML replaces special characters, like `<`, with their respective HTML entities, in this case `&lt;`. In EJS, we can escape the output using `<%= %>`.
133+
To prevent this [cross-site scripting (XSS) attack](https://en.wikipedia.org/wiki/Cross-site_scripting), we can _escape_ the output (you may also see this referred to as _encoding_). Escaped HTML replaces special characters, like `<`, with their respective HTML entities, in this case `&lt;`. In EJS, we can escape the output using `<%= %>`.
130134

131135
```ejs
132136
<div>
@@ -191,7 +195,7 @@ In our form, the action would look something like this:
191195
<form action="/users/<%= user.userId %>/update" method="POST"></form>
192196
```
193197

194-
`/users/:id/update` is an *endpoint* we've created on our Express server.
198+
`/users/:id/update` is an _endpoint_ we've created on our Express server.
195199

196200
### Putting it together
197201

@@ -220,7 +224,7 @@ const PORT = process.env.PORT || 3000;
220224
app.listen(PORT, () => console.log(`Express app listening on port ${PORT}!`));
221225
```
222226

223-
Most simple forms will use the `Content-Type: application/x-www-form-urlencoded` HTTP header when sending data to the server. Express, however, can't natively parse that data. We can use the `express.urlencoded()` middleware to handle this for us and automatically set form's data to the `req.body` field. When `extended` is `false`, our server will only accept a `string` or an array of data, so we set it to `true` for some added flexibility. Note that if the `Content-Type` doesn't match `application/x-www-form-urlencoded`, then your server will show the data as an empty object `{}`.
227+
Most simple forms will use the `Content-Type: application/x-www-form-urlencoded` HTTP header when sending data to the server. Express, however, can't natively parse that data. We can use the `express.urlencoded()` middleware to handle this for us and automatically set form's data to the `req.body` field. When `extended` is `false`, our server will only accept a `string` or an array of data, so we set it to `true` for some added flexibility. Note that if the `Content-Type` doesn't match `application/x-www-form-urlencoded`, then your server will show the data as an empty object `{}`.
224228

225229
Let's create a new router called `usersRouter.js` in the routes folder:
226230

@@ -364,12 +368,18 @@ const alphaErr = "must only contain letters.";
364368
const lengthErr = "must be between 1 and 10 characters.";
365369

366370
const validateUser = [
367-
body("firstName").trim()
368-
.isAlpha().withMessage(`First name ${alphaErr}`)
369-
.isLength({ min: 1, max: 10 }).withMessage(`First name ${lengthErr}`),
370-
body("lastName").trim()
371-
.isAlpha().withMessage(`Last name ${alphaErr}`)
372-
.isLength({ min: 1, max: 10 }).withMessage(`Last name ${lengthErr}`),
371+
body("firstName")
372+
.trim()
373+
.isAlpha()
374+
.withMessage(`First name ${alphaErr}`)
375+
.isLength({ min: 1, max: 10 })
376+
.withMessage(`First name ${lengthErr}`),
377+
body("lastName")
378+
.trim()
379+
.isAlpha()
380+
.withMessage(`Last name ${alphaErr}`)
381+
.isLength({ min: 1, max: 10 })
382+
.withMessage(`Last name ${lengthErr}`),
373383
];
374384

375385
// We can pass an entire array of middleware validations to our controller.
@@ -386,7 +396,7 @@ exports.usersCreatePost = [
386396
const { firstName, lastName } = req.body;
387397
usersStorage.addUser({ firstName, lastName });
388398
res.redirect("/");
389-
}
399+
},
390400
];
391401
```
392402

@@ -475,7 +485,7 @@ exports.usersUpdatePost = [
475485
const { firstName, lastName } = req.body;
476486
usersStorage.updateUser(req.params.id, { firstName, lastName });
477487
res.redirect("/");
478-
}
488+
},
479489
];
480490
```
481491

@@ -541,11 +551,10 @@ Don't forget to update the view to display these new fields!
541551

542552
What if we want to search for a specific user in a list of thousands? We'll need a new route and view that lets clients search our list of users.
543553

544-
1. Add a form (in `createUser.ejs` or another view) which accepts a `name` or `email` (or both!)
545-
1. Create a new route `/search` which accepts `GET` and `POST` requests.
546-
1. Add the search logic to your controller which searches your list for a matching user.
547-
- Your `POST` request should handle searching for the user.
548-
- Your `GET` request should then render the search result.
554+
1. Add a form with a `GET` method (in `createUser.ejs` or another view) which accepts a `name` or `email` (or both!)
555+
1. Create a new route `/search` which accepts a `GET` request.
556+
1. Add the search logic to your controller which searches your list for a matching user. Form data that has been sent via a `GET` request will not be available in the `req.body`. You will need to use `req.query` instead.
557+
- Your `GET` request should handle searching for the user and then render the search result.
549558
1. Display the search results in a new view: `search.ejs`.
550559

551560
#### Further Reading

0 commit comments

Comments
 (0)