The purpose of this challenge is to understand server fundamentals in vanilla Node.js under the hood - notably the request and response object. We will be learning how to deal with events, streams and constructing the request body. Later on, the popular framework Express will abstract these concepts, but we want to learn their fundamental workings in this unit.
Clients (browsers, mobile devices, and more) send requests to servers. The server's responsibility is to interpret the request and then respond with the the appropriate information. For example, the client might request the most recent 20 tweets from all of its friends. The server would process the request in the following order:
- Find the user requesting the tweets
- Find the friends of that user
- Find their most recent tweets
- Sort the tweets
- Give the client what was requested via the response object
All of this information can be gathered based on the information in the request object. If, however, the server is unable to provide the data the client requested, then the response object is returned with information about the error. The most common error the response object provides is the 404 error:
- Install dependencies.
npm install
- A node http ‘server’ has been started for you in the
server.js
file. A GET request from the user’s browser is usually designed to get content/data from a server. Add code to have the server serve a message “Welcome to Twitter” back to the client (the user). In this question, ignore the conditional logic for now
For this exercise, do not use Express or any other Node framework. Run your server with the following command:
node server.js
or npm start
Then visit http://localhost:3000/
. To exit the server, press ctrl+C
.
Note: Whenever you make changes to your server, you will need to restart your server by exiting your server then opening it again.
(optional) Alternatively, Nodemon is a utility that will automatically restart your server whenever you save changes to a file. Install nodemon by running npm install --save-dev nodemon
and then run your server using the following command: nodemon server.js
. Servers running with nodemon do not need to be restarted when changes are made to the source code.
- Now we are going to investigate the Node auto-inserted object into the callback function. It represents the request from the user.
Write logic in the conditional to send the index.html
page on a GET request to the url /
by introspecting the request object. Look up the fs.readFileSync
function. (Note that in future sections we will be using the asynchronous and non-blocking fs.readFile
rather than the synchronous and blocking fs.readFileSync
.)
-
When you successfully serve the index.html page, have your server respond to a POST request to the url
/sayHi
with the texthi back to you!
. (Notice how we've set up the POST request functionality for you in index.html: what happens when we click the button "Say Hi"? Check the browser console.) -
A POST request is usually designed to store data on a server. Modify your code for the POST request to
/sayHi
so that the server adds the textSomebody said hi.\n
to a file namedhi_log.txt
. Look up thefs.appendFileSync
to complete this task. (Note:fs.appendFileSync
has an asynchronous counterpart calledfs.appendFile
which we will be using in future units). After the file operation have the server respond with the stringhi back to you!
Now happens when we click the button "Say Hi"? -
A POST request is usually accompanied by a request body. The body is a string that usually represents the data we want to store. The request body can sometimes be very long depending on the volume of data that needs to be stored. Thus, the request body comes to the server in "chunks" at a time. These "chunks" flow from the client to the server in what we call a "stream." Have your server respond to a POST request to
/greeting
. One of the buttons in index.html makes a POST to/greeting
with the bodyhello
, and the another makes a POST to/greeting
with the bodywhat's up
(which buttons are these? Check index.html). If the request body ishello
, then respond withhello there!
. If the request body iswhat's up
, then respond withthe sky
. Otherwise, respond withgood morning
. To accumulate the request body chunks that come to the server, define two event handlers for the request: ondata
, and onend
. Thedata
event handler fires when we receive a chunk of the request body. When theend
event handler fires, we need to combine these chunks together into a final request body string. Depending on that string, make the appropriate response from the server. -
Have the POST request to the route
/greeting
store the request body in the filehi_log.txt
. -
On a typical website, making a request to a url that the server cannot find will display a 404: not found page. In general, you want to respond to any request that cannot be found with a 404 message. Currently, our site hangs and eventually times out if we make a request to e.g.
http://localhost:3000/nonexistent
(try it!). Thus, if the server cannot find the url, set the response header code to 404 and send back the messageError: Not Found
. -
Our web page currently has no styling. Go to the
index.html
file and uncomment out the link to the stylesheet. Now restart the server, and go look at our web page. We still don't have any styling on our page! If we check the console it suggests that the request to/style.css
is giving a 404 not found error. Have your server respond to GET requests for/style.css
so that the page is styled. Where is this/style.css
route being requested? -
Download Postman. Postman allows you to directly make GET, POST, and other requests to a server by typing into a URL bar. Note that directly typing into the web browser URL bar only allows making GET requests. Test your server's GET and POST requests to the routes you defined earlier using Postman. To do this, go to Postman and
- Make a GET request to
http://localhost:3000/
. What do we expect to see in the response? - Make a POST request to
http://localhost:3000/sayHi
. What do we expect to see in the response? Doeshi_log.txt
also change? - Make a POST request to
http://localhost:3000/greeting
. Define the request body in Postman. To do this, click on the "Body" tab(below the URL bar), click on "raw", click on "JSON", then type in the request body text as a JSON object. - Make a GET request to
http://localhost:3000/nonexistent
. What do we expect to see in the response?
- Make a GET request to
Start your node server and visit http://localhost:3000/
to test out whether you have successfully responded to the user request
The acronym CRUD
(Create, Read, Update, Delete) refers to the four major functions implemented in persistent data applications (this will become more clear when we start working with databases). Although there are many different types of request methods to choose from (see the request method drop down in Postman for varying options), there are four key request methods that complement CRUD functionality. Lucky for you, you've already used two of them! POST
is the request method used to Create
new data in storage. GET
is the method used to Read
existing data. PUT
is the method to Update
existing data, and lastly DELETE
is the method used to Delete
existing data. Let's try implementing PUT
and DELETE
.
-
Add a button to
index.html
that makes a PUT request (you can choose the url). Send the stringupdated message
. Have the server, upon receiving this request, replace the contents ofhi_log.txt
with the updated message. -
Add a button to
index.html
that makes a DELETE request (you can choose the url). Have the server, upon receiving this request, delete thehi_log.txt
file.
- Set up a templating engine so you can write your pages in a templating language. If you don't know which one to pick some great ones are
Take a look at the file created for you in streams/streams.js
. This can be run using npm run streams
.
- Readable streams
- Create a readable stream to import the file
on-joy-and-sorrow-emoji.txt
- On the 'data' event, console.log the data received (what do you notice?)
- How can we decode this data so it shows up in the console?
- Update our console logs so ':)' is replaced with 'joy' and ':(' is replaced with 'sorrow'
- Create a readable stream to import the file
- Writable streams
- Create a writable stream exporting to
on-joy-and-sorrow-fixed.txt
- Pipe the readable stream to the writable stream
- Create a writable stream exporting to
- Transform streams implement a readable and writable interface for modifying input from readable streams
- Create a transform stream to modify incoming data, replacing ':)' with 'joy' and ':(' with 'sorrow'.
NOTE: The through2 library is a useful abstraction for this (it's already been imported for you) - Pipe the readable stream to the transform stream you just created, and then pipe the result to the writable stream
- Create a transform stream to modify incoming data, replacing ':)' with 'joy' and ':(' with 'sorrow'.