All pages
Powered by GitBook
1 of 4

Loading...

Loading...

Loading...

Loading...

Node.js

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 - Workshop

3 - Workshop

Today 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

What is CORS

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

What is Authentication

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:

  1. An object stored on the server that remembers if a user is still logged in, a reference to their profile, etc.

  2. 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).

Drawbacks With Cookie-based Auth

  • 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 JSONWebToken

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:

JSON Web Tokens Are Better

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

What are environment variables

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:

What is password hashing?

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 .

Workshop JWT Authentication Flow for User Sign-up & User Login

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:

Setup Express web server

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:

Database / Data store

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:

Define Routes

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:

Registration endpoint

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.

JWT Secret

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.

JWT Generator

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.

Implement User Router in server.js

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

Test User Registration in Postman

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.

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.

Test User Login/Sign-in in Postman

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.

User Authorization 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.

Authenticate Middleware

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.

Test User Authorization in Postman

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.

1 - Node and Express 101

Learning Objectives

By the end of this lesson students should be able to:

  • Explain what Node.js is.

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

  • www.example.com
    bcrypt in Wikipedia
    link
    cors
    http://localhost:4000/
    Explain what Express is.
  • 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.

  • What is Node.js?

    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.

    What is Express?

    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.

    Creating a simple Rest API

    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

    Get started

    Step 1: Go to the terminal and create a folder called node-web-server

    Step 2: Go inside the project and generate the package.json file using npm init

    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

    Step 3: Install Express

    Step 4: Create a file called server.js in the root/main project folder ( e.g. node-web-server )

    This is the file where we will configure all our routes.

    Step 5: Paste the following code in your server.js file:

    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:

    1. ( "express": "4.x.x" ) MAJOR version when you make incompatible API changes,

    2. ( "express": "x.15.x" ) MINOR version when you add functionality in a backwards compatible manner, and

    3. ( "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.

    Step 6: To run the application, change into the root directory of the project and type the following in the terminal:

    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

    Step 7: Setting up a server to listen to changes automatically

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

    Step 8: Npm Scripts

    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.

    What is Postman

    Postman is a scalable API testing tool which started in 2012 to simplify the API workflow in testing and development.

    Why Use Postman?

    Developers use Postman for the following reasons:

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

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

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

    4. Debugging - Postman console helps to check what data has been retrieved, making it easy to debug tests.

    5. Continuous Integration - With its ability to support continuous integration, development practices are maintained.

    How to download and install Postman

    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

    How to use Postman to execute APIs

    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.

    1. New - This is where you will create a new request, collection or environment.

    2. Import - This is used to import a collection or environment. There are options such as import from file, folder, link or paste raw text.

    3. Runner - Automation tests can be executed through the Collection Runner. This will be discussed further in the next lesson.

    4. Open New - Open a new tab, Postman Window or Runner Window by clicking this button.

    5. My Workspace - You can create a new workspace individually or as a team.

    6. Invite - Collaborate in a workspace by inviting team members.

    7. History - Past requests that you have sent will be displayed in History. This makes it easy to track actions that you have done.

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

    9. Request tab - This displays the title of the request you are working on. By default, "Untitled Request" would be displayed for requests without titles.

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

    11. Request URL - Also known as an endpoint, this is where you will identify the link to where the API will communicate with.

    12. Save - If there are changes to a request, clicking save is a must so that new changes will not be lost or overwritten.

    13. Params - This is where you will write parameters needed for a request such as key values.

    14. Authorization - In order to access APIs, proper authorization is needed. It may be in the form of a username and password, bearer token, etc.

    15. Headers - You can set headers such as content type JSON, depending on the needs of the organization.

    16. Body - This is where you can customize details in a request commonly used in POST request.

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

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

    Working with GET requests using Postman

    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

    1. Set your HTTP request to GET.

    2. Copy the link above in the request URL field,

    3. Click Send

    4. You will see a 200 OK message

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

    Working with POST Requests using Postman

    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

    1. Set your HTTP request to POST.

    2. Input the same link in the request URL: https://jsonplaceholder.typicode.com/users

    3. Switch to the Body tab

    Step 3) In Body,

    1. Click raw

    2. 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,

    1. Click Send.

    2. Status: 201 Created should be displayed

    3. The posted data are showing up in the body.

    Communicating with the server

    Now that we've built the server, we need to communicate with it. We are going to control the server with handler functions.

    What is a handler function?

    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.

    1. Create your own handler function

    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.log the request object 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.

    2. Check it out in Postman

    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.

    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!".

    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.

    What is an endpoint?

    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.

    What are the elements of a URL?

    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.

    For example:

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

    Query Parameters

    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:

    https://stackabuse.com/?page=2&limit=3

    1. Detect Query Parameters

    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: Follow the instructions of node-challenge-calculator

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022
    }
    Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o
    # Inside .gitignore
    .env
    mkdir node-auth-project-migracode
    cd node-auth-project-migracode
    npm 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) yes
    npm 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.js
    const 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 .env
    jwtSecret = "migracodeAuthJan2021"
    mkdir utils
    cd utils
    touch generateJWT.js
    const 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.js
    const 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.js
    const 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 router
    const authenticate = require("../middleware/authenticate");
    mkdir node-web-server
    cd node-web-server
    npm init
    npm 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 express
    touch server.js
    const 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.js
    http://localhost:3000/
    npm install -g nodemon
    nodemon server.js
    http://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);
    });

    2 - APIs in Node

    Learning Objectives

    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

    CRUD Continued

    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.

    (1) Get Exercise

    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.

    (2) Post Exercise

    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

    (3) Put Exercise

    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.

    (4) Delete Exercise

    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.

    Workshop

    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.

    Objective

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

    GET /Albums

    1. In server.js Add the endpoint for GET /albums.

    1. Test the endpoint with Postman. GET /albums should return a JSON reply with the array we specified.

    2. Add another item to the array and test that the GET /albums returns three items.

    Step 1: GET /albums/:albumId

    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

    Step 2: Add a new album

    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 method to POST instead of GET and 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 say res.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.

    What is a Middleware

    Middleware is just a function which gives you access to req and res in the apps request-> response cycle.

    What does a middleware function look like?

    There are several important things to point out here:

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

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

    How do I write my own middleware for certain routes?

    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 POST this data to /albums endpoint.

    Finish the code for the route POST /albums to add the album data to the albums list (how to amend an array?).

    Step 3: Delete an album

    Complete in-class (3) DELETE Exercise at this point

    Lets look back at our original objectives.

    DELETE /albums/:albumId should 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?

    You must call 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.

  • node-quotes-api
    Express Cheatsheet
    How To Geek
    guide
    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&amp;controls=0&amp;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&amp;controls=0&amp;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/123456
    app.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 definition
    app.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&amp;controls=0&amp;showinfo=0"
    }
    // notice .delete
    app.delete("/albums/:albumID", function (req, res) {
      console.log("DELETE /albums route");
    });