# 2008-FSA Cookie Jar: node-postgres (`pg`), Express `Router`
## What is destructuring?
- ***Answer:***
Please see the following two _amazing_ posts. (Also, linked in your [cohort repo](https://github.com/FullstackAcademy/2008-FSA-RM-WEB-FT#helpful-resourceslinks).)
- [A Dead Simple intro to Destructuring JavaScript Objects](https://wesbos.com/destructuring-objects)
- [Rename & Destructure Variables in ES6](https://wesbos.com/destructuring-renaming)
## Why can't I see my pair programming partner's database on my machine after pulling from GitHub?
- ***Answer:***
Your database is on your **local** machine. This means you have to **create** it on each person's machine. Likewise, you must each **seed** your database locally. Remember to ***read*** your errors. They tell us _a lot_.
Database information (i.e. table rows/instances) is ***not*** stored on GitHub. This can be **_very_ private** information. It is written to a disk (run `show data_directory;` in your `psql` CLI to see exactly where locally). Application production databases are hosted on a server (see PostgreSQL hosting providers [here](https://www.postgresql.org/support/professional_hosting/northamerica/). For example, Amazon Web Services is very popular throughout the industry. We will use Heroku at FSA (Best Buy uses Heroku too!).
## I wanted to verify my understanding: the HTTP verbs (GET, POST, PUT, DELETE) are just semantic. That is, it would be valid code, but bad practice, to do create/update/delete actions on the server in response to GET requests. Is that correct?
- ***Answer:***
- Precisely. From [MDN: Http request methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods):
> HTTP defines a set of **request methods** to indicate the desired action to be performed for a given resource. Although they can also be nouns, these request methods are sometimes referred to as ***HTTP verbs***. Each of them implements a different semantic, but some common features are shared by a group of them: e.g. a request method can be safe, idempotent, or cacheable.
- I also recommend reading [DEV: Why you should use standard HTTP methods when designing REST APIs](https://dev.to/suhas_chatekar/why-should-you-use-standard-http-methods-while-designing-rest-apis).
- Specifically, the "**Idempotence is not limited to mathematics**" section! 🔥
## When adding the ability to parse (such as `app.use(express.urlencoded/json/etc.)`), would adding too many options negatively impact performance? Is it bad practice to include ones we might not use 'just in case'?
- ***Answer:***
I am not aware of any egregious hits in performance by simply passing options to middleware parsing methods.
Side note: Express is relatively very lightweight. If you're curious about other Node backend frameworks, you can check out Koa, Fastify, and Hapi.js, as a few examples.
## When doing SQL queries into our database during the Wizard News Pt 3, we saw the option to handle more or our logic in SQL vs. handling more of our logic in Javascript, and using additional SQL queries. Would there be reasons to prefer a SQL heavy approach vs. a JS-heavy approach or vice-versa?
- ***Answer:***
Concrete examples (i.e. code snippets) would help me have a better idea of what you mean here, but I'll try answering the question I _think_ you're asking.
Everytime we send a SQL query, we are opening up a conversation with the database. If we can take care of what we need exactly in one shot in SQL then it's best to do so and avoid pinging the database again (i.e. sending another query).
Likewise, if we are in a route such as `/posts/:id`, it doesn't make sense for us to fetch **all** posts from the database and then iterate through the array to find the correct instance using `req.params.id`. This is a taxing operation. Imagine if you have a database table with 100,000s of rows.
If I misinterpreted your question, kindly take up an office hour with me!
___
# Exit Ticket Questions
## When chaining through the middleware and arriving at a specific route, if there are public related files to return in a html object response I’d there a new request made to the server for those files? Ex, a logo.png file
- ***Answer:***
If there is a view (HTML) that has an `<img>`, for example, the client will make ***another*** request to the server for that asset. I encourage you to open up the _Network_ tab in Chrome dev tools to see all of the requests made. If you take my [personal site](https://www.noellelaureano.com/), as a reference, my image is retrieved through a `GET` request to the URL https://www.noellelaureano.com/static/noelle.40b25272.jpg. In fact, if you simple click this link from here, it'll just show you my image (awww) by sending that same aforementioned `GET` request from the browser. If you're curious about the source code, feel free to look at my personal website's [GitHub repo](https://github.com/nrl240/noelle-laureano/blob/master/src/layouts/components/About.js).
## How did we set the submit button on the /posts/add form to do anything? Is the `<form>` tag implicitly linked with this `<button>` tag?
- ***Answer:***
Yes, `<form>` tags are implicitly submitted by the associated `<button>` tag nested within. We can also submit our forms using an `<input>` tag so as long as the `type` attribute is set to `submit`. Please see the following references.
- [MDN: How to structure a web form](https://developer.mozilla.org/en-US/docs/Learn/Forms/How_to_structure_a_web_form)
- [MDN: Your first form](https://developer.mozilla.org/en-US/docs/Learn/Forms/Your_first_form)
- [MDN: Web forms — Working with user data](https://developer.mozilla.org/en-US/docs/Learn/Forms)
- [MDN: Sending form data](https://developer.mozilla.org/en-US/docs/Learn/Forms/Sending_and_retrieving_form_data)
## I noticed that in the Wizard News workshop, the URI parameter (`/:id`) needed to come last for the `/add` route to work. Can you please go over this?
- ***Answer:***
This is called "fuzzy matching". A route will match any path that follows its path immediately with a “/”. For example, `app.use('/apple', ...)` will match “/apple”, “/apple/images”, “/apple/images/news”, and so on.
Going back to the Wizard News workshop, if the route `router.get('/:id', ...)` comes **before** `router.get('/add', ...)`, an incoming `GET` request to `/add` will hit the `router.get('/:id', ...)` route first since it will consider "add" as the "id", and set `req.params = { id: "add" }`. Instead of adding logic into the route to check if the `id` is an integer, we simply change the order of our routes in the file to avoid this.
## How can we input key value pairs to be stored in an SQL table? Basically the "Creating the form submission route" part of Wizard News 3.
- ***Answer:***
Our keys represent our **table _fields_** (e.g. `name`, `title`, `content`), which are determined when we design our database schema and set when the table is created in the database (e.g. using raw SQL or an ORM like Sequelize).
How the information (the "values" you mentioned) for those fields is inserted into the table(s) is via **SQL** in Wizard News (e.g. `let userData = await client.query('SELECT * FROM users WHERE users.name = $1', [req.body.name]);`). Please refer to the `POST` route in the [solution code](https://github.com/FullstackAcademy/2008-FSA-RM-WEB-FT/blob/master/01-junior-phase/08-pg-express/Solution.WizardNewsPt3/routes/posts.js).
## Can you explain the logic behind the `router.post()` route? // do a quick run-through of that
- ***Answer:***
Please see all of my comments in the solution code below (e.g. "Step 1: ..."). Note, this is also in the workshop's [review video walkthrough](https://youtu.be/xH6waRdwQ_w), which was linked in your GitHub repo, as well.
```js
router.post("/", async (req, res) => {
try {
// Step 1: Check if the user exists in the database
let userData = await client.query(
'SELECT * FROM users WHERE users.name = $1',
[req.body.name]
);
// Step 2: If the user doesn't exist in the database, the `rows` array will not have a length
if(!userData.rows.length) {
// Step 3: Since the user doesn't exist, insert the user into the database
userData = await client.query(
'INSERT INTO users (name) VALUES ($1) RETURNING *',
[req.body.name]
);
}
// Step 4: Pluck the user's `id` off of the user instance
const userId = userData.rows[0].id;
// Step 5: Insert the new post into the database with the associated `userId`
const postData = await client.query(
`INSERT INTO posts (userId, title, content) VALUES ($1, $2, $3) RETURNING *`,
[userId, req.body.title, req.body.content]
);
// Step 6: Pluck the post's `id` off of the post instance
const postId = postData.rows[0].id;
// Step 7: Create a new row in the `upvotes` table for the newly created post and the post's associated `userId`
const upvoteData = await client.query(
'INSERT INTO upvotes (userId, postId) VALUES ($1, $2) RETURNING *',
[userId, postId]
);
// Step 8: Redirect the client to that specific post's page using its id (i.e. `postId`)
res.redirect(`/posts/${postId}`);
} catch (error) {
res.status(500).send(`Something went wrong: ${error}`);
}
})
```