Skip to content

Commit

Permalink
adds endpoints step and updates all later steps
Browse files Browse the repository at this point in the history
  • Loading branch information
msmichellegar committed Jul 2, 2016
1 parent 9f63c31 commit a961559
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 194 deletions.
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,13 @@ Throughout each step, we have **bolded** any jargon that you may or may not be f

You will need Node.js installed. Download it from the Node.js website [here](https://nodejs.org/en/).

#### 2. Create a Repository
#### 2. Fork and clone this repository

Create a public repository on GitHub to store your code. Find instructions on how to do that [here](https://help.github.com/articles/create-a-repo/). Make sure you select a Node .gitignore file, and initialise the repository with a README. The setup should look like this:
Fork this repository to your own GitHub account. Instructions for doing this can be found [here](https://help.github.com/articles/fork-a-repo/).

<img src="https://cloud.githubusercontent.com/assets/10683087/16171849/01f36002-3572-11e6-8119-cb866571972b.png">
Then, clone your forked version of the repository to your desktop in the terminal. Instructions for doing this can be found [here](https://help.github.com/articles/cloning-a-repository/), or run the command below.

Clone the repository to your desktop in the terminal. Instructions for doing this can be found [here](https://help.github.com/articles/cloning-a-repository/), or run the command below.

`$ git clone https://github.com/YOUR-USERNAME/YOUR-REPOSITORY`
`$ git clone https://github.com/YOUR-USERNAME/express-workshop`

### [Go to Step 1 >>>>](https://github.com/node-girls/express-workshop/blob/master/step01.md)

Expand Down
2 changes: 1 addition & 1 deletion step04.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,6 @@ Now, open your favourite browser (we like Chrome), and navigate to `http://local
| Keyword | Explanation |
|--------|:-------------------------------:|
| handler function | A function that receives requests and tells the server how to respond to them. |
| endpoint | The part of the URL which comes after /. For example: `/chocolate` is the "chocolate" endpoint. |
| endpoint | The part of the URL which comes after `/`. For example: `/chocolate` is the "chocolate" endpoint. |
| `get()` | The Express method used to set up a handler function in Express. Takes two parameters: the endpoint, and the handler function. |
| `send()` | The Express method used to send information back to the client from the server. Updates the response object. |
40 changes: 19 additions & 21 deletions step05.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
# Step 5 - Routing

At the moment our server only does one thing. When it receives a request from the `/` endpoint, it sends back the same response - "Yay Node Girls!".
At the moment our server only does one thing. When it receives a request from the `/` endpoint, it sends back the same response: "Yay Node Girls!".

**If you don't believe try typing localhost:3000/chocolate and see what happens**
Want to check? Try typing http://localhost:3000/nodegirls and see what happens.

We can make the server send different responses for different requests.
However by making use of endpoints, we can make the server send different responses for different requests. This concept is called **routing**.

### What is an endpoint?

An endpoint is the part of the url which comes after `/`, in above case it's `/chocolate`.
An endpoint is the part of the URL which comes after `/`. For example: `/chocolate` is the "chocolate" endpoint. It's the URL to which you send a request.

## 1. Create your own endpoints and send different responses

## 1. Create your own endpoints and send different responses.
We're going to try sending different responses at different endpoints. Remember the `app.get()` method? To set up routing in your server, we just need to repeat this method with different endpoints.

Add some code so that your server sends one message when the endpoint is `/node` and another one when it's `/girls`.

Good luck :) Feel free to discuss it with your team or mentor.

## 2. Serving your files

So we know how to send back a simple message. But what if you want to send back a whole html page, or an image?

Things like html files, images etc are known as **static assets**. If you want your server to 'serve' static assets back to the browser, you need to do something different.

To be able to send any file from the server we need a special, built-in middleware function that comes with Express: `express.static`.

**Delete all your `app.get` endpoint functions. Then add this one line of code:**
For example:

```js
app.use(express.static('public'));
app.get("/", function (req, res) {
res.send("Hello World!");
});

app.get("/chocolate", function (req, res) {
res.send("Mm chocolate :O");
});
```
Restart your server, refresh your browser and see what happens!

*Challenge:* Add some code so that your server sends one message when the endpoint is `/node` and another one when it's `/girls`.

## [**next step >>>**](step06.md)

---
| Keyword | Explanation |
|--------|:-------------------------------:|
| routing | The definition of application endpoints and how they respond to client requests. |
115 changes: 15 additions & 100 deletions step06.md
Original file line number Diff line number Diff line change
@@ -1,111 +1,26 @@
# Step 06 - Sending your blog post to your server
# Step 6 - Serving static files

So far we have been requesting data from our server. But we can also *send* data to the server to be stored somewhere.
So we know how to send back a simple message. But what if you want to send back a whole HTML page, or an image?

### HTTP request methods
All requests use one of the HTTP methods. The main ones are: `GET, POST, PUT, DELETE`.
Things like HTML files, images etc are known as **static assets**. If you want your server to "serve" static assets back to the browser, you need to do something different than just using the `res.send()` method.

To be able to send any file from the server we need a special, built-in **middleware** function that comes with Express: `express.static()`. Read more about it [here](http://expressjs.com/en/starter/static-files.html).

`app.get` deals with requests that use the `GET` HTTP method.
Say we want to serve all the static assets in our "public" folder. The `express.static()` function will look like this:

### The `POST` http request method

When sending data to the server, we use the `POST` http request method, instead of `GET`. To understand the difference, follow the "POST vs GET" link in the keywords section below.

Let's try `POST`ing some text to the server.

We're going to add a form to the `index.html` page, so that you can write your blogposts from there.

Open up the `index.html` file in your text editor. If you have a look, you should see this:

```html
<div class="entry-container">
<!--PASTE YOUR CODE HERE!! -->
</div>
```

**Replace the greyed-out comment with this code snippet:**

```html
<h3>Create a blog post</h3>
<form action="/create-post" method="POST">
<textarea name="blogpost" rows="10" cols="14">

</textarea>
<button type="submit">Send</button>
</form>
```

* This form has a text area and a Send button.
* The `action` attribute is the endpoint form data will be sent to.
* The `name` attribute will be used later to reference the data.

When you hit Send, the form will send a `POST` request to the server, using whatever is in the `action` attribute as the endpoint. In our case it's `/create-post`.

### Receiving the blog post on the server

* Data doesn't come through the server in one go; it flows to the server in a **stream**. Think of a stream as water flowing from a tap into a bucket. Your job is to collect this water in the server.

* If we were writing a pure Node server, we would have to think about how to collect the stream of data properly. But luckily for us, Express handles all of that stuff under the hood.

* All you need to do is define a route to deal with requests that come through on the `/create-post` endpoint.

Let's remind ourselves of a simple `GET` route in Express:
```js
app.get('/my-lovely-endpoint', function (req, res) {
res.send('Hello there!');
});
app.use(express.static("public"));
```

This time we want to define a route to deal with a `POST` request. What do you think you would need to do differently? Experiment and see if you can define a route for the `/create-post` endpoint!

For now, make your `/create-post` handler simply do this: `console.log('/create-post')`.

---

### Extracting the blog post
## 1. Serve static files from your server

Now the contents of your blogpost is hidden in your `req` object somewhere. Normally you would extract it using `req.body`. Try to console.log `req.body` now.

Getting `undefined`? Not to worry, that's normal. When data has been `POST`ed to the server, we need to do things slightly differently to access the data that's come through in the request.

We need another middleware function: `body-parser`. `body-parser` does what it says on the tin, it will **parse** the data in the request and make it available to you when you do `req.body`.

This time though, `body-parser` is not built-in, we need to explicitly install it.

**In your terminal, install body-parser**
```bash
npm install body-parser --save
```

Now add this towards the top of your server, after your `require`s and before your `/create-post` endpoint:
```js
app.use(bodyParser.urlencoded({ extended: true }));

```
(Don't worry too much about the `{ extended:true }` bit. If you're curious, you can read about it [here](https://www.npmjs.com/package/body-parser#bodyparserurlencodedoptions))

Refresh your server and have another go at writing a blogpost.

You should now see an object in the console. The key should be `blogpost`, just like the name attribute in the form. The value of `blogpost` will be your message!


### Redirecting your page

So you may have noticed that when you hit Send on the form, the browser sort of hangs. It's because it's trying to navigate to the `/create-post` page. Of course, there is no such page.

There's an easy fix for this. In the response, you need to let the browser know that after it's finished with receiving the blogpost, you want it to reload the same page, and not try to go to fake page '/create-post'.

At the end of your `/create-post` handler, add this line of code:

```js
res.redirect('/');
```
Delete all your `app.get` endpoint functions, and replace them with the line of code above. Restart your server, refresh your browser and see what happens! If you see a Node Girls CMS, then your static assets have been successfully served.

This means: "please redirect to the `/` endpoint." This little trick will refresh the page!
## [**Next step >>>**](step07.md)
## [**next step >>>**](step07.md)

---
### Keywords
* [POST vs GET](http://www.w3schools.com/tags/ref_httpmethods.asp)
* [html forms]
| Keyword | Explanation |
|--------|:-------------------------------:|
| static assets | Files such as HTML, CSS and JavaScript documents or images that you want to appear in the browser. |
| middleware | A function (or functions) that are invoked by Express before your final request handler is executed. Middleware sits between a raw request and its final intended route. |
| `use()` | The method that tells Express to use a certain piece of middleware. |
| `express.static()` | The built-in Express middleware function that makes it possible to serve static assets. |
130 changes: 64 additions & 66 deletions step07.md
Original file line number Diff line number Diff line change
@@ -1,113 +1,111 @@
# Step 7 - Saving your blog post
# Step 7 - Sending your blog post to your server

Right now, your precious blog posts aren't being saved anywhere, which is a bit of a shame. Let's do something about that.
So far we have been requesting data from our server. But we can also *send* data to the server to be stored somewhere.

### JSON - the handy data format
### HTTP request methods
All requests use one of the HTTP methods. The main ones are: `GET, POST, PUT, DELETE`.

You'll note that in the data folder there's a new file called `posts.json`.

JSON is a type of file for structuring data in a readable way. It is also a really popular format for sending data across the web.
`app.get` deals with requests that use the `GET` HTTP method.

JSON is a string representation of a Javascript object. JSON objects convert really easily to Javascript objects, and vice versa, with JSON.parse() and JSON.stringify().
### The `POST` http request method

(If you're not sure about Javascript objects, have a chat with your mentor and your team.)
When sending data to the server, we use the `POST` http request method, instead of `GET`. To understand the difference, follow the "POST vs GET" link in the keywords section below.

If you look at `posts.json` will see there's already one blog post there. The format is:
Let's try `POST`ing some text to the server.

```js
{
[timestamp]: [blog post message]
}
```

We've used a timestamp as the key so that the blog posts are listed in chronological order. Also, it's a record of when the blog post was created.
We're going to add a form to the `index.html` page, so that you can write your blogposts from there.

### Writing to your hard drive
Open up the `index.html` file in your text editor. If you have a look, you should see this:

Anytime a blog post comes through to the server, we want to save the data on your computer's hard drive. To do this, we need to use a built-in Node module: `fs`, which stands for 'file-system'.
```html
<div class="entry-container">
<!--PASTE YOUR CODE HERE!! -->
</div>
```

Built-in Node modules (core Node modules) are rather like the built-in Express middleware functions. Only difference is that where you need to have installed Express to use Express middleware functions, the core Node modules come automatically with Node itself.
**Replace the greyed-out comment with this code snippet:**

To use `fs`, you'll need to require it at the top of your server file:
```html
<h3>Create a blog post</h3>
<form action="/create-post" method="POST">
<textarea name="blogpost" rows="10" cols="14">

```js
var fs = require('fs');
</textarea>
<button type="submit">Send</button>
</form>
```

The method we need to write to your hard drive is `fs.writeFile`.
* This form has a text area and a Send button.
* The `action` attribute is the endpoint form data will be sent to.
* The `name` attribute will be used later to reference the data.

```js
fs.writeFile('path/to/file', yourData, function (error) {
// do something
});
```
Argument 1: the location of the file you want to write to
Argument 2: the data you want to write
Argument 3: the callback function
When you hit Send, the form will send a `POST` request to the server, using whatever is in the `action` attribute as the endpoint. In our case it's `/create-post`.

### Receiving the blog post on the server

The 'path/to/file' will be replaced with the actual path to the file you want to write to. If it doesn't exist, `fs.writeFile` cleverly creates one for you. But we already have `posts.json`, so not to worry.
* Data doesn't come through the server in one go; it flows to the server in a **stream**. Think of a stream as water flowing from a tap into a bucket. Your job is to collect this water in the server.

* If we were writing a pure Node server, we would have to think about how to collect the stream of data properly. But luckily for us, Express handles all of that stuff under the hood.

### Reading from your hard drive
To read data that's already there, you would use `fs.readFile`. The way to use `fs.readFile` is very similar to `fs.writeFile`:
* All you need to do is define a route to deal with requests that come through on the `/create-post` endpoint.

Let's remind ourselves of a simple `GET` route in Express:
```js
fs.readFile('path/to/file', function (error, file) {
// do something
app.get('/my-lovely-endpoint', function (req, res) {
res.send('Hello there!');
});
```
Argument 1: the location of the file you want to write to
Argument 2: the callback function

This time we want to define a route to deal with a `POST` request. What do you think you would need to do differently? Experiment and see if you can define a route for the `/create-post` endpoint!

You'll notice that `fs.readFile`'s callback function takes a second argument. That argument would be the file you're reading.
For now, make your `/create-post` handler simply do this: `console.log('/create-post')`.

---

### Extracting the blog post

Let's read the data from the `posts.json` file. Make sure you've `require`d the `fs` core Node module at the top of your server file somewhere.
Now the contents of your blogpost is hidden in your `req` object somewhere. Normally you would extract it using `req.body`. Try to console.log `req.body` now.

Add this code to your server (put it anywhere after the `require`s for now):
Getting `undefined`? Not to worry, that's normal. When data has been `POST`ed to the server, we need to do things slightly differently to access the data that's come through in the request.

```js
fs.readFile(__dirname + '/data/posts.json', function (error, file) {
We need another middleware function: `body-parser`. `body-parser` does what it says on the tin, it will **parse** the data in the request and make it available to you when you do `req.body`.

console.log(file);
});
```


(`__dirname` is a Node global object that gives you a path to current working directory. It's handy if we want to avoid writing the whole path out in full.)
This time though, `body-parser` is not built-in, we need to explicitly install it.


You'll probably see something like this:
**In your terminal, install body-parser**
```bash
<Buffer 7b 0a 20 20 20 20 22 31 34 36 37 33 39 30 33 35 36 32 39 31 22 3a 20 22 54 68 69 73 20 69 73 20 6d 79 20 76 65 72 79 20 66 69 72 73 74 20 62 6c 6f 67 ... >
npm install body-parser --save
```
This is actually the contents of your `posts.json` file, but in a format called a **buffer**. To make it a bit more human-readable, you can console.log the file to a string, like this:

Now add this towards the top of your server, after your `require`s and before your `/create-post` endpoint:
```js
console.log(file.toString());
app.use(bodyParser.urlencoded({ extended: true }));

```
(Don't worry too much about the `{ extended:true }` bit. If you're curious, you can read about it [here](https://www.npmjs.com/package/body-parser#bodyparserurlencodedoptions))

`file` is in JSON format right now. If we want to access the blog post message inside `file`, we need to parse it from JSON back to a JavaScipt object.
Refresh your server and have another go at writing a blogpost.

Add this next bit of code to your `fs.readFile`'s callback function:
```js
var parsedFile = JSON.parse(file);
```
You should now see an object in the console. The key should be `blogpost`, just like the name attribute in the form. The value of `blogpost` will be your message!

Now `parsedFile` is a normal JavaScript object, and we can access the data inside it.

### Redirecting your page

Ok, so we've talked about JSON and we've talked about reading and writing files. You now have the power to save new blog post data to your hard drive! Work with your partner and your mentor to see if you can figure the next steps out on your own.
So you may have noticed that when you hit Send on the form, the browser sort of hangs. It's because it's trying to navigate to the `/create-post` page. Of course, there is no such page.

Here's a breakdown of what you want to achieve:
* When new blog post data comes through, read from `posts.json` to access its contents
* Add your new blog post data to the old ones.
* Write your new combined data back to the `posts.json` file.
There's an easy fix for this. In the response, you need to let the browser know that after it's finished with receiving the blogpost, you want it to reload the same page, and not try to go to fake page '/create-post'.

Oh by the way, if you want to get the current timestamp, use the JavaScript `Date.now()` method.
At the end of your `/create-post` handler, add this line of code:

Good luck!
```js
res.redirect('/');
```

This means: "please redirect to the `/` endpoint." This little trick will refresh the page!
## [**Next step >>>**](step08.md)

---
### Keywords
* [POST vs GET](http://www.w3schools.com/tags/ref_httpmethods.asp)
* [html forms]
Loading

0 comments on commit a961559

Please sign in to comment.