Node.js is an open-source, back-end (or server-side) environment for developing apps. It works across platforms and Node.js applications are written in JavaScript. Node.js provides a runtime environment that executes JavaScript code outside a web browser. In this module, we teach you how to use Node.js most effectively.
Below an overview of the week-by-week topics - click on the title to find more details.
1 - Node and Express 1012 - APIs in Node3 - WorkshopToday we’re going to build a Node.js Express Rest API example that supports Token Based Authentication with JWT (JSONWebToken). You’ll know:
What is CORS
What is Authentication
What is JSONWebToken
What are environment variables
What is password hashing
Appropriate Flow for User Sign-up & User Login with JWT Authentication
Node.js Express Architecture with CORS, Authentication & Authorization middlewares
How to configure Express routes to work with JWT
CORS stands for Cross-Origin Resource Sharing. It allows you to make requests from one website to another website in the browser, which is normally prohibited by another browser policy called the Same-Origin Policy (SOP).
CORS and SOP are both browser policies that have developed in response to issues of browser security and vulnerabilities.
The specific browser vulnerability that Same Origin Policy is meant to address is called “cross-site request forgery” (CSRF, or alternatively XSRF, don’t you love all these acronyms? XD ).
CORS allows servers to specify certain trusted ‘origins’ they are willing to permit requests from. Origins are defined as the combination of protocol (http or https), host (a domain like or an IP address) and port. Browsers which implement the CORS policy will include a HTTP header called ‘Origin’ in requests made with AJAX (or newer web APIs like Fetch).
Authentication is the process of verifying identity. A unique identifier is associated with a user which is the username or user id. Traditionally, we use a combination of username and password to authenticate a user.
User authentication plays a central role in almost everything we do online. From apps to hardware and websites, user accounts and logins are everywhere. Authentication is critical for verifying a user's identity online and for confirming permissions so individuals can perform privileged actions.
Let’s take a quick look at how we used to do authentication:
HTTP is a stateless protocol. That means it doesn’t remember anything from request to request. If you login for one request, you’ll be forgotten, and will need to login again to make another request. As you can imagine, this can get very annoying fast.
The old-school solution has been to create what’s called a “session”. A session is implemented in two parts:
An object stored on the server that remembers if a user is still logged in, a reference to their profile, etc.
A cookie on the client-side that stores some kind of ID that can be referenced on the server against the session object’s ID.
Cookie-based Auth:
If a user visits a web page (makes a request) and the server detects a session cookie, it will check if it currently has a session stored with the ID from the cookie, and if that object is still valid (whatever that means: not expired, not revoked, not blacklisted, etc). A cookie is a small file of letters and numbers downloaded on to your computer when you access certain websites.
If the session is still valid, it will respond with the requested web page (or data. If it finds a session object, that object can contain data and with that, the server can “remember” who you are and what you were doing (e.g. if this is an e-commerce store, what products you’ve added to our shopping cart).
If the session is not valid (or no session cookie was detected) it will respond with some sort of error message saying that the request is “unauthorized”.
This type of setup has worked pretty well for us since the web came out and since we’ve been visiting websites that do most of their “thinking” on the server side. Typically, this has been a conversation between the user’s front-end browser and a corresponding back-end server in a one-to-one relationship.
This setup still works, but these days we have many different situations that require different setups (e.g. multiple mobile native apps alongside large single-page web apps contacting multiple back-end services, that may be nothing more than json data without a webpage at all). In these types of scenarios, the cookie you get from one server, won’t correspond — or even be sent — to another server (let alone the problems that get created with CORS).
Sessions: need to be stored somewhere, either in memory, in a database and they need to be managed so that they are removed when they expire or are otherwise invalidated.
Poor Scalability: The session store needs to be scaled when scaling the server. The store uses up resources, and adds complexity.
Performance Issues: When the session needs to be stored on the server, a lot of database/store lookups need to happen on every request which can bog down the server.
What Is JSON?
JSON stands for JavaScript Object Notation. It is a text-based format for transmitting data across web applications. It stores information in an easy-to-access manner, both for developers and computers. It can be used as a data format by any programming language and is quickly becoming the preferred syntax for APIs.
What Are Tokens?
Now that you understand JSON as a data text format, you may be wondering what tokens are. To put it simply, a token is a string of data that represents something else, such as an identity. In the case of authentication, a non-JWT based token is a string of characters that allows the receiver to validate the sender’s identity. The important distinction here is lack of meaning within the characters themselves.
What Do JWTs Look Like?
JWTs differ from other web tokens in that they contain a set of claims. Claims are used to transmit information between two parties. What these claims are depends on the use case at hand. For example, a claim may assert who issued the token, how long it is valid for, or what permissions the client has been granted.
A JWT is a string made up of three parts, separated by dots (.), and serialized using base64. In the most common serialization format, compact serialization, the JWT looks something like this
The first section of the JWT is the header, which is a Base64-encoded string. If you decoded the header it would look something similar to this:
The header section contains the hashing algorithm, which was used to generate the sign and the type of the token.
The second section is the payload that contains the JSON object that was sent back to the user. Since this is only Base64-encoded, it can easily be decoded by anyone.
It is recommended not to include any sensitive data in JWTs, such as passwords or personally identifiable information.
Usually, the JWT body will look something like this, though it's not necessarily enforced:
Most of the time, the sub property will contain the ID of the user, the property iat, which is shorthand for issued at, is the timestamp of when the token is issued.
You may also see some common properties such as eat or exp, which is the expiration time of the token.
The final section is the signature of the token. This is generated by hashing the string base64UrlEncode(header) + "." + base64UrlEncode(payload) + secret using the algorithm that is mentioned in the header section.
The secret is a random string which only the server should know. No hash can be converted back to the original text and even a small change of the original string will result in a different hash. So the secret cannot be reverse-engineered.
When this signature sends back to the server it can verify that the client has not changed any details in the object.
According to the standards, the client should send this token to the server via the HTTP request in a header called Authorization with the form Bearer [JWT_TOKEN]. So the value of the Authorization header will look something like:
JWTs don’t use sessions, have no problem with native apps, and actually don’t even need special CSRF protections, and they work very well with CORS.
With JWT you register yourself with an app, much the same way you would with an old-school app, and you login with your credentials (e.g. username/password). But instead of making a session and setting a cookie, the server will send you a JSON Web Token instead. Now you can use that token to do whatever you want to do with the server (that you have authorization to do).
Think of it like a hotel key: you register at the front desk and they give you one of those plastic electronic keys that you can use to access your room, the pool, and the garage. But you can’t open other people’s rooms or go into the manager’s office. And, like a hotel key, when your stay has ended, you’re simply left with a useless piece of plastic (i.e. the token doesn’t do anything any more after it’s expired).
Environment variables are predetermined values that are typically used to make it possible to configure a value in your code from outside of your application.
You'll often find these variables stored in a file named with some kind of variation of .env.
How can I keep these .env files secure?
This is probably one of the more important points here – you need to ensure you're handling these files with care and not checking them into a git repository. If you expose these keys by uploading them to a public location by mistake, the internet could easily find these keys and people could abuse them for their own gains.
So how can we keep these secure? The easiest way is to add the environment file where you keep these keys to your .gitignore file.
To do this, simply open your existing .gitignore file or create a new one at the root of your repository and add the filename as a new line:
A hash is just a way to represent any data as a unique string of characters. You can hash anything: music, movies, your name, or this article. Metaphorically speaking, hashing is a way of assigning a “name” to your data. It allows you to take an input of any length and turn it into a string of characters that is always the same length. Obviously, there are many methods (algorithms) to do this.
A few of the most popular hashing algorithms:
MD5 – Given any data will return a unique 32 character hash.
SHA1 – Given any data will return a unique 40 character hash.
SHA256 – Given any data will return a unique 64 character hash; designed by the National Security Agency.
The reason hashing is secure is simple: hashing is a one way operation. It cannot be reversed.
bcrypt is an npm library that helps you hash passwords. You can read about as well as through this .
First, we create a folder for our project:
Then we initialize the application with a package.json file:
We need to install necessary modules: express, cors, dotenv, jsonwebtoken and bcrypt.
Run the command:
Important: You have to install nodemon globally in your system if you haven't done so already. Using this command npm i -g nodemon
Once all these packages are installed, add a script in package.json "start": "nodemon server.js"
The package.json file now looks like this:
In the project's root folder which is node-auth-project-migracode, let’s create a new server.js file:
Let me explain what we’ve just done:
1) import express and cors modules:
Express is for building the Rest APIs
express.json() helps to parse the request and create the req.body object
provides Express middleware to enable CORS
2) create an Express app, then add express.json() and cors middleware using app.use()method. Notice that we set origin http://localhost:3000.
3) define a GET route which is simple for test.
4) listen on port 4000 for incoming requests.
Note: we assign PORT variable equal to process.env.PORT || 4000 which means if PORT is defined already as an environment variable then it will be selected otherwise 4000 will be selected. We will create the .env file in a later step.
Now let’s run the app with command: nodemon server.js.
Open your browser with URL , you will see:
Since we have not learned how databases works, we will continue working with JSON files.
Lets create a JSON file with an empty array inside it where we will save the user data after user registration.
In the project's root folder which is node-auth-project-migracode, let’s create a new directory database with a file db.json using following command:
Now open this db.json file and create an empty array inside it like this:
When a client sends a request for an endpoint using an HTTP request (GET, POST, PUT, DELETE), we need to determine how the server will respond by setting up the routes.
We can separate our routes depending on the resources we want to access.
User Authentication:
POST /user/sign-up
POST /user/sign-in
POST /user/auth
In the project's root folder node-auth-project-migracode, let’s create a new directory routes with a file user.js using following command:
Let's create a user authentication endpoint in the user.js file we just created
node-auth-project-migracode/routes/user.js
Line 22: We create a salt using bcrypt. Salting is simply the addition of a unique, random string of characters known only to the site to each password before it is hashed. Typically, this “salt” is placed in front of each password.
Line 23: We hash the password provided by user using bcrypt and the salt we generated in the previous line.
First we need to create a secret which we will use for generating JWT token. Secret is just a long string which can contain anything.
In the project's root folder which is node-auth-project-migracode, let’s create a new file .env with a secret inside it using following command:
Now inside this file create a secret like this:
This is your secret to sign the JWT token. You should never share this secret, otherwise someone else could use it to forge JWT tokens to gain unauthorized access to your service. The more complex this access token is, the more secure your application will be.
In the project's root folder node-auth-project-migracode, let’s create a new directory utils with a file generateJWT.js using following command:
Now open this generateJWT.js file and create a function like this:
Lets import this function inside routes/user.js
Put the following code on line 7 in user.js file right before we create a router on line 8
At this point our user router is ready with one endpoint for user registration/sign-up. We will connect this user router to our server.js in the next step.
All we need now is to import the router right before we initialize our application using const app = express(); by using following code inside your server.js file
Hint: put this code in line 4
Once the router is imported we need to use this router in our application by writing following code before app.listen(...)
Hint: put this code in line 22 or 23
We will create a new POST request to localhost:4000/user/sign-up URL with a body in JSON format with three key-value pairs which we need for your registration. It will look like the following
Once you hit the send button, it will send a request to our server and make sure that the server is running and you are able to see this in your terminal
Once the request is sent with a name, email and password, we will receive a response back from our server which will look something like this in Postman
As you can see we have Status: 201 Created and we received an object with a token.
If we try to send the same request again we will receive something like this
This means that the user already exists and we can not create a new user with same email.
At this point our user registration endpoint is ready and we can move forward to create login/sign-in endpoint.
We have already done all the tedious part of setting up a server and creating a router. Now we just need to append a new endpoint in the existing user.js file inside routes directory.
Lets append the following code inside routes/user.js file
Hint: add it between sign-up endpoint and export statement which is the last line of code in the file.
We will create a new POST request to localhost:4000/user/sign-in URL with a body in JSON format with two key-value pairs that we need for login. It will look like the following:
Once you hit the send button, it will send a request to our server and make sure that the server is running and you are able to see this in your terminal
Once the request is sent with an email and password, we will receive a response back from our server which will look something like this in Postman
As you can see that the Status: 200 OK and we received an object with a token.
If we try to send a request with different password we will receive something like this
This means that the provided login credentials are incorrect and we have Status: 401 Unauthorized
At this point our user registration and login/sign-in endpoints are ready and we can move forward to create our last endpoint.
This endpoint is created to verify the user identity before sending back any resource to the user. Lets start by adding the following code in routes/user.js file
Hint: add it between sign-in endpoint and export statement which is the last line of code in the file.
As you might have already noticed, we have a new argument between "/auth" and (req, res) called authenticate. It is a custom middleware function which we will create in the next step. We will use this authenticate middleware in all the endpoints which we want to protect to verify user identity before sending back the requested resources.
In the project's root folder node-auth-project-migracode, let’s create a new directory middleware with a file authenticate.js using the following command:
Now open this authenticate.js file and create a function like this:
Line 7: We will receive an Authorization header from user with every request to a protected endpoint which requires user authentication. Without this Authorization header, user can not access any information.
Line 14: In this middleware, we read the value of the authorization header. Since the authorization header has a value in the format of Bearer [JWT_TOKEN], we have split the value by the space and separated the token.
Line 20: Then we have verified the token with JWT.
Line 22: Once verified, we attach the user object into the request and continue. Otherwise, we will send an error to the client.
Now lets import this middleware function inside routes/user.js
Put the following code on line 6 in user.js file right before we create a router on line 8
At this point our user router is ready with all three endpoints for user registration/sign-up, login/sign-in and authorization.
We will create a new POST request to the localhost:4000/user/auth URL with a Authorization header which we need for user verification. You will have to select Bearer Token from the drop-down under Authorization tab and paste the token (which you received after login or registration) on the right side of Token. It will look like the following
Once you hit the send button, it will send a request to our server and make sure that the server is running and you are able to see this in your terminal
Once the request is sent with a Authorization header containing Bearer Token, we will receive a response back from our server that will look something like this in Postman
As you can see that the Status: 200 OK and we received an object with a property isAuthenticated: true
If we try to send a request without Bearer Token we will receive something like this
This means that we cannot access protected endpoints that use the authenticate middleware without a Bearer Token and we have Status: 403 Forbidden
Now we can add this authenticate middleware to any endpoint which we want to protect and users will have to provide a token to access the resources of these endpoints.

Native Apps (or non-browser apps): Browsers handle cookies, but custom apps don’t (at least not easily), so a different kind of session mechanism is needed.
CSRF: If cookies are being used, extra security is needed to prevent cross-site request forgery attacks since the cookie will be automatically sent to the server with any request made from that site.
CORS: Cookies + CORS doesn’t work well across different domains (actually, real cross-domain doesn’t work at all).
Create a simple REST API using Express.
Explain what Postman is and how it works.
Working with GET Requests using Postman.
Working with POST Requests using Postman.
Communicating with the server.
Implement routing to return different resources depending on the URL.
Implement query parameters to return different content.
Node.js is an open-source* and cross-platform JavaScript runtime environment. The runtime environment is the environment in which a program or application is executed. It's the hardware and software infrastructure that supports the running of a particular codebase in real time.
Node.js runs the V8 JavaScript engine (the core of Google Chrome) outside of the browser. This allows Node.js to be very performant. A Node.js app runs in a single process, without creating a new thread for every request. Threads are a way for a program to divide (termed "split") itself into two or more simultaneously (or pseudo-simultaneously) running tasks.
Node.js has a unique advantage because millions of front-end developers that write JavaScript for the browser can write the server-side code in addition to the client-side code without the need to learn a completely different language.
*Open source is a term that originally referred to open source software (OSS). Open source software is code that is designed to be publicly accessible—anyone can see, modify, and distribute the code as they see fit.
Express.js or simply Express is a minimal, open source and flexible Node.js web framework designed to make developing websites, web apps, and APIs much easier. It lets you structure a web application to handle multiple different http requests at a specific URL (Uniform Resource Locator).
Express helps you respond to requests with route support so that you may write responses to specific URLs. The nice thing about it is that it’s very simple and it’s open-source.
A route is a section of Express code that links an HTTP action ( GET, POST, PUT, DELETE, etc.) to a URL path/pattern, and a function that is called to handle that pattern.
The REST abbreviation stands for representational state transfer. The definition can be conveyed with simpler words: data presentation for a client in the format that is convenient for it. One of the main points that you need to understand and remember is that REST is not a standard or protocol: it is an approach to, or architectural style for, writing APIs.
API stands for Application Programming Interface. It is a way to provide information for other applications. Basically, it enables communication between applications.
REST is an architectural style, and RESTful is the interpretation of it. This means that if your back-end server has a REST API and you make client-side requests (from a website/application) to this API, then your client is RESTful.
RESTful API best practices come down to four essential operations:
receiving data in a convenient format
creating new data
updating data
deleting data
You can keep pressing 'enter' through all of the options that you will see in your terminal. After this, you will see that a file called package.json has been created automatically.
The terminal will look something like this once you execute npm init
This is the file where we will configure all our routes.
Line 1: We already installed Express in Step 3, but we need to make sure it is included in this file specifically so we can use its methods. In Node.js, when you want to use a package in another file, you must require it. You can think of require as a need to import something. You can instantiate the package at the top of your file. Instantiate means creating an example or single occurrence of something and we assign that example or instance to a variable, for example "express"
Line 2: To initialise/create our server, we need to call the express()function. This will perform a set of operations behind the scene and create an Express application for us and we can assign it to the app variable.
Line 4: app.getis saying that when it gets that route, it should give the response that is specified in the function. It takes in two arguments: (1) the URL (2) the function that tells Express what to send back to the person making the request.
Line 8: One more step left: we need to set a port for our server to listen to. Think of a port as a door number; any requests that comes to the server will come via that door. Setting a port will allow us to find out where our server is running. We use the app.listenmethod to do this. This method takes two arguments: a port and a callback function telling it what to do once the server is running.
Note : If the port 3000 is in use (e.g. you already have a project running on port 3000), then your system will throw an error. In this case you will have to manually change port in Line 8 app.listen(3001) or app.listen(3002) or app.listen(3003) till you find the next available port and run the server with that.
When you run npm install package_name in the terminal, the package you want gets added as one of the dependencies into the package.json file:
The syntax it uses is semantic versioning (SEMVER), which means you can specify which version of the dependency you would like.
A star symbol (*) means it can be any version, whichever is the latest one.
A carrot symbol (^) prior to the version means I want that version or anything newer.
SEMVER : Given a version number (e.g "express": "4.15.3" ) MAJOR.MINOR.PATCH, increment the:
( "express": "4.x.x" ) MAJOR version when you make incompatible API changes,
( "express": "x.15.x" ) MINOR version when you add functionality in a backwards compatible manner, and
( "express": "x.x.3" ) PATCH version when you make backwards compatible bug fixes.
Note : We never installed "jade" and "underscore". These are mentioned for explaining SEMVER and you can ignore these packages here.
Go to your browser and type the following URL (use port 3000 or whichever port you used in the previous step)
You should see “Hello Express” on your screen.
Note: Whenever you make any changes in your project, you will have to manually restart the server. You can do this by pressingctrl c on your keyboard to stop the current server and then repeat the step to start the server:node server.js
Install the package nodemon globally on your machine by using following command:
When you install an npm package using the -g flag, that package gets installed in your system instead of in your program, and you do not need to install it ever again. Now you can usenodemon instead ofnode when running your app locally. Nodemon monitors your app for any changes and automatically restarts your application when you change anything. With thenode command, you have to restart manually after you make changes.
Go to your browser and go to port 3000 (or whichever port you used in step 5)
You should see “Hello Express”.
package.json has various sections. scripts is one of them, and it allows you to write an npm script that you can run using npm run <script-name>.
Typically we can have a scripts section. The scripts are defined as JSON with the key-value script. Key is the command name that we will use to run and value is the command we want to run.
To exit the running the server, type crtl c. Instead of running the server with nodemon server.js every time, we can create an alias (a shortcut) for it in package.json.
Under the scripts property, add "start: nodemon server.js".
We can now run our server using npm start which will be an alias for nodemon server.js.Go to the terminal and type npm start and make sure that the server still runs.
Postman is a scalable API testing tool which started in 2012 to simplify the API workflow in testing and development.
Developers use Postman for the following reasons:
Accessibility - To use the Postman tool, a developer can log into their own account, making it easy to access files anytime, anywhere, as long as a Postman application is installed on the computer.
Use of Collections - Postman lets users create collections for their Postman API calls. Each collection can have sub-folders and multiple requests. This helps in organizing your test suites.
Collaboration - Collections and environments can be imported or exported, making it easy to share files. A direct link can also be used to share collections.
Debugging - Postman console helps to check what data has been retrieved, making it easy to debug tests.
Continuous Integration - With its ability to support continuous integration, development practices are maintained.
Postman is an Open Source tool and can be easily downloaded. Here are the steps to install:
Step 1) Go to https://www.postman.com/downloads/ and choose your desired platform (Mac, Windows or Linux). Click Download
Step 2) The message Your download is in progress'should now display on the Apps page. Once the Postman download is completed, click on Run
Step 3) Installation Starts
Step 4) In the next window, signup for a Postman Account
NOTE: There are two ways to sign up for a Postman account. One is to create a new Postman account, and the other is to use a Google account. Though Postman allows users to use the tool without logging in, signing up ensures that your collection is saved and can be accessed for later use.
Step 5) Select the workspace tools you need and click Save My Preferences
Step 6) You will see the Startup Screen
Below is the Postman Workspace. Let's explore the step by step process on How to use Postman and different features of the Postman tool!
Note: Don't worry about all the features mentioned below, right now you just need a few.
New - This is where you will create a new request, collection or environment.
Import - This is used to import a collection or environment. There are options such as import from file, folder, link or paste raw text.
Runner - Automation tests can be executed through the Collection Runner. This will be discussed further in the next lesson.
Open New - Open a new tab, Postman Window or Runner Window by clicking this button.
My Workspace - You can create a new workspace individually or as a team.
Invite - Collaborate in a workspace by inviting team members.
History - Past requests that you have sent will be displayed in History. This makes it easy to track actions that you have done.
Collections - Organize your test suite by creating collections. Each collection may have sub-folders and multiple requests. A request or folder can be duplicated as well.
Request tab - This displays the title of the request you are working on. By default, "Untitled Request" would be displayed for requests without titles.
HTTP Request - Clicking this will display a drop-down list of different requests such as GET, POST, COPY, DELETE, etc. In Postman API testing, the most commonly used requests are GET and POST.
Request URL - Also known as an endpoint, this is where you will identify the link to where the API will communicate with.
Save - If there are changes to a request, clicking save is a must so that new changes will not be lost or overwritten.
Params - This is where you will write parameters needed for a request such as key values.
Authorization - In order to access APIs, proper authorization is needed. It may be in the form of a username and password, bearer token, etc.
Headers - You can set headers such as content type JSON, depending on the needs of the organization.
Body - This is where you can customize details in a request commonly used in POST request.
Pre-request Script - This is a script that will be executed before the request. Usually, pre-request scripts for the setting environment are used to ensure that tests will be run in the correct environment.
Tests - These are scripts executed during the request. It is important to have tests as it sets up checkpoints to verify if response status is OK, retrieved data is as expected and other tests.
GET requests are used to retrieve information from the given URL. There will be no changes done to the endpoint.
We will use the following URL for all examples in this Postman tutorial. It is a website for testing HTTP requests.
In the workspace
Set your HTTP request to GET.
Copy the link above in the request URL field,
Click Send
You will see a 200 OK message
There should be 10 user results in the body. This means that your test has run successfully.
Note: There may be cases that a Postman GET request is unsuccessful. It can be due to an invalid request URL, or that authentication is needed.
POST requests are different from GET request because there is data manipulation: the user adds data to the endpoint. Using the same data from the previous tutorial on the GET request, let's now add our own user.
Step 1) Click a new tab to create a new request.
Step 2) In the new tab
Set your HTTP request to POST.
Input the same link in the request URL: https://jsonplaceholder.typicode.com/users
Switch to the Body tab
Step 3) In Body,
Click raw
Select JSON
Step 4) Copy and paste one user result from the previous GET request (see example below). Ensure that the code has been copied correctly with paired curly braces and brackets. Changeid to 11 andname to any desired name. You can also change other details like the address.
Note: An online POST request should have the correct format to ensure that the requested data will be created. It is a good practice to use GET first to check the JSON format of the request. You can use tools like https://jsonformatter.curiousconcept.com/
Step 5) Next,
Click Send.
Status: 201 Created should be displayed
The posted data are showing up in the body.
Now that we've built the server, we need to communicate with it. We are going to control the server with handler functions.
When a request reaches the server, we need a way of responding to it. In comes the handler function. The handler function is a function that receives requests and handles them, hence the name.
The handler function is always called with a req and res (= request and response) object. The response object is what gets sent back to the client. It contains the information that gets displayed in the web page. You can decide what to send back in your response.
What does a handler function look like in Express?
The get() method is one of the methods used to define a handler function in Express. It takes two parameters: the endpoint at which to trigger an action (we'll explain more about this in the next step), and the handler function that specifies exactly what to do. Here's a simple "Hello World!" example:
Here, we are telling our server to respond with "Hello World!" when someone tries to access the webpage.
Let us add a handler function to send back a message to the client. To do that, we're going to use the Express send() method. This will update the response object with the message.
Update your handler function like so:
Exercise: Try to
console.logtherequestobject inside the handler function. Send the request again with Postman, then go to your terminal to see what it looks like. You should see a lot of data coming through.
Now, open Postman, and send a GET request to http://localhost:3000. If you see your message in Postman, congratulations! You have just sent your first response from the server.
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!".
Try typing http://localhost:3000/node and see what happens.
By making use of endpoints, we can make the server send different responses for different requests. This concept is called routing.
An endpoint is the part of the URL which comes after /. For example: In this URL https://jsonplaceholder.typicode.com/users everything before /users is the base URL and /users is the endpoint. It's the URL which we used in Postman example to send a request.
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.
For example:
Exercise: Add some code so that your server sends one message when the endpoint is
/nodeand another one when it's/migracode.
So what is a query parameter?
In simple terms, a query string is the part of a URL after the question mark (?). It is meant to send small amounts of information to the server via the URL. This information is used as parameters to query a database or to filter results.
Here is an example of a URL with query strings attached:
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.
For example:
{
"alg": "HS256",
"typ": "JWT"
}{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o# Inside .gitignore
.envmkdir node-auth-project-migracode
cd node-auth-project-migracodenpm init
name: (auth-project-migracode)
version: (1.0.0)
description: Authentication using JWT in REST API
entry point: (index.js) server.js
test command:
git repository:
author: yogi
license: ISC
Is this ok? (yes) yesnpm install express dotenv cors jsonwebtoken bcrypt{
"name": "auth-project-migracode",
"version": "1.0.0",
"description": "Authentication using JWT in REST API",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon server.js"
},
"author": "yogi",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.0.1",
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1"
}
}const express = require("express");
const cors = require("cors");
// initializing express application
const app = express();
// parse requests of content-type - application/json
app.use(express.json());
const corsOptions = {
origin: "http://localhost:3000"
};
app.use(cors(corsOptions)); // enable CORS
// simple route
app.get("/", (req, res) => {
res.json({ message: "Welcome to MigraCode Auth application." });
});
// set port, listen for requests
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
mkdir database
cd database
touch db.json[]mkdir routes
cd routes
touch user.jsconst express = require("express");
const bcrypt = require("bcrypt"); // bcrypt is used to hash password before saving it to database
const fs = require("fs"); // fs is node's inbuilt file system module used to manage files
const usersDb = require("../database/db.json"); // import existing data from db.json file
const router = express.Router(); // we create a new router using express's inbuilt Router method
// user registration / sign-up
router.post("/sign-up", async (req, res) => {
const { name, email, password } = req.body;
try {
const user = await usersDb.filter(user => user.email === email);
if (user.length > 0) {
return res.status(400).json({error: "User already exist!"});
}
const salt = await bcrypt.genSalt(10);
const bcryptPassword = await bcrypt.hash(password, salt);
let newUser = {
id: usersDb.length,
name: name,
email: email,
password: bcryptPassword
}
usersDb.push(newUser); // we add newUser to usersDb array
// we save the updated array to db.json file by using fs module of node
await fs.writeFileSync('./database/db.json', JSON.stringify(usersDb));
/* Once the user registration is done successfully, we will generate a
jsonwebtoken and send it back to user. This token will be used for
accessing other resources to verify identity of the user.
The following generateJWT function does not exist till now but we
will create it in the next step. */
const jwtToken = generateJWT(newUser.id);
return res.status(201).send({ jwtToken: jwtToken, isAuthenticated: true});
} catch (error) {
console.error(error.message);
res.status(500).send({error: error.message});
}
});
module.exports = router; // we need to export this router to implement it inside our server.js file
touch .envjwtSecret = "migracodeAuthJan2021"mkdir utils
cd utils
touch generateJWT.jsconst jwt = require("jsonwebtoken");
require("dotenv").config(); // here we use dotenv module which we installed in the begining to access environment variables from .env file
function generateJWT(user_id) {
// payload is just an object which usually contains some information about user but not confidential information such as password.
const payload = {
user: {
id: user_id
}
};
return jwt.sign(payload, process.env.jwtSecret, { expiresIn: "1h" });
}
module.exports = generateJWT; // we export this function to use it inside routes/user.jsconst generateJWT = require("../utils/generateJWT");const user = require("./routes/user");app.use("/user", user);
// user sign-in / login
router.post("/sign-in", async (req, res) => {
const { email, password } = req.body;
try {
const user = await usersDb.filter(user => user.email === email);
if (user.length === 0) {
return res.status(401).json({error: "Invalid Credential", isAuthenticated: false});
}
// if the user exist then we will compare the password provided by user with the hashed password we stored during user registration
const isValidPassword = await bcrypt.compare(
password,
user[0].password
);
if (!isValidPassword) {
return res.status(401).json({error: "Invalid Credential", isAuthenticated: false});
}
// if the password matches with hashed password then we generate a new token and send it back to user
const jwtToken = generateJWT(user[0].id);
return res.status(200).send({ jwtToken, isAuthenticated: true });
} catch (error) {
console.error(error.message);
res.status(500).send({error: error.message});
}
});
// user authorization
router.post("/auth", authenticate, (req, res) => {
try {
res.status(200).send({isAuthenticated: true});
} catch (error) {
console.error(error.message);
res.status(500).send({error: error.message, isAuthenticated: false});
}
});mkdir middleware
cd middleware
touch authenticate.jsconst jwt = require("jsonwebtoken");
require("dotenv").config();
function authenticate (req, res, next) {
// Get token from request headers
let token = req.header("authorization");
// Check if token exists
if (!token) {
return res.status(403).send({ message: "authorization denied", isAuthenticated: false });
}
token = token.split(" ")[1];
// Verify token using jwt
try {
/* this will return the user id (user:{id: user_id}) which we
provided as payload while generating JWT token */
const verify = jwt.verify(token, process.env.jwtSecret);
req.user = verify.user;
next();
} catch (err) {
res.status(401).send({ message: "Token is not valid", isAuthenticated: false });
}
};
module.exports = authenticate; // we export it to use it inside user routerconst authenticate = require("../middleware/authenticate");mkdir node-web-servercd node-web-server
npm initnpm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (new)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /home/yogi/new/package.json:
{
"name": "new",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this OK? (yes)npm install expresstouch server.jsconst express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello Express')
});
app.listen(3000, () => console.log("Server is up and running")){
“name”: “node-web-server”,
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"dependencies": {
"express": "4.15.3",
"jade": "*",
"underscore": "^1.7.0"
}
}node server.jshttp://localhost:3000/npm install -g nodemonnodemon server.jshttp://localhost:3000/"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon server.js"
}https://jsonplaceholder.typicode.com/users[
{
"id": 11,
"name": "Krishna Rungta",
"username": "Bret",
"email": "[email protected]",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
}
]// req is the Request object, res is the Response object
// (these are just variable names, they can be anything but it's a convention to call them req and res)
app.get("/", (req, res) => {
res.send("Hello World!");
});const express = require("express");
const app = express();
app.get("/", function (req, res) {
res.send("Yay Node!");
});
app.listen(3000, () => console.log("Server is up and running"))app.get("/", function (req, res) {
res.send("Hello World!");
});
app.get("/chocolate", function (req, res) {
res.send("Mm chocolate :O");
});app.get("/", function (req, res) {
let searchQuery = req.query.search;
res.send("Hello World! You searched for " + searchQuery);
});



By the end of this lesson students should be able to:
Define what each part of CRUD is and what it does
Process a GET request using Express and Node to retrieve data from memory
Process a POST request using Express and Node and store data in memory
Process a PUT request using Express and Node and update existing data in memory
Process a DELETE request using Express and Node to remove data from memory
Install a third party library using npm
What is a middleware
We will now build a CRUD API. CRUD stands for Create, Retrieve, Update, Delete. If you think about it, this is what most applications do:
Create some "resources"
Retrieve them (GET them)This step will require you to use POSTMAN because our project does not have client interface (front-end part) with a HTML form for creating new quotes.
Update them
Delete them
Below are three in-class exercises that can be used to demonstrate parts of the API workshop below.
This is an instructor-led exercise that can be used to show how we can retrieve an element by ID using a GET request.
Objective
Change a quote API server to allow GETting a quote according to the given ID.
The id should be given in the URL structure like this:
/quotes/2
You should use the starting project: . This is because this project has quotes with IDs.
When you fork and clone the starting project, run npm install to install required dependencies.
This is an instructor-led exercise that can be used to show how we can add an element to an array
Objective
Change a quote API server to allow POSTs of new quotes.
The new quotes should be added to your quotes list, which is just an array in memory.
You can assume the POSTed quotes are all in the correct JSON format.
The route should use the HTTP method POST and should use the URL:
/quotes
This is an instructor-led exercise that can be used to show how we can update existing data in memory using a PUT request.
Objective
Change the quote API server to allow updating a quote according to the given ID.
The route should use the HTTP method PUT and ID should be given in the URL structure like this:
/quotes/2
This step will require you to use POSTMAN because our project does not have client interface (front-end part) with a HTML form for updating quotes.
This is an instructor-led exercise that can be used to show how we can remove an element to an array
Objective
Change a quote API server to allow updating a quote according to the given ID.
The id should be given in the URL structure like this:
/quotes/2
You should use the delete HTTP method.
You can use this to help you.
API stands for Application Programming Interface.
Read this description of what an API does from .
Think of an API like a menu in a restaurant. The menu provides a list of dishes you can order, along with a description of each dish. When you specify what menu items you want, the restaurant’s kitchen does the work and provides you with some finished dishes. You don’t know exactly how the restaurant prepares that food, and you don’t really need to. Similarly, an API lists a bunch of operations that developers can use, along with a description of what they do. The developer doesn’t necessarily need to know how, for example, an operating system builds and presents a “Save As” dialog box. They just need to know that it’s available for use in their app.
An API does not have to be web-based. But in our work, since we are doing web development, we will work only with web-based APIs (also referred to as Web Services), and we will communicate with those services using the protocol for the Web: HTTP.
Checkpoint: Let us recap what we know about HTTP before continuing.
Our API will manage Beyoncé albums:
Create a new album,
Retrieve a list of albums or a single album,
Update an existing album's information
Delete an album
We will build these endpoints:
GET /albums should return all the albums GET /albums/:albumId should return a single album (that matches the passed albumId) POST /albums should save a new album PUT /albums/:albumId should update the album (that matches the passed albumId) DELETE /albums/:albumId should delete the album (that matches the passed albumId).
In server.js Add the endpoint for GET /albums.
Test the endpoint with Postman. GET /albums should return a JSON reply with the array we specified.
Add another item to the array and test that the GET /albums returns three items.
Complete in-class (1) GET Exercise at this point
Sometimes, we do not want to list all the information in one request, maybe we only want to get the information related to a single album. Imagine if we have a page to display the details of one album, we could call the server and get all albums then filter the one we need client-side. Would it not be more effective to tell the server to just return the one album we are interested in?
Let us add a new endpoint to return only a single album GET /albums/:albumId. In this case, albumId will tell us what album we can return so the call will be something like GET /albums/10 and that will return the album with that has albumId 10.
This endpoint has something different. The endpoint /albums/:albumId has a dynamic part, because the albumId will vary depending on what the client sends. If we call /albums/12 then albumId is 12, and if we call /albums/10 then we will return the album with albumId 10, and so on.
How can we achieve that using express - req.params
These are properties attached to the URL named route parameters. You prefix the parameter name with a colon (:) when writing your routes.
For instance,
To send the parameter from the client, just replace its name with the value
Tip :- Install nodemon following previous week's
Complete in-class (2) Post Exercise at this point
Our analogy with the Restaurant menu is somewhat incomplete. In a restaurant, we only GET items from the menu. In the world of APIs, we also have the possibility to create items, we can provide ingredients to create a new dish. In this case, we provide some data (a payload) and we use a different verb POST (Create) as opposed to GET.
POST /albums should save a new album and return 200 with JSON { success: true } to the user.
Let's start by testing using Postman. Do a POST request to the endpoint and make sure it prints the console.log message we have added.
In Postman, change the request
methodtoPOSTinstead ofGETand test our endpoint. It should log the message to the terminal but the request will hang because we did not end it, i.e. we did not sayres.send(something)
So what format does the client send the data with? It is up to us, but since we already are familiar with json, let us use it.
In order for our server-side to receive and use the data sent by the client. We will need to use a middleware. Lets take a pause to learn about middleware and then we will come back to this exercise.
Middleware is just a function which gives you access to req and res in the apps request-> response cycle.
There are several important things to point out here:
Middleware functions usually have 3 standard params req, res, and next. The first two are objects, the last is a function that will call the next middleware function, if there is one.
Usually there is a middleware chain, meaning a chain of functions that are called one after the other, with the last function sending the response back to the browser. So we get the request from the browser, make any modifications and data additions, and then send a response back.
This is where middleware is the most useful.
When we run the above code, and request the /user/someName route, the server will check to see if the user is already logged in. If they are not, the server tells the browser to redirect to the /login route.
Now that we know what is a middleware function, lets continue with the exercise.
The express.json() function is a built-in middleware function in Express. It parses incoming requests with JSON payloads and is based on body-parser. It makes it easier for our endpoints to receive and understand different formats of data.
Now we will receive the data as req.body.
Exercise: Use Postman to
POSTthis data to/albumsendpoint.
Finish the code for the route
POST /albumsto add the album data to the albums list (how to amend an array?).
Complete in-class (3) DELETE Exercise at this point
Lets look back at our original objectives.
DELETE /albums/:albumIdshould delete the album that matches the passed albumId.
This means that DELETE /albums/2 should delete an album with the id 2 and return 200 with JSON { success: true } to the user.
The code will look like this:
Can you work out how to remove an album using this code?
next() (unless it’s the last function in the chain) or the request will just hang and eventually timeout. In the browser this will manifest as a really long spinner before a message of “connection timed out” or similar.Any changes you make to req or res will be available in the next middleware function.
req and res are unique for each request. Meaning that the changes you make to req or res in one request will not be reflected in a new request.
const albumsData = [
{
albumId: "10",
artistName: "Beyoncé",
collectionName: "Lemonade",
artworkUrl100:
"http://is1.mzstatic.com/image/thumb/Music20/v4/23/c1/9e/23c19e53-783f-ae47-7212-03cc9998bd84/source/100x100bb.jpg",
releaseDate: "2016-04-25T07:00:00Z",
primaryGenreName: "Pop",
url:
"https://www.youtube.com/embed/PeonBmeFR8o?rel=0&controls=0&showinfo=0",
},
{
albumId: "11",
artistName: "Beyoncé",
collectionName: "Dangerously In Love",
artworkUrl100:
"http://is1.mzstatic.com/image/thumb/Music/v4/18/93/6d/18936d85-8f6b-7597-87ef-62c4c5211298/source/100x100bb.jpg",
releaseDate: "2003-06-24T07:00:00Z",
primaryGenreName: "Pop",
url:
"https://www.youtube.com/embed/ViwtNLUqkMY?rel=0&controls=0&showinfo=0",
},
];
app.get("/albums", function (req, res) {
res.send(albumsData);
}); app.get("/albums/:albumId", (req, res) => {
console.log(req.params.albumId)
}) GET http://localhost:3000/albums/123456app.get("/albums/:albumId", function (req, res) {
// req.params.albumId will match the value in the url after /albums/
console.log(req.params.albumId);
// now we can use the value for req.params.albumId to find the album requested
// how do we "find" something in an array
// finish the code yourself - it should end with res.send(album) where album is the single album you found based on the id
});// notice .post (not .get)
app.post("/albums", function (req, res) {
console.log("POST /albums route");
});app.use(express.json()); // before our routes definitionapp.post("/albums", function (req, res) {
console.log("POST /albums route");
console.log(req.body);
});{
"albumId": "13",
"artistName": "Beyoncé",
"collectionName": "B'Day (Deluxe Edition)",
"artworkUrl100": "http://is5.mzstatic.com/image/thumb/Music/v4/6c/fc/6a/6cfc6a13-0633-f96b-9d72-cf56774beb4b/source/100x100bb.jpg",
"releaseDate": "2007-05-29T07:00:00Z",
"primaryGenreName": "Pop",
"url": "https://www.youtube.com/embed/RQ9BWndKEgs?rel=0&controls=0&showinfo=0"
}// notice .delete
app.delete("/albums/:albumID", function (req, res) {
console.log("DELETE /albums route");
});

































