Skip to content
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

Forms and Data Handling: Use single GET request and req.query for Search functionality #28640

Merged
merged 3 commits into from
Aug 16, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 34 additions & 25 deletions nodeJS/express/forms_and_data_handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
The HTML structure would look something like this:

```html
<form action="/create" method="POST" >
<form action="/create" method="POST">
<label for="fullName">Full Name:</label>
<input placeholder="John Doe" type="text" name="fullName" id="fullName">
<input placeholder="John Doe" type="text" name="fullName" id="fullName" />
<button type="submit">Submit</button>
</form>
```
Expand All @@ -39,7 +39,7 @@
- `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
- `method`: Defines the HTTP method to use (`POST` or `GET`).

`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.
`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.

#### Form handling process

Expand All @@ -51,16 +51,16 @@

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

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

Check failure on line 54 in nodeJS/express/forms_and_data_handling.md

View workflow job for this annotation

GitHub Actions / Lint lesson files

Emphasis style

nodeJS/express/forms_and_data_handling.md:54:3 MD049/emphasis-style Emphasis style [Expected: asterisk; Actual: underscore] https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md

Check failure on line 54 in nodeJS/express/forms_and_data_handling.md

View workflow job for this annotation

GitHub Actions / Lint lesson files

Emphasis style

nodeJS/express/forms_and_data_handling.md:54:14 MD049/emphasis-style Emphasis style [Expected: asterisk; Actual: underscore] https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md
- _Sanitization_ cleans user input to prevent malicious data from being processed by removing or encoding potentially malicious characters.

Check failure on line 55 in nodeJS/express/forms_and_data_handling.md

View workflow job for this annotation

GitHub Actions / Lint lesson files

Emphasis style

nodeJS/express/forms_and_data_handling.md:55:3 MD049/emphasis-style Emphasis style [Expected: asterisk; Actual: underscore] https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md

Check failure on line 55 in nodeJS/express/forms_and_data_handling.md

View workflow job for this annotation

GitHub Actions / Lint lesson files

Emphasis style

nodeJS/express/forms_and_data_handling.md:55:16 MD049/emphasis-style Emphasis style [Expected: asterisk; Actual: underscore] https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md

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.

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.

#### Installing express-validator

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

Check failure on line 63 in nodeJS/express/forms_and_data_handling.md

View workflow job for this annotation

GitHub Actions / Lint lesson files

Emphasis style

nodeJS/express/forms_and_data_handling.md:63:60 MD049/emphasis-style Emphasis style [Expected: asterisk; Actual: underscore] https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md

Check failure on line 63 in nodeJS/express/forms_and_data_handling.md

View workflow job for this annotation

GitHub Actions / Lint lesson files

Emphasis style

nodeJS/express/forms_and_data_handling.md:63:65 MD049/emphasis-style Emphasis style [Expected: asterisk; Actual: underscore] https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md

```bash
npm install express-validator
Expand All @@ -82,7 +82,7 @@
[
body("birthdate", "Must be a valid date.")
.optional({ values: "falsy" })
.isISO8601() // Enforce a YYYY-MM-DD format.
.isISO8601(), // Enforce a YYYY-MM-DD format.
];
```

Expand All @@ -99,7 +99,7 @@
.notEmpty()
.withMessage("Name can not be empty.")
.isAlpha()
.withMessage("Name must only contain alphabet letters."),
.withMessage("Name must only contain alphabet letters."),
];
```

Expand All @@ -122,11 +122,15 @@

```html
<div>
About Me: <script>alert("Hacked!");</script>!
About Me:
<script>
alert("Hacked!");
</script>
!
</div>
```

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 `<%= %>`.
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 `<%= %>`.

Check failure on line 133 in nodeJS/express/forms_and_data_handling.md

View workflow job for this annotation

GitHub Actions / Lint lesson files

Emphasis style

nodeJS/express/forms_and_data_handling.md:133:113 MD049/emphasis-style Emphasis style [Expected: asterisk; Actual: underscore] https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md

Check failure on line 133 in nodeJS/express/forms_and_data_handling.md

View workflow job for this annotation

GitHub Actions / Lint lesson files

Emphasis style

nodeJS/express/forms_and_data_handling.md:133:120 MD049/emphasis-style Emphasis style [Expected: asterisk; Actual: underscore] https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md

Check failure on line 133 in nodeJS/express/forms_and_data_handling.md

View workflow job for this annotation

GitHub Actions / Lint lesson files

Emphasis style

nodeJS/express/forms_and_data_handling.md:133:171 MD049/emphasis-style Emphasis style [Expected: asterisk; Actual: underscore] https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md

Check failure on line 133 in nodeJS/express/forms_and_data_handling.md

View workflow job for this annotation

GitHub Actions / Lint lesson files

Emphasis style

nodeJS/express/forms_and_data_handling.md:133:180 MD049/emphasis-style Emphasis style [Expected: asterisk; Actual: underscore] https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md

```ejs
<div>
Expand Down Expand Up @@ -191,7 +195,7 @@
<form action="/users/<%= user.userId %>/update" method="POST"></form>
```

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

### Putting it together

Expand Down Expand Up @@ -220,7 +224,7 @@
app.listen(PORT, () => console.log(`Express app listening on port ${PORT}!`));
```

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 `{}`.
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 `{}`.

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

Expand Down Expand Up @@ -364,12 +368,18 @@
const lengthErr = "must be between 1 and 10 characters.";

const validateUser = [
body("firstName").trim()
.isAlpha().withMessage(`First name ${alphaErr}`)
.isLength({ min: 1, max: 10 }).withMessage(`First name ${lengthErr}`),
body("lastName").trim()
.isAlpha().withMessage(`Last name ${alphaErr}`)
.isLength({ min: 1, max: 10 }).withMessage(`Last name ${lengthErr}`),
body("firstName")
.trim()
.isAlpha()
.withMessage(`First name ${alphaErr}`)
.isLength({ min: 1, max: 10 })
.withMessage(`First name ${lengthErr}`),
body("lastName")
.trim()
.isAlpha()
.withMessage(`Last name ${alphaErr}`)
.isLength({ min: 1, max: 10 })
.withMessage(`Last name ${lengthErr}`),
];

// We can pass an entire array of middleware validations to our controller.
Expand All @@ -386,7 +396,7 @@
const { firstName, lastName } = req.body;
usersStorage.addUser({ firstName, lastName });
res.redirect("/");
}
},
];
```

Expand Down Expand Up @@ -475,7 +485,7 @@
const { firstName, lastName } = req.body;
usersStorage.updateUser(req.params.id, { firstName, lastName });
res.redirect("/");
}
},
];
```

Expand Down Expand Up @@ -541,11 +551,10 @@

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.

1. Add a form (in `createUser.ejs` or another view) which accepts a `name` or `email` (or both!)
1. Create a new route `/search` which accepts `GET` and `POST` requests.
1. Add the search logic to your controller which searches your list for a matching user.
- Your `POST` request should handle searching for the user.
- Your `GET` request should then render the search result.
1. Add a form with a `GET` method (in `createUser.ejs` or another view) which accepts a `name` or `email` (or both!)
1. Create a new route `/search` which accepts a `GET` request.
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.
MaoShizhong marked this conversation as resolved.
Show resolved Hide resolved
- Your `GET` request should handle searching for the user and then render the search result.
1. Display the search results in a new view: `search.ejs`.

#### Further Reading
Expand Down
Loading