The provided text is a comprehensive guide to building a RESTful API using Node.js and the Express framework. It covers fundamental concepts like handling different HTTP request methods (GET, POST, PUT, PATCH, DELETE), setting up routes and middleware, managing request and response objects, and implementing user authentication using Express Session and Passport. The text further explains how to integrate with a MongoDB database using Mongoose for data persistence and introduces unit and integration testing with Jest.
Express.js Study Guide
Quiz
- Explain the purpose of package.json and describe the significance of the type: “module” property and the start script.
- What is the role of the express() function, and how is it used to create an Express application instance? Describe the app.listen() method.
- Define what a route is in the context of Express.js. Explain the difference between the base route and other specific routes.
- Describe HTTP verbs (methods) and provide at least three examples. How are they used in Express to handle different types of requests?
- Explain the purpose and syntax of app.get(). What are the two primary arguments it accepts, and what do they represent?
- What are route parameters, and how are they defined and accessed in Express routes? Provide a simple example of a route with a parameter.
- Explain the concept of middleware in Express.js. What are the arguments passed to a middleware function, and what is the significance of the next() function?
- Describe the two ways middleware can be registered in Express.js. How does the order of middleware registration matter?
- What is an Express Router, and why is it useful for organizing routes in a larger application? Briefly explain how to create and register a Router.
- Explain the purpose of HTTP cookies. How can you set a cookie in an Express response and access cookies in a request?
Quiz Answer Key
- package.json is a manifest file for Node.js projects that contains metadata about the project, including its name, version, dependencies, and scripts. Setting type: “module” enables the use of ECMAScript Modules (ESM) with import and export statements. The start script defines a command to run the application in a production-like environment using the node command.
- The express() function, when called, creates a new instance of the Express application. This instance, typically assigned to the app variable, provides methods for defining routes, middleware, and other application settings. The app.listen() method starts the Express server on a specified port, making it listen for incoming HTTP requests. It takes the port number and an optional callback function that executes once the server has started.
- A route in Express.js is a specific path on the server that is associated with a particular handler function. The base route is the root path of the application (e.g., /), while other specific routes are defined by appending segments to the base URL (e.g., /users, /products). Each route is designed to handle requests to that specific path.
- HTTP verbs (or methods) indicate the type of action the client wants to perform on the server’s resource. Examples include GET (retrieve data), POST (create new data), PUT (update existing data), PATCH (partially update existing data), and DELETE (remove data). In Express, different methods like app.get(), app.post(), etc., are used to define route handlers for specific HTTP verbs.
- app.get() is used to define a route that handles HTTP GET requests to a specific path. The first argument is a string specifying the path (route) to match. The second argument is the request handler, which is a function that takes two arguments: the request object (containing information about the incoming request) and the response object (used to send a response back to the client).
- Route parameters are dynamic segments in a route path used to capture values from the URL. They are defined by prefixing a segment with a colon (e.g., /users/:id). These values can be accessed within the route handler function using req.params, which is an object containing the named parameters as properties (e.g., req.params.id).
- Middleware in Express.js are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next() function is a callback that, when invoked, passes control to the next middleware function. If next() is not called, the request-response cycle is halted.
- Middleware can be registered globally using app.use() without a specific path, in which case it will be executed for every incoming request. It can also be registered for a specific route by passing the middleware function as an argument (or multiple arguments) to route handling methods like app.get(), app.post(), etc. The order of middleware registration is crucial because middleware functions are executed sequentially in the order they are defined.
- An Express Router is an object that acts like a mini Express application, capable of handling routes and middleware. It’s useful for organizing API endpoints based on domains or features, preventing a single file from becoming too large and unmanageable. To create a Router, you use const router = express.Router(). To register the Router with the main application, you use app.use(‘/some/path’, router), where all routes defined on the router will be prefixed with /some/path.
- HTTP cookies are small pieces of data that a web server sends to the user’s web browser. The browser may store these cookies and send them back to the server with later requests. You can set a cookie in an Express response using the res.cookie(‘name’, ‘value’, [options]) method. You can access cookies sent by the browser in a request using the req.cookies object, provided you have used the cookie-parser middleware.
Essay Format Questions
- Discuss the request-response lifecycle in Express.js, emphasizing the role and flow of control through middleware functions and route handlers.
- Compare and contrast the different HTTP methods (GET, POST, PUT, PATCH, DELETE) and explain how they are typically used in building RESTful APIs with Express.js, providing relevant examples.
- Explain the importance of modularity and organization in developing large-scale Express.js applications. Discuss how Express Routers can be effectively utilized to achieve this, providing a hypothetical scenario.
- Describe the concept of state management in web applications, particularly focusing on the stateless nature of HTTP. Discuss how cookies and sessions can be used in Express.js to maintain user-specific state across multiple requests.
- Explain the significance of input validation in web application development. Describe how middleware, such as those provided by Express Validator, can be implemented in Express.js to ensure data integrity and security.
Glossary of Key Terms
- Entry Point: The primary file that is executed to start an application (e.g., index.js or index.mjs).
- Script (in package.json): A command-line instruction that can be executed using npm run <script-name>.
- Watch Mode: A development mode (often using tools like Nodemon) that automatically restarts the server when code changes are detected.
- Production: The environment where the final, deployed version of the application runs.
- CommonJS: The module system traditionally used in Node.js, utilizing require() for importing and module.exports for exporting.
- ECMAScript Modules (ESM): The standardized module system in JavaScript, using import and export statements.
- Module System: A mechanism for organizing and sharing code in JavaScript.
- File Extension (MJS): The file extension used to explicitly indicate that a JavaScript file should be treated as an ECMAScript Module.
- Module: A reusable unit of code.
- Package: A directory containing a package.json file and the associated code and resources.
- Import: To bring in code or functionality from another module or package.
- Export: To make code or functionality available for use by other modules or packages.
- Express: A minimal and flexible Node.js web application framework.
- Application Instance (app): An object created by calling the express() function, representing the Express application.
- Method (on app object): A function associated with the Express application instance (e.g., app.get(), app.listen(), app.use()).
- Property (on app object): A data value associated with the Express application instance.
- Listen Method (app.listen()): A method that starts the Express server and makes it listen for incoming requests on a specified port.
- Port: A virtual communication endpoint on a computer’s network interface used by processes to listen for or send data.
- Callback Function: A function that is passed as an argument to another function and is executed at a later point in time.
- Global (in Node.js): Objects or variables that are available throughout the Node.js environment without requiring explicit import (e.g., process).
- Environment Variables (process.env): Dynamic named values that can affect the way running processes will behave on a computer.
- Logical OR Operator (||): A binary operator that returns the right-hand operand if the left-hand operand is falsy, otherwise it returns the left-hand operand.
- Start Script: A script defined in package.json that typically runs the main application.
- Nodemon: A utility that automatically restarts Node.js applications when file changes in the directory are detected.
- Localhost: The standard hostname for the loopback network interface (IP address 127.0.0.1) of a computer, often used for testing web applications locally.
- Route: A defined path on the server that is associated with a handler function.
- Base Route: The root path of a website or application, typically represented by /.
- Resolver: A function or piece of code that determines how to respond to a request for a specific route.
- Endpoint: Often used synonymously with “route,” referring to a specific URL on the server that the client can access.
- Host Name: The label assigned to a device connected to a computer network that is used to identify the device in various forms of electronic communication.
- HTTP Request: A message sent from a client (e.g., a web browser) to a server to request a resource or trigger an action.
- HTTP Verbs (Methods): Indicate the type of action the client wants to perform on the server’s resource (e.g., GET, POST, PUT, DELETE).
- Client: An application (e.g., web browser, mobile app) that makes requests to a server.
- Backend Server: The part of a web application that runs on the server and handles data storage, logic, and API requests.
- HTTP Request Methods: See HTTP Verbs.
- GET Request: An HTTP method used to retrieve data from the server.
- POST Request: An HTTP method used to send data to the server to create a new resource.
- PUT Request: An HTTP method used to update an existing resource on the server.
- PATCH Request: An HTTP method used to partially update an existing resource on the server.
- DELETE Request: An HTTP method used to remove a resource from the server.
- Request Handler: A function that is executed when the server receives a request matching a defined route. It receives the request and response objects as arguments.
- Request Object (req): An object containing information about the incoming HTTP request, such as headers, parameters, body, and cookies.
- Response Object (res): An object used by the server to send a response back to the client, allowing you to set headers, status codes, and the response body.
- Send Method (res.send()): A method on the response object used to send the HTTP response back to the client. It can send strings, HTML, JSON objects, etc.
- JSON Object: A lightweight data-interchange format consisting of key-value pairs.
- Status Code: A three-digit number in an HTTP response that indicates the outcome of the request (e.g., 200 OK, 404 Not Found).
- Status Method (res.status()): A method on the response object used to set the HTTP status code for the response.
- Chaining (Methods): Calling multiple methods on an object in sequence, where each method returns the object itself.
- API Prefix: A common practice of starting API route paths with /api/ or similar to distinguish them from other application routes.
- Route Parameters: Dynamic segments in a route path used to capture values from the URL (e.g., /users/:id).
- Dynamic Data: Data that can vary based on input or conditions.
- Middleware: Functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle.
- Request Handler (as Middleware): A middleware function that handles an incoming request.
- Next Argument (next): A function passed to middleware that, when called, passes control to the next middleware function in the stack.
- Global Middleware: Middleware registered using app.use() without a specific path, applied to all routes.
- Endpoint-Specific Middleware: Middleware applied only to specific routes, either by passing them as arguments to route handlers or using app.use() with a specific path.
- Sequential Order: Middleware functions are executed in the order they are registered in the application.
- Authorization Token: A credential used to verify the identity and permissions of a client making a request.
- Status Code 401 (Unauthorized): An HTTP status code indicating that the client is not authenticated and needs to provide valid credentials.
- Mock Users: Sample or simulated user data used for development and testing purposes.
- Splice Method (Array): A JavaScript array method that changes the contents of an array by removing or replacing existing elements and/or adding new elements in place.
- Delete Count (splice): The number of elements to remove from the array when using the splice() method.
- Thunder Client: A lightweight HTTP client extension for VS Code used to make API requests.
- Not Found (404): An HTTP status code indicating that the server cannot find the requested resource.
- Mozilla Docs (MDN): The official web documentation provided by Mozilla.
- HTTP Request Methods (MDN): Documentation on various HTTP request methods and their purposes.
- Head Method: An HTTP method that requests the same response as a GET request, but without the response body.
- Connect Method: An HTTP method that establishes a tunnel to the server identified by the target resource.
- Options Method: An HTTP method that describes the communication options for the target resource.
- Trace Method: An HTTP method that performs a message loop-back test along the path to the target resource.
- Mid Process: An intermediate step or function in a sequence of operations.
- Logging Middleware: Middleware used to record information about incoming requests, such as the method and URL.
- app.use(): A method used to register middleware functions with the Express application.
- Sequential Order (Middleware): Middleware functions are executed in the order they are registered.
- Route (app.get, app.post, etc.): A specific path and HTTP method combination that is handled by the application.
- app.post(): A method used to define a route that handles HTTP POST requests.
- app.put(): A method used to define a route that handles HTTP PUT requests.
- app.patch(): A method used to define a route that handles HTTP PATCH requests.
- app.delete(): A method used to define a route that handles HTTP DELETE requests.
- Domain (API): A logical grouping of API endpoints based on a specific area of functionality (e.g., users, products).
- Express Router: An object that allows you to create modular, mountable route handlers.
- Routes Folder: A common directory in Express applications to organize route definitions.
- users.mjs: A file containing route definitions related to user resources.
- Import (Router): Bringing the Router class from the express module into a file.
- Router Instance: An object created by calling express.Router().
- Method (on Router): Functions associated with a Router instance (e.g., router.get(), router.post()).
- Register (Router): Making the routes defined in a Router instance available to the main Express application using app.use().
- Export (default): Making a single value the primary export of a module.
- Index.mjs (routes): A common file within a routes directory used to aggregate and export all defined routers.
- Utils Folder: A directory to store utility functions and constants used throughout the application.
- Constants File: A file (e.g., constants.mjs) to store constant values used in the application.
- Named Export: Exporting specific variables or functions from a module using their names.
- Middlewares File: A file (e.g., middlewares.mjs) to store reusable middleware functions.
- Products Router: A Router instance specifically for handling product-related routes.
- Barrel File: A module that re-exports other modules, providing a single point of import for a set of modules.
- Prefix (for Routes): A base path added to all routes defined within a specific Router when it’s mounted using app.use().
- HTTP Cookies: Small pieces of data that a web server sends to the user’s web browser, which may then be stored by the browser and sent back to the server with subsequent requests.
- Thunder Client (Cookies Section): A part of the Thunder Client interface that allows you to view and manage cookies associated with a particular domain.
- Response (Set-Cookie Header): When a server wants to set a cookie in a user’s browser, it includes a Set-Cookie header in its HTTP response.
- Browser (Cookie Storage): Web browsers have a mechanism to store cookies received from servers, usually associated with the domain that set them.
- Request (Cookie Header): When a browser makes a request to a server, it automatically includes any cookies associated with that server’s domain in the Cookie header of the HTTP request.
- Stateless (HTTP): The property of the HTTP protocol where the server does not retain any information about past client requests. Each request is treated as independent.
- E-commerce Website (Cart System): A common application where cookies are used to maintain a user’s shopping cart even if they close and revisit the website.
- Authentication: The process of verifying the identity of a user.
- Sessions: A mechanism to maintain state across multiple requests from the same user, typically using a session ID stored in a cookie.
- Cookie Method (res.cookie()): An Express response object method used to set a cookie in the Set-Cookie header of the HTTP response. It takes the cookie name, value, and optional options as arguments.
- Expiration (Cookie): The date and time at which a cookie will no longer be valid and will be discarded by the browser.
- Max-Age (Cookie Option): A cookie option that specifies the lifespan of the cookie in seconds.
- Domain (Cookie Option): A cookie option that specifies the domain for which the cookie is valid.
- HTTPOnly (Cookie Option): A cookie option that, when set to true, prevents client-side scripts from accessing the cookie.
- Secure (Cookie Option): A cookie option that, when set to true, ensures the cookie is only transmitted over HTTPS.
- Request Object (req.headers.cookie): The Cookie header in the request object, which contains a string of all cookies sent by the browser for the current domain.
- Parsing (Cookies): The process of converting the raw Cookie header string into a more usable format, typically an object where each cookie name is a key.
- Cookie Parser Middleware (cookie-parser): An Express middleware that parses the Cookie header and populates req.cookies with an object containing the cookie names and values.
- Third-Party Package: A module or library developed by someone other than the core framework developers.
- npm (Node Package Manager): The default package manager for Node.js.
- Install (npm install or npm i): The command used to download and install packages from npm.
- Middleware (cookie-parser): The cookie-parser package provides a middleware function that needs to be registered with the Express application using app.use().
- req.cookies: An object added to the request object by the cookie-parser middleware, containing the parsed cookies.
- Conditional Logic: Using if statements or other control flow structures to execute different code based on certain conditions.
- Status Code 403 (Forbidden): An HTTP status code indicating that the server understands the request but refuses to authorize it.
- Status Code 401 (Unauthorized): An HTTP status code indicating that the client is not authenticated.
- Signed Cookies: Cookies that have a digital signature to prevent tampering.
- Secret (for Signed Cookies): A secret key used to generate and verify the signatures of signed cookies. This needs to be passed to the cookie-parser middleware.
- res.cookie() (signed option): When the signed option is set to true in res.cookie(), a signed cookie is set.
- req.signedCookies: An object added to the request object by the cookie-parser middleware (when configured with a secret), containing the parsed and verified signed cookies.
- Session: A mechanism to maintain state for a user across multiple HTTP requests. It typically involves storing user-specific data on the server and associating it with a unique session ID that is usually stored in a cookie on the client’s browser.
- express-session: An Express middleware that creates and manages session data.
- Session ID: A unique identifier generated by the server for each user’s session. This ID is typically stored in a cookie sent to the user’s browser.
- Session Store: The storage mechanism on the server where session data is persisted. By default, express-session uses an in-memory store, but for production environments, persistent stores like databases are recommended.
- app.use(session(…)): How the express-session middleware is registered with the Express application.
- secret (session option): A string used to sign the session ID cookie, preventing client-side tampering. This should be a complex, randomly generated string in a production environment.
- saveUninitialized (session option): When set to true, a new but unmodified session will be saved to the store. Setting it to false is recommended to avoid storing unnecessary sessions.
- resave (session option): When set to true, the session will be saved back to the session store on every request, even if it wasn’t modified. Setting it to false is often preferred to avoid unnecessary writes to the store.
- cookie (session option): An object that allows you to configure the properties of the session ID cookie, such as maxAge, httpOnly, and secure.
- req.session: An object attached to the request object by the express-session middleware. It is used to store and access session data specific to the current user.
- Dynamic Property (on req.session): You can add custom properties to the req.session object to store user-specific data.
- In-Memory Store (Session): The default session store used by express-session, which stores session data in the server’s memory. This is not suitable for production environments with multiple server instances or restarts.
- Persistent Session Store: A session store that persists data across server restarts and can be shared between multiple server instances (e.g., using databases like Redis, MongoDB, or PostgreSQL).
- req.session.destroy(): A method to end the current session and remove the associated session data from the store.
- req.sessionStore: An object representing the underlying session storage mechanism.
- req.sessionStore.get(sid, callback): A method on the session store to retrieve session data associated with a given session ID (sid).
- npm install mongodb: The command to install the official MongoDB driver for Node.js.
- MongoDB: A popular NoSQL database.
- Database Connection: The process of establishing a link between an application and a database server.
- Connection URI (MongoDB): A string that specifies how to connect to a MongoDB database, including the protocol, hostname, port, database name, and authentication credentials if required.
- mongoose: A popular Object Data Modeling (ODM) library for MongoDB and Node.js. It provides a higher-level abstraction for interacting with MongoDB.
- ODM (Object Data Modeling): A programming technique that maps objects to a database schema.
- Schema (Mongoose): A blueprint for the structure of documents in a MongoDB collection, defining the data types, validators, and other properties of the fields.
- Model (Mongoose): A class that represents a MongoDB collection and provides an interface for creating, querying, updating, and deleting documents. It is created from a Mongoose schema.
- mongoose.Schema({…}): Used to define a new Mongoose schema.
- Data Type (Mongoose): Specifies the type of data that a field in a Mongoose schema can hold (e.g., String, Number, Boolean).
- Validator (Mongoose): Functions or objects that define rules for the values that can be saved in a field of a Mongoose schema (e.g., required, unique, minlength, maxlength).
- required: true (Validator): Ensures that a field must have a value.
- unique: true (Validator): Ensures that the values in a field are unique across all documents in the collection.
- minlength and maxlength (Validators): Specify the minimum and maximum length for string fields.
- mongoose.model(modelName, schema): Used to create a Mongoose model from a defined schema.
- try…catch Block: A JavaScript construct used for error handling. Code that might throw an error is placed in the try block, and code to handle the error is placed in the catch block.
- async and await: Keywords in JavaScript used to work with asynchronous operations in a more synchronous-like manner. async marks a function as asynchronous, and await pauses the execution of an async function until a Promise is resolved.
- Asynchronous Operation: An operation that does not block the execution of the program while it is in progress. It typically relies on callbacks, Promises, or async/await to handle the result.
- Promise: An object representing the eventual completion (or failure) of an asynchronous operation and its resulting value.
- new Model({…}): Creating a new document instance of a Mongoose model.
- Constructor (Class): A special method for creating and initializing an object created with a class.
- document.save() (Mongoose): An asynchronous method on a Mongoose document instance that saves the document to the MongoDB database.
- Status Code 201 (Created): An HTTP status code indicating that the request has succeeded and a new resource has been created as a result.
- Status Code 400 (Bad Request): An HTTP status code indicating that the server could not understand the request due to invalid syntax or other client-side error.
- Duplicate Key Error (MongoDB): An error thrown by MongoDB when trying to insert a document with a value for a field marked as unique that already exists in the collection.
- Express Validator: A library for validating and sanitizing user input in Express.js applications.
- checkSchema(schema): A function from Express Validator that creates a middleware to validate request data against a provided schema.
- Validation Schema (Express Validator): An object that defines the validation rules for different fields of the request (e.g., body, query, params).
- validationResult(req): A function from Express Validator that retrieves the validation errors that occurred during the schema check.
- .isEmpty() (Validation Result): A method on the validation result object that returns true if there are no validation errors, and false otherwise.
- .array() (Validation Result): A method on the validation result object that returns an array of validation errors.
- matchedData(req): A function from Express Validator that extracts the validated data from the request, according to the validation schema.
- bcrypt: A library for password hashing.
- Password Hashing: The process of transforming a plain-text password into a fixed-size string of characters using a cryptographic hash function. This makes it computationally infeasible to retrieve the original password from the hash.
- bcrypt.hashSync(password, salt): A synchronous function from bcrypt that hashes a password using a generated salt.
- salt (bcrypt): A randomly generated string that is added to each password before it is hashed. This makes it more difficult for attackers to use pre-computed tables of hashes (rainbow tables).
- saltRounds (bcrypt): A parameter that controls the computational cost of the hashing process. Higher rounds provide more security but take longer to compute.
- bcrypt.compareSync(plainTextPassword, hashedPassword): A synchronous function from bcrypt that compares a plain-text password with a stored hash to see if they match.
- Unit Testing: A software testing method by which individual units of source code (the smallest testable parts of an application) are tested to determine whether they are fit for use.
- jest: A popular JavaScript testing framework.
- Test Suite (describe): A block of code in a test file that groups together related tests, typically for a specific component or functionality.
- Test Case (it or test): An individual test that focuses on a specific aspect or behavior of the code being tested.
- Assertion (expect): A statement in a test that verifies a certain condition or outcome. If the assertion fails, the test is considered failed.
- Mocking: Replacing dependencies of the code being tested with controlled test doubles (mocks) to isolate the unit under test and control its behavior.
- Mock Request (mockRequest): A simulated request object used in unit tests, containing only the properties and methods relevant to the code being tested.
- Mock Response (mockResponse): A simulated response object used in unit tests, providing mock implementations of methods like status() and send() to observe how the code under test interacts with the response.
- jest.fn(): A Jest function that creates a mock function, which can be used to track calls, arguments, and return values.
- mockResponse.status.mockReturnValue(value): Setting the return value of the mocked status() method.
- mockResponse.send.mockImplementation(value): Setting the implementation of the mocked send() method, allowing you to observe what data is being sent.
- expect(mockFunction).toHaveBeenCalled(): A Jest assertion that verifies if a mock function has been called.
- expect(mockFunction).toHaveBeenCalledWith(…args): A Jest assertion that verifies if a mock function has been called with specific arguments.
- expect(mockFunction).toHaveBeenCalledTimes(number): A Jest assertion that verifies how many times a mock function has been called.
- expect(mockFunction).mock.calls: An array containing all the calls that were made to a mock function. Each call is represented by an array of arguments passed to the mock.
- expect(value).toBe(expected): A Jest matcher that performs a strict equality check.
- Dependency Injection: A software design pattern in which an object receives other objects that it depends on (dependencies) instead of creating them itself. This makes code more testable and modular.
- Implementation Detail: A specific way in which a piece of code is implemented, which might not be relevant to the overall behavior being tested.
- Behavioral Testing: A testing approach that focuses on verifying the observable behavior of the code under test, rather than its internal implementation details.
- jest.mock(‘moduleName’, factory): A Jest function used to mock an entire module. The factory argument is a function that returns the mock implementation of the module’s exports.
- clearMocks (Jest Config): A Jest configuration option that, when set to true, automatically resets the state of all mocked functions before each test.
- beforeEach(() => {…}): A Jest hook that runs a provided function before each test within a describe block. It can be used to set up test data or reset mocks.
- End-to-End (E2E) Testing: A testing methodology used to test an application’s workflow from start to finish, simulating real user scenarios and verifying that all integrated components work correctly together.
- SuperTest: A library for testing web applications by making HTTP requests to them and asserting the responses.
- Test Script (E2E): A script in package.json specifically for running end-to-end tests.
- request(app) (SuperTest): A function from SuperTest that creates an agent for making requests to a given Express application instance.
- .get(path) (SuperTest Agent): A method on the SuperTest agent to make an HTTP GET request to a specified path.
- .expect(status) (SuperTest Response): A method on the SuperTest response object to assert the expected HTTP status code.
- .expect(body) (SuperTest Response): A method on the SuperTest response object to assert the expected response body.
- .end((err, res) => {…}) (SuperTest Request): A method to execute the HTTP request and receive the response in a callback function.
- async and await (with SuperTest): Using async/await with SuperTest allows you to handle the asynchronous nature of HTTP requests in a more straightforward way, making it easier to work with the response.
- Response Object (SuperTest): The object returned after making a request with SuperTest, containing properties like status, body, and headers.
- .toStrictEqual(value) (Jest Matcher): A Jest matcher that performs a strict equality check on all levels, including object properties and array elements.
- .toBeEmptyObject() (Jest Matcher): A Jest matcher that checks if a value is an empty object.
- Test Environment (Node): Configuring Jest to run tests in a Node.js environment, suitable for server-side JavaScript code.
- Transform (Jest Config): A Jest configuration option that specifies how to transform source files before running tests, often used to handle non-standard JavaScript syntax (e.g., ESM in a CommonJS environment).
- @babel/preset-env: A Babel preset that allows you to use the latest JavaScript features without needing to micromanage which syntax transforms (plugins) are needed by your target environment(s).
- targets: { node: ‘current’ } (Babel Config): A configuration in @babel/preset-env that tells Babel to transpile JavaScript to the version supported by the current Node.js environment where the tests are being run.
- Babel (@babel/core, @babel/cli, etc.): A JavaScript transpiler that converts ECMAScript 2015+ code into a backwards compatible version of JavaScript that can be run by older JavaScript engines.
- babel-jest: A Jest preprocessor that uses Babel to transform your test files.
- Module File Extensions (Jest Config): A Jest configuration option that specifies the file extensions to consider as modules.
- .babelrc: A configuration file for Babel, where you can specify presets and plugins to use for transpilation.
- npm init -y: A command to quickly initialize a new Node.js project and create a package.json file with default settings.
- @jest/globals: A package that provides global Jest functions like describe, it, expect, etc., for environments where they are not automatically available.
- @types/jest: TypeScript type definitions for the Jest API, providing better type checking and autocompletion in editors.
- jsconfig.json: A configuration file that specifies the root files and the options for the JavaScript language service provided by VS Code.
- Type Acquisition (VS Code): A feature in VS Code that automatically downloads and configures type definition files (.d.ts) for JavaScript projects, improving IntelliSense.
Express.js Web Server Development Fundamentals
## Briefing Document: Review of Provided Sources
This document provides a detailed review of the main themes, important ideas, and facts presented in the provided excerpts from “01.pdf”. The source primarily focuses on setting up a basic web server using Express.js, defining routes, handling HTTP request methods, implementing middleware, organizing routes with Express Router, working with HTTP cookies and sessions, performing input validation, integrating with MongoDB, hashing and comparing passwords using bcrypt, and finally, introducing unit and end-to-end testing with Jest and SuperTest.
### Main Themes:
1. **Express.js Fundamentals:** The initial sections detail the foundational steps for creating an Express.js application, including setting up the entry point, using `package.json` for script management and ES Modules, importing the Express module, creating an application instance, and starting the server with the `listen` method.
2. **Route Definition and HTTP Methods:** A significant portion of the content explains how to define routes in Express using different HTTP verbs (GET, POST, PUT, PATCH, DELETE) and how to handle requests to these routes using request handler functions with `request` and `response` objects.
3. **Middleware Implementation:** The concept of middleware in Express.js is introduced, demonstrating how to create and register middleware functions globally or for specific routes. The importance of the `next()` function in the middleware pipeline is emphasized.
4. **Route Organization with Express Router:** The document illustrates how to use the Express Router to modularize and organize API endpoints based on domains (e.g., users, products), promoting better code structure and maintainability.
5. **HTTP Cookies and Sessions:** The use of HTTP cookies for maintaining client-side state is explained, along with how to set, retrieve (using `cookie-parser` middleware), and manage cookie properties like expiration. Sessions are introduced as a server-side mechanism for tracking user activity, utilizing the `express-session` middleware.
6. **Input Validation:** The importance of validating incoming request data is highlighted, demonstrating the use of `express-validator` for defining validation schemas and checking for validation errors within request handlers.
7. **MongoDB Integration:** The excerpts cover the basic steps of connecting an Express.js application to a MongoDB database using Mongoose, defining schemas, creating models, and performing CRUD operations (specifically creation).
8. **Password Hashing with Bcrypt:** The document explains the necessity of hashing passwords before storing them in a database for security reasons and demonstrates how to use the `bcrypt` library for generating password hashes and comparing them during login.
9. **Unit and End-to-End Testing:** The final sections introduce the concepts of unit and end-to-end testing. Jest is presented as a testing framework for writing unit tests, focusing on testing individual functions in isolation by using mocks. SuperTest is introduced as a library for performing end-to-end tests, simulating HTTP requests to the application’s routes.
### Most Important Ideas and Facts:
* **ES Modules:** Setting `”type”: “module”` in `package.json` enables the use of modern `import` and `export` statements, requiring `.mjs` file extensions.
> “I’m going to go ahead and set this type property and you can see that there’s two values uh commonjs or module I’m going to set it to module and what this will allow me to do is use esm as my module system so that way I can use the modern import export statements instead of having to use require to import modules and module that exports to export stuff.”
* **Express Application Instance:** The `express()` function returns an instance of an Express application, which is used to define routes and middleware.
> “now the imported value of this Express name is actually a top level function and we need to call this function in order to create an express application so what I’m going to do is I’m going to first declare a variable […] I’ll call it app and then I’m just simply going to reference Express and then invoke that function by using parentheses and that’s all.”
* **`app.listen()`:** This method starts the Express server on a specified port, allowing it to listen for incoming HTTP requests.
> “the method that we need to call is the listen method and this pretty much allows you to listen to a port for incoming requests. This is actually what starts up the express server on a specific port and then you can begin receiving incoming HTTP requests.”
* **Routes and Request Handlers:** Routes are paths defined on the server, and request handlers are callback functions that execute when a specific route is accessed with a particular HTTP method.
> “a route in general is think of it like a path in your express application so determining which path you want to take gives you different outputs.”
> “the request Handler is just a function but in this case it’s a callback function so it would look like this so I’ll pass a simple arrow function and this callback function has two arguments okay it has a request argument which is the request object itself […] now the second argument is the response object the response object is what you can use to modify the response and send it back to the user…”
* **HTTP Verbs:** Different HTTP methods (GET, POST, PUT, PATCH, DELETE) indicate the desired action to be performed on a resource.
> “these verbs pretty much are ways on how you can tell the server to perform some operation. So for example you don’t always want to just get data sometimes you might want to create data […] sometimes you want to update data sometimes you want to delete data…”
* **Middleware:** Middleware functions have access to the `request`, `response`, and `next` function, allowing them to modify requests and responses, execute code, and pass control to the next middleware in the stack.
> “in the context of expressjs a middleware is just a function that can have logic but the middleware function also is a request Handler as as well so that middleware function has the request response arguments as well and you can actually use the middleware function to return a response if you want to.”
> “the middleware function or the request Handler function also has access to this next argument which is a function that you call when you are done with the middleware.”
* **`app.use()`:** Used to register middleware functions globally or for specific routes. Order of registration matters.
> “Let’s call app.use to register our middleware globally so all I do is I just pass in logging middleware as a function or as an argument like this.”
> “middleware must be registered before a route if you’re using app.use register it.”
* **Express Router:** Provides a way to create modular, mountable route handlers, allowing for better organization of API endpoints.
> “we can use an Express router to do this and what I’ll do is I’ll create a new folder inside the source folder and I’ll call this routes and then I’m going to go ahead and create a new file and call it users. MJS and then inside users. MJS we’re going to import the router from Express…”
* **HTTP Cookies:** Small pieces of data that the server sends to the client’s browser, which the browser can store and send back to the server with subsequent requests. Useful for maintaining state in a stateless HTTP environment.
> “cookies or HTTP cookies they’re literally just small pieces of data that your web server sends to the browser…”
> “remember that HTTP is stateless and using cookies enables the server to send a cookie to the web browser and that cookie typically is going to be some unique value so that way the server when they receive it they can distinguish whose cookie this belongs to and then they can send Dynamic data based on the cookie value.”
* **`cookie-parser` Middleware:** Parses the `Cookie` header in the incoming request, populating `req.cookies` with an object keyed by the cookie names.
> “we can actually use a third-party package called cookie parser to parse the cookies for us.”
* **Signed Cookies:** Cookies that are cryptographically signed to prevent tampering. Require a secret key for signing and parsing.
> “if you ever need to set sign cookies which like I said earlier it has a signature uh you can go ahead right over here and set signed to True Whenever you set the cookie but in order for you to actually uh parse cookies that are signed you must you must you must provide a secret…”
* **`express-session` Middleware:** Creates and manages server-side sessions, typically using cookies to store a session identifier on the client.
> “sessions represent the duration of a user on a website by default HTTP is stateless we don’t know who is making requests to our server so we need to be able to track requests and know where they are coming from. One common usage of sessions is to manage user authentication.”
> “we’ll get started in implementing sessions using the express session Library…”
* **Input Validation with `express-validator`:** A library for validating and sanitizing request data based on defined schemas.
> “I want to show you all how we can use a very popular package called Express validator to make input validation a lot more easier.”
> “this middleware does not actually throw an error we need to go inside the request Handler and actually check if there are any errors.”
* **MongoDB and Mongoose:** Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js, providing a higher-level abstraction for interacting with the database.
> “Now I’m going to show you all how we can actually integrate our Express application with a real database in this case we’re going to be using mongodb…”
> “Mongoose is an object data modeling library that provides a straightforward schema based solution to model your application data.”
* **Password Hashing with `bcrypt`:** A library for securely hashing passwords using the bcrypt algorithm.
> “you want to make sure you always hash your passwords before you save it to the database…”
> “first let’s go ahead and install bcrypt…”
* **Unit Testing with Jest:** A JavaScript testing framework used to test individual units of code in isolation. Involves mocking dependencies to avoid external interactions.
> “the next topic that I want to talk about is testing and specifically unit testing so what exactly is unit testing well unit testing is a software testing method by which individual units of source code test for determining whether they are fit for use.”
> “we’re going to install a couple of dependencies so I’m going to type npmi hyphen capital D CU I’m going to install these as Dev dependencies so the packages are at Babel slore Babel code at Babel slpre EnV so that’s it for Babel we then need to install just as well…”
* **End-to-End Testing with SuperTest:** A library for testing HTTP endpoints by making actual requests to the application and asserting on the responses.
> “for our end to end test we’re going to be using a very popular package called super test.”
> “end to end testing is a methodology used to test an application flow from start to finish.”
This briefing document summarizes the key concepts and procedures outlined in the provided source, offering a comprehensive overview of building a backend API with Node.js, Express.js, and related technologies, including database integration, security measures, and testing strategies.
Express.js API Development Fundamentals
1. What is the purpose of the package.json file configurations shown, specifically the type property and the start script?
The package.json file is the manifest for the Node.js project. The type property is set to module, which enables the use of ECMAScript Modules (ESM) syntax (i.e., import and export) instead of the CommonJS require and module.exports. To use ESM, the file extension for JavaScript files needs to be .mjs. The scripts section defines executable commands. Here, a start script is created to run the application using the node command, typically used for production deployments where a file watcher (like Nodemon) is not needed.
2. How is an Express application instance created and configured to listen for incoming requests?
An Express application instance is created by first importing the express module and then invoking the imported Express function. This returns the application object, which is typically stored in a variable (e.g., app). To configure the application to listen for incoming HTTP requests, the app.listen() method is used. This method takes the port number as its first argument and optionally a callback function as its second argument. The callback function is executed once the server has started listening on the specified port, often used for logging or other post-startup operations. It’s best practice to configure the port using an environment variable (process.env.PORT) with a default value (e.g., 3000) for flexibility.
3. What are routes in Express, and how are they defined for handling different types of HTTP requests?
Routes in Express define how the application responds to client requests to specific endpoints (URIs) and HTTP request methods (verbs). A route is associated with a path (e.g., /, /api/users) and one or more handler functions. Routes are defined using methods on the Express application object that correspond to HTTP verbs, such as app.get() for handling GET requests, app.post() for POST requests, app.put() for PUT requests, app.patch() for PATCH requests, and app.delete() for DELETE requests. Each of these methods takes the route path as the first argument and a request handler function (or a series of middleware functions and a handler) as the subsequent argument(s). The request handler function receives request and response objects, allowing you to access request details and send responses back to the client.
4. Explain the roles of the request and response objects within a route handler function in Express.
The request object in a route handler function contains all the information about the incoming HTTP request from the client. This includes headers, the request body (if any), query parameters, route parameters, cookies, and metadata about the connection. You can access these details through various properties of the request object (e.g., request.headers, request.body, request.params, request.cookies).
The response object is used to send data back to the client. It provides methods for controlling the response, such as setting the HTTP status code (response.status()), sending data as the response body (response.send(), response.json()), setting headers (response.set()), and setting cookies (response.cookie()). Route handlers must ultimately use the response object to end the request-response cycle by sending a response back to the client.
5. What are route parameters in Express, and how are they used to handle dynamic data in URLs?
Route parameters are named URL segments that are used to capture values specified at their position in the URL. They are defined in the route path by prefixing the parameter name with a colon (e.g., /api/users/:id). When a client makes a request to a URL that matches this pattern, the value in the parameter segment is captured and made available in the request.params object within the route handler function. This allows you to create dynamic routes where different data can be accessed based on the specific value in the URL. For example, /api/users/123 would make the value 123 accessible as request.params.id.
6. What is middleware in Express, and how can it be used to handle tasks like logging, authentication, or data processing before route handlers?
Middleware in Express are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. Middleware functions can perform various tasks such as logging requests, authenticating users, validating data, and modifying the request or response objects. They can terminate the request-response cycle by sending a response, or they can pass control to the next middleware function in the stack by calling next().
Middleware can be registered globally for all routes using app.use() or locally for specific routes by passing the middleware function as an argument when defining a route (e.g., app.get(‘/path’, middlewareFunction, routeHandler)). The order in which middleware is registered is crucial, as they are executed in the order they are added to the application.
7. How can Express Routers be used to organize API endpoints into logical groups and keep the main application file cleaner?
Express Routers are isolated instances of middleware and routes. They allow you to group related API endpoints together and define their handlers within a separate file or module. To use a Router, you first create an instance using express.Router(). Then, you can define routes on this router instance using the same HTTP method functions (router.get(), router.post(), etc.) as you would on the main application object. Finally, you mount the router to a specific path in your main application using app.use(‘/api/resource’, resourceRouter). This will apply all the routes defined in resourceRouter under the /api/resource path. Using routers helps to modularize your application, making it easier to manage and understand as the number of endpoints grows.
8. Explain the purpose and basic usage of HTTP cookies in Express for maintaining client-server state.
HTTP cookies are small pieces of data that a web server sends to a user’s web browser. The browser may store these cookies and send them back to the server with subsequent requests made to the same server. Cookies are often used to remember information about the user, such as session tokens, preferences, or shopping cart contents, thus allowing the server to maintain state for otherwise stateless HTTP connections.
In Express, you can set cookies on the response object using response.cookie(‘name’, ‘value’, [options]). The options argument can include properties like maxAge (in milliseconds), expires (a Date object), httpOnly, secure, and signed. To access cookies sent by the browser, you typically use the cookie-parser middleware. Once installed and used with app.use(cookieParser()), it populates the request.cookies object with the parsed cookies. For signed cookies (where the value is cryptographically signed), you would use response.signedCookie() to set them and request.signedCookies to access them, after configuring a secret with the cookie-parser middleware. Cookies are essential for implementing features like user sessions and persistent settings.
Express.js and HTTP Request Methods
The sources discuss several HTTP request methods used in building web APIs, particularly within the context of the Express.js framework. Here’s a breakdown of these methods based on the provided information:
- GET:
- Used to retrieve data from the server in a read-only format without manipulating any data on the server side.
- Clients make GET requests to fetch resources. For example, an e-commerce website might use a GET request to display a list of products.
- Data can be sent to the server through the URL using query strings or query parameters. These are key-value pairs appended to the URL after a question mark (?), separated by ampersands (&). Express.js parses the query string into a JSON object accessible via request.query. This can be used for filtering or sorting data on the server before sending it back.
- In Express.js, GET requests are handled using app.get(). This method takes a route path and a request handler function as arguments. The request handler receives a request object (containing information about the incoming request) and a response object (used to send data back to the client).
- The response.send() method is used to send back data, which can be plain text, JSON objects, or arrays. The response.status() method can be used to set the HTTP status code of the response (e.g., 200 for success).
- POST:
- Used to create new data or resources on the server.
- When a client (e.g., a web form) wants to send data to the server to be stored (e.g., creating a new user), it makes a POST request.
- The data to be sent is included in the request body or payload of the HTTP request.
- Express.js, by default, does not parse request bodies. Middleware like express.json() needs to be used to parse JSON request bodies. This makes the data available in the request.body property of the request object.
- In Express.js, POST requests are handled using app.post(). It takes a route path and a request handler function.
- A successful POST request typically returns a 201 status code (Created). The server might also return the newly created resource in the response body.
- PUT:
- Used to update an existing resource on the server.
- A PUT request is intended to replace the entire target resource with the data provided in the request body. If a field is not included in the request body during a PUT request, it might be removed or set to null on the server, depending on the backend implementation.
- In Express.js, PUT requests are handled using app.put(), taking a route path (often including a route parameter to identify the resource to update, e.g., /api/users/:id) and a request handler.
- PATCH:
- Also used to update an existing resource on the server, but unlike PUT, it’s for partial updates.
- With PATCH, you only need to send the specific fields that you want to modify in the request body, leaving the other fields untouched.
- In Express.js, PATCH requests are handled using app.patch(), similar to PUT, often with a route parameter to specify the resource.
- A successful PUT or PATCH request might return a 200 (OK) or 204 (No Content) status code.
- DELETE:
- Used to remove a resource from the server.
- Typically, a DELETE request targets a specific resource identified by its URL, often including a route parameter (e.g., /api/users/:id).
- While a request body can be sent with a DELETE request if additional data is needed, it’s not as common as with POST, PUT, or PATCH.
- In Express.js, DELETE requests are handled using app.delete(), with a route path and a request handler.
- A successful DELETE request might return a 200 (OK) or 204 (No Content) status code.
- Other HTTP Request Methods:
- The source briefly mentions other HTTP request methods like HEAD, CONNECT, OPTIONS, and TRACE, noting that they are sometimes used but less frequently than GET, POST, PUT, PATCH, and DELETE.
In summary, these HTTP request methods define the action that a client wants to perform on the server, forming the foundation of communication in web APIs. Express.js provides methods like app.get(), app.post(), app.put(), app.patch(), and app.delete() to define how the server should handle requests made with these different HTTP verbs for specific routes.
Express.js Application Routing Fundamentals
Based on the sources, Express.js application routing is the mechanism that determines how an application responds to client requests to specific endpoints or URLs. It involves defining routes, which consist of a URL path (or pattern) and handler functions that will be executed when a request matches that path and a specific HTTP method.
Here’s a breakdown of Express app routing:
- Route Definition: In Express, routes are defined using methods of the app object (an instance of the Express application) that correspond to HTTP request methods. The basic structure for defining a route is:
- app.METHOD(PATH, HANDLER_FUNCTION);
- where:
- app is the Express application instance.
- METHOD is one of the HTTP request methods (verbs) like get, post, put, patch, delete, etc..
- PATH is the URL path (or pattern) on the server. It starts with a forward slash (/) and can include static segments, route parameters, and other patterns.
- HANDLER_FUNCTION is a function that will be executed when the route is matched. It receives two main arguments:
- request (often abbreviated as req): An object containing information about the incoming HTTP request, such as headers, query parameters, route parameters, and the request body.
- response (often abbreviated as res): An object used to send a response back to the client. It has methods like send(), status(), json(), etc..
- Base Route: The simplest route is the base route, accessed by just the hostname and port (e.g., http://localhost:3000/). You can define a handler for the base route using app.get(‘/’), app.post(‘/’), etc.. If no route handler is defined for a requested path, Express will typically respond with a “Cannot GET /” or similar error.
- Route Paths: Route paths can be simple strings, as seen in examples like /, /api/users, /api/products. They define the specific URL structure that the application will listen for.
- Request Handlers: The request handler function contains the logic that will be executed when a client makes a request to a defined route. This function can:
- Access data from the request object (e.g., query parameters using request.query, route parameters using request.params, request body using request.body after appropriate middleware is configured).
- Perform business logic, such as retrieving data from a database.
- Modify the response object to send data back to the client, set the status code, and control other aspects of the response. Examples include using response.send() to send text or JSON, response.status() to set the HTTP status code, and chaining methods like response.status(201).send().
- HTTP Methods and Routing: The HTTP method used in the client’s request (e.g., GET, POST) determines which Express route handler will be invoked for a given path. For instance, app.get(‘/api/users’) will handle GET requests to /api/users to retrieve a list of users, while app.post(‘/api/users’) will handle POST requests to the same path to create a new user. Express allows you to define different handlers for the same route path based on the HTTP method.
- Route Parameters: Express allows you to define dynamic segments within route paths called route parameters. These are denoted by a colon (:) followed by the parameter name (e.g., /api/users/:id). When a client makes a request to a URL matching this pattern (e.g., /api/users/123), Express captures the dynamic value (123 in this case) and makes it available in the request.params object under the name defined in the route path (request.params.id). This is useful for fetching or manipulating specific resources based on their identifiers.
- Query Strings/Parameters: Clients can send additional data to the server in the URL after the route path using a query string. The query string starts with a question mark (?) and consists of key-value pairs separated by ampersands (&) (e.g., /api/users?filter=Anson&sort=username). Express.js automatically parses this query string and makes the key-value pairs accessible as properties of the request.query object (e.g., request.query.filter would be “Anson” and request.query.sort would be “username”). Query parameters are commonly used for filtering, sorting, and pagination of data.
- Organizing Routes with Express Router: As an application grows, it’s good practice to organize routes into separate modules based on their functionality or domain (e.g., users, products). Express provides the Router class for this purpose.
- You create a router instance using express.Router().
- You can define routes on the router instance using the same HTTP method functions (router.get(), router.post(), etc.).
- Once you’ve defined the routes for a specific domain on a router, you can then mount that router onto a specific path in your main Express application using app.use(‘/api/users’, usersRouter). This means that all routes defined in the usersRouter will be prefixed with /api/users in the application.
- Using Router helps in keeping your main application file (index.mjs or similar) cleaner and makes it easier to manage and maintain routes for different parts of your API. You can even create an index.mjs file within your routes directory to act as a central place to import and register all your individual routers.
In essence, Express.js routing provides a structured way to map incoming client requests to specific server-side logic, enabling you to build well-organized and scalable web applications and APIs.
Express.js Request and Response Objects
In Express.js, the request and response objects are fundamental to handling client interactions with your application. They are passed as arguments to every route handler and middleware function, playing crucial roles in receiving information from the client and sending data back.
Here’s a breakdown of these objects based on the sources:
1. The Request Object (request or req):
- The request object contains all the information about the incoming HTTP request from the client.
- It serves as a central repository for data sent by the client, allowing your server-side code to access and process it.
Key properties and methods of the request object mentioned in the sources include:
- request.headers: This property holds all the HTTP headers sent by the client. This can include information like the user-agent, content type, and importantly, cookies before they are parsed.
- request.body: This property contains the data sent in the request body of HTTP methods like POST, PUT, and PATCH. By default, Express.js does not parse request bodies, so you need to use middleware like express.json() to parse JSON data into this object.
- request.params: This object contains route parameters captured from the URL. When you define a route with placeholders (e.g., /api/users/:id), the values of those parameters are available in request.params (e.g., request.params.id).
- request.query: This object holds the query parameters sent in the URL. These are key-value pairs that appear after the question mark (?) in the URL (e.g., /api/users?filter=name). Express.js automatically parses these into the request.query object (e.g., request.query.filter).
- request.cookies: After using the cookie-parser middleware, this object will contain the parsed cookies sent by the client. Each cookie is available as a property of this object (e.g., request.cookies.hello).
- request.signedCookies: If you are using signed cookies with cookie-parser, this object will contain the parsed and verified signed cookies.
- request.session: After using the express-session middleware, this object represents the session associated with the client. It allows you to store and retrieve user-specific data across multiple requests.
- request.user: After using Passport middleware for authentication, this property typically holds the authenticated user object.
2. The Response Object (response or res):
- The response object is used to send data back to the client and control various aspects of the HTTP response.
- It provides methods to set headers, status codes, send data, and manage cookies.
Key methods of the response object mentioned in the sources include:
- response.send(body): This method sends the HTTP response to the client. The body argument can be a string, an HTML buffer, an object, or an array, and Express.js will automatically set the Content-Type header appropriately (e.g., text/html for strings, application/json for objects/arrays).
- response.status(code): This method sets the HTTP status code for the response. It accepts a numeric status code as an argument (e.g., 200 for OK, 201 for Created, 404 for Not Found, 400 for Bad Request, 401 for Unauthorized, 403 for Forbidden). This method can be chained with other response methods like send().
- response.sendStatus(code): This method sets the HTTP status code and sends the corresponding status text as the response body.
- response.cookie(name, value, [options]): This method is used to set a cookie in the client’s browser. It takes the cookie name, the cookie value, and an optional options object to configure cookie attributes like maxAge, expires, domain, path, secure, httpOnly, and signed.
- response.clearCookie(name, [options]): This method is used to clear a previously set cookie on the client by setting its value to an empty string and its maxAge to zero.
- response.json(obj): This method sends a JSON response to the client. It automatically sets the Content-Type header to application/json and converts the JavaScript object or array to a JSON string.
Interaction in Route Handlers:
Within a route handler function, you typically use the request object to access data from the client’s request and the response object to send back the desired information or perform actions like setting cookies or redirecting the client.
Example:
Consider a GET request to /api/users/:id. The route handler might access the user’s ID using request.params.id, fetch the user data from a database, and then use response.json(user) to send the user data back to the client as a JSON object. If the user is not found, the handler might use response.sendStatus(404).
Understanding the request and response objects and their properties and methods is crucial for building robust and interactive web applications with Express.js. They enable the server to effectively communicate with clients by receiving their requests and sending back appropriate responses.
Express.js Middleware: Concepts and Usage
Based on the sources, middleware functions in Express.js are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle, commonly denoted as next.
Here’s a more detailed breakdown of middleware functions:
- Role and Functionality:
- Middleware functions act as an intermediary between the server receiving a request and the final route handler processing that request.
- They can execute any code.
- They can make changes to the request and the response objects.
- They can end the request-response cycle by sending a response to the client.
- They can call the next middleware function in the stack.
- Arguments: Each middleware function receives three arguments:
- request (req): Contains information about the incoming HTTP request (as discussed previously).
- response (res): Used to send a response back to the client (as discussed previously).
- next: A function that, when invoked, passes control to the next middleware function in the application.
- The next() Function:
- Calling next() is crucial for allowing the request to proceed through the middleware stack and eventually reach the route handler (or the next middleware).
- If next() is not called within a middleware function, the request will be left hanging, and the client will not receive a response.
- The next() function can optionally take an error object as an argument. If an error is passed to next(err), Express will skip any remaining non-error-handling middleware functions and will proceed to an error-handling middleware (though this is not explicitly detailed in the provided source). If no argument or null is passed, Express assumes everything is successful and moves to the next middleware.
- Registration of Middleware: Middleware functions can be registered at two levels:
- Application-level middleware (Global): These are bound to the entire application instance using app.use(). Middleware registered this way will be executed for every request that comes to the application, in the order they are declared.
- Route-level middleware (Specific Endpoints): These are bound to specific routes. You can pass middleware functions as arguments to route definition methods (app.get(), app.post(), etc.). They will only be executed for requests matching those specific routes, and they are invoked in the order they are listed.
- Order of Execution: The order in which middleware functions are registered using app.use() and the order in which they are passed as arguments to route handlers matters significantly. Middleware functions are executed sequentially in the order they are added to the middleware stack. If a middleware function sends a response and does not call next(), the subsequent middleware functions for that route will not be executed.
- Built-in Middleware: Express.js itself provides some built-in middleware functions. The source mentions express.json(), which is used to parse incoming requests with JSON payloads. When registered using app.use(express.json()), it populates the request.body with the parsed JSON data.
- Third-party Middleware: Many third-party packages provide middleware functions that extend the functionality of your Express application. For example, express-validator provides middleware functions like query() and body() to validate request data. These middleware functions perform validation checks and attach validation results to the request object. You then use the validationResult() function to check for any validation errors within your route handler.
- Custom Middleware: You can write your own middleware functions to encapsulate reusable logic that you want to execute before your route handlers. The source provides an example of a loggingMiddleware function that logs the request method and URL. Another custom middleware example is resolveIndexByUserID, which was created to find the index of a user in a mock array based on the ID from the route parameters and attach it to the request object for subsequent middleware to use.
- Reusability: Middleware promotes code reusability. By extracting common logic into middleware functions, you can apply the same functionality to multiple routes without repeating code. For instance, the logic to resolve a user by ID was moved into a middleware function and reused across put, patch, delete, and get requests for user-related endpoints.
In summary, middleware functions are a powerful feature of Express.js that allow you to intercept and process requests before they reach your main route handlers, enabling you to perform tasks like logging, authentication, data validation, and more in a modular and reusable way. The order of middleware registration and the proper use of the next() function are crucial for ensuring the correct flow of your application’s request-response cycle.
Express.js User Authentication Methods and Strategies
Based on the sources, user authentication in Express.js can be implemented using various methods, ranging from basic credential checks to more sophisticated approaches using sessions, cookies, and dedicated authentication libraries like Passport.js.
Here’s a discussion of user authentication based on the provided material:
1. Basic Username and Password Checking (Without Sessions):
- Source demonstrates a simple login endpoint (/api/off) that receives a username and password in the request body.
- It retrieves a user from a mock users array based on the provided username.
- It then performs a direct comparison of the provided password with the password associated with the found user.
- If the user is not found or the passwords do not match, it returns an “unauthenticated” status (401) with a “bad credentials” message.
- This approach does not involve maintaining any session state, meaning the user would have to authenticate on every request to access protected resources.
2. Authentication Using Sessions and Cookies:
- Source expands on the basic check by introducing express-session to manage user sessions.
- Upon successful username and password verification, it modifies the request.session object by attaching a user property to it, storing the authenticated user’s information.
- Express session then automatically sets a cookie in the user’s browser containing a session ID.
- On subsequent requests from the same client, the browser sends this cookie back to the server.
- express-session middleware uses the session ID from the cookie to retrieve the corresponding session data stored on the server (initially in memory).
- By checking for the presence of the user property on the request.session object, the server can determine if the user is authenticated for subsequent requests. Source creates a /api/status endpoint that checks request.session.user to determine the authentication status.
- Source further illustrates this by showing how different clients (Thunder Client and Postman) can have different sessions and be authenticated as different users simultaneously, with the server managing multiple sessions.
- Source introduces cookie-parser middleware, which parses cookies from the request.headers and makes them available in the request.cookies object. This is necessary for express-session to function correctly.
- Source also briefly discusses using cookies for basic authentication checks, where the presence or value of a specific cookie determines the server’s response. However, the primary use of cookies in the context of these sources is for maintaining session IDs.
- Source also touches upon signed cookies for added security, requiring a secret to be provided to cookie-parser.
3. Authentication with Passport.js:
- Sources through extensively cover using Passport.js, a popular authentication middleware for Node.js.
- Passport supports various authentication strategies, including:
- Local Strategy: Source details how to implement local authentication (username and password stored in the application’s database).
- It requires installing passport and passport-local.
- A Local Strategy is defined with a verify callback function. This function receives the username and password from the request and is responsible for:
- Finding the user (e.g., in a database).
- Verifying the password (comparing the provided password with the stored password, which should be hashed for security). Source introduces bcrypt for hashing passwords and bcrypt.compareSync for comparing them.
- Calling the done function with an error if authentication fails, or with the user object if authentication succeeds.
- Serialization (serializeUser) and Deserialization (deserializeUser): Passport uses these functions to manage the user’s identity within the session.
- serializeUser determines which data from the user object should be stored in the session. Typically, only a unique identifier (like the user’s ID) is stored.
- deserializeUser is responsible for retrieving the full user object from the stored identifier in the session on subsequent requests. This user object is then typically attached to the request.user property.
- Passport Middleware: app.use(passport.initialize()) initializes Passport, and app.use(passport.session()) integrates Passport with express-session.
- The passport.authenticate(‘local’, …) middleware is used on the login route to trigger the local authentication process.
- OAuth 2 Strategy (Discord as an Example): Sources explain how to implement authentication using a third-party provider like Discord via OAuth 2.
- It requires installing the specific Passport strategy (e.g., passport-discord).
- An OAuth 2 Strategy is configured with details obtained from the third-party provider’s developer portal, such as client ID, client secret, and redirect URL (callback URL).
- The strategy also defines a verify callback. In the OAuth 2 flow, after the user authorizes the application with the third-party provider, the provider redirects the user back to the application’s redirect URL with an authorization code. The verify callback receives access tokens, refresh tokens, the user’s profile information from the provider, and a done function. It’s responsible for:
- Checking if the user from the third-party provider exists in the application’s database.
- If not, creating a new user record (often linking it to the third-party account’s ID).
- Calling the done function with the user object.
- Similar to local strategy, serializeUser and deserializeUser are crucial for managing the user’s session after successful OAuth 2 authentication.
- Specific routes are set up to initiate the OAuth 2 flow (e.g., /api/oth/discord) using passport.authenticate(‘discord’, …) and to handle the callback from the provider (e.g., /api/oth/discord/redirect) also using passport.authenticate(‘discord’, …).
- Scope: When setting up the OAuth 2 strategy, you can specify the scopes (permissions) your application requests from the third-party provider (e.g., ‘identify’, ‘guilds’, ’email’ for Discord).
4. Session Stores for Persistence:
- Source addresses the issue of session data being lost when the server restarts (as it’s stored in memory by default with express-session).
- It introduces session stores (e.g., using the connect-mongo package for MongoDB) to persist session data in a database.
- By configuring express-session with a session store, session data is saved to the database, allowing sessions to be restored even after server restarts.
5. Logging Out:
- Source shows how to implement a logout endpoint (/api/oth/logout).
- It uses the request.logout() function (provided by Passport) to clear the user’s session.
- After logging out, subsequent requests to protected resources will fail authentication.
In summary, the sources demonstrate a progression of user authentication methods in Express.js, starting from basic checks to utilizing sessions and the comprehensive Passport.js library for both local username/password authentication and integration with third-party OAuth 2 providers. The importance of secure password handling (hashing) and persistent session storage is also highlighted.
The Original Text
hello everyone my name is Anon and in this tutorial I will teach you how to build a web API using the expressjs framework Express is the most popular server sided web framework in the node.js ecosystem it is widely used by many developers it’s in over 20 million projects according to GitHub it has over 27 million weekly downloads according to npm and it is used by a lot of companies ranging from startups all the way to Fortune 500 companies but why is it so popular though well mainly because expressjs is very easy to learn it makes it very easy for you to set up an API in less than 30 seconds it’s unated which means there’s not much if not there’s really not any overhead at all you don’t have to worry about configuring a bunch of different properties in your application before you can actually use it all you have to do is just in install the package instantiate the express app and then listen to a port and then begin listening to requests that’s it there’s no right or wrong answer when it comes to building web apis using a framework that is unopinionated like expressjs and because of that that is why till this day over the past perhaps 10 years now Express is still the dominant framework that many people choose to use whenever they want to build their next project now for those of you who are not really familiar with how web apis interact with other applications I have a simple diagram over here that we’re going to go over right now expressjs remember is a serers sided application so pretend that right over here on the right hand side this server is our is where our express application is going to live and then we have our clients so these are typically just regular users that will use your application either on a mobile device such as a phone or a tablet or they’ll use it on a computer either via the web browser or a desktop client now let’s say for example we have an e-commerce website and that e-commerce website when you visit it it displays a list of products those products needs to come from somewhere they don’t just randomly appear when you click on those products you can see more information about it but where does that information come from where does all the data come from well most of the time it comes from a server comes from a web API but the client doesn’t just automatically receive that data from the server the client needs to make what is called an HTTP request HTTP stands for hyper text transfer protocol it pretty much just means hey this is how I want to exchange data with you okay there are many different types of protocols but HTTP is one of the most popular ones out there so let’s go back to our example of the e-commerce app the moment that you visit the homepage of the e-commerce app what happens is the code on the client side will make an HTTP request to the server side application okay in our case it will be the express API the express API will receive that request and it will say okay I just received receive the request to send back a list of products for the client I don’t care how the client uses it I don’t know what they’re going to do with it but my responsibility is just to get that list of products and send it back to the client so what the server will do is it’ll perform some business logic and then it will produce an output okay in this case the output is retrieving the list of products and the client itself never actually sees this operation going on so think of it like this let’s say you’re at a restaurant and you sit down you’re at a table the waiter comes to you the waiter in this case is the server the waiter asks you what you want you request the waiter hey this is what I want to eat the waiter will send that request back to the kitchen back to where all the chefs are working so you can think of the kitchen like the server you never actually see what’s going on in the kitchen all you know is that after a certain amount of time the waiter will come back with a response in this case that response is going to be your food in our case for our e-commerce application the response that we are getting from the server is going to be a list of products hopefully that makes sense and now we are finally ready to dive into setting up our expressjs project and writing some code so let’s go ahead and get started so right inside my windows Powershell I’m going to go ahead and create a new directory and I’m going to call this expressjs tutorial I’m going to go ahead and CD into that directory and let me just clear up my console I’m currently using using node.js version 2.4.0 as of right now the time of recording this video however there hasn’t really been any major breaking changes with expressjs between different node.js versions so even if you’re using an earlier version or a later version you really won’t run into any issues at all so don’t worry about that so let’s go ahead and type npm init hyphen y to initialize this folder as an npm repository and this will give us a package.json file that’s generated for us and and let’s go ahead and open up visual studio code or whatever text editor you prefer to use and let’s just take a look at this package Json file and there’s nothing in here uh for the dependencies just yet we need to install it so let’s go ahead and install Express so I’m going to type npm I or install I is short for install and then Express and just hit enter and now this will install Express for you and that’s it that’s the only package that we need to install it’s that simple let’s go ahead and install actually one more tool for development I’m going to install nodemon and what nodemon allows you to do is run your application in watch mode so as you’re saving changes to your source code the process will automatically restart based on file changes so you don’t have to manually exit out of the process and restart it again so I’m going to install nodon as a Dev dependency so I’m going to use the hyphen D flag as you can see right down over here let me zoom in a little bit more and I’ll type nodemon okay and what I’m going to do is I’m going to set up uh a script so right inside the scripts object I’m going to set up a start colon Dev script and this will use nodemon to run our our main Javascript file so that file doesn’t exist yet we need to create it but I’m going to go ahead and create a folder called Source in just a bit and the main file will be called index.js so this will be the entry point to our application I’ll create one more script called start and this will just be a simple script to just use a regular node command to run our application so not in watch mode so this will typically be for production when you’re ready to deploy the API now there’s one more thing that I want to do inside this p package.json file I’m going to go ahead and set this type property and you can see that there’s two values uh commonjs or module I’m going to set it to module and what this will allow me to do is use esm as my module system so that way I can use the modern import export statements instead of having to use require to import modules and module that exports to export stuff because I’m using uh esm modules I need to actually change the file extension to MJS in order for this to work so let’s go ahead and do that and don’t worry everything will still work fine it really doesn’t make much of a difference except for you have the latest um modern versions of importing and exporting modules that’s really all it is for let’s go ahead and continue I’m going to go ahead and create a new folder called Source SRC and I’ll create a new file called index. MJS and now what we’re going to do is we’re going to import Express from Express just like that so I’m basically importing the entire Express module from this Express package now the imported value of this Express name is actually a top level function and we need to call this function in order to create an express application so what I’m going to do is I’m going to first declare a variable let me zoom in a little bit more I’ll call it app and then I’m just simply going to reference Express and then invoke that function by using parentheses and that’s all and that’s all you have to do now that we have our Express app I can reference the app variable and whenever I use the dot operator you can see that there are a bunch of different methods and properties that I can reference now it might be a little bit overwhelming at first but don’t worry the method that we need to call is the listen method and this pretty much allows you to listen to a port for incoming requests this is actually what starts up the express server on a specific port and then you can begin receiving incoming HTTP requests so let’s go ahead and set a port Port uh you can pass in really any port you want I’m going to go ahe and pass in Port 3000 but instead of just passing in a hardcoded number for the port for best practice it’s best to assign your port to a variable called port in this case and then you can reference process which is a global in node.js and then process has an object called EnV and from here you can access your environment variables so we would assume that there is going to be an environment variable for ports but if the environment variable for Port is undefined then we can have it assign this leftand value with our logical or operator right over here let’s go ahead and reference app now and call. listen and pass in Port and then I’m going to go ahead and pass in a callback function so you can use this to perform post-processing operations once your server has uh started up so maybe if you want to send an event to some centralized logging system so that way they know that the server was just started up at this time you can do that inside this callback function however I’ll simply write a console log and I’ll use string interpolation um and then I’ll go ahead and write running on Port and then I’ll log the port okay so let’s go ahead and start up our application and make sure that it works so I’ll go into the terminal now and I’m going to run that start Dev script so let’s type npm Run start colon Dev and now you’re going to see that nodemon will start up this application and you can see that now it says running on Port 3000 now if you want to test this out you can simply just go to your web browser and just type Local Host colon and then the port number that you are listening to requests on since I’m listening to requests on Port 3000 I would type Local Host colon Port 3000 right now you can see that it says cannot get and this is because we don’t have anything registered just yet okay we need to actually register what’s called a route in order for us to start requesting something from the server and then receiving a response so hope hopefully this all makes sense so now that you finally know how to set up a simple web server using expressjs I’m going to show you how we can Define routes and access those routes to receive different responses but first of all what exactly is a route well think of it like this currently we were trying to access Local Host Port 3000 okay and this was the base route and we actually don’t have anything set up up to be returned from the base route so whenever we try to access it that’s the reason why it said cannot get slash because we didn’t have any resolver to map a response back to that route but a route in general is think of it like a path in your express application so determining which path you want to take gives you different outputs so for example if you go to let’s say the users route let’s say if I have a users route defined on my server this will give me a list of users if I wanted to get a list of products I would access the products route and all you do is just you just add this forward slash and then the name of the route at the end of the host name and the port in actual real uh applications that are deployed you typically don’t have the port uh exposed like this so it would just be after the host name like something like Local Host test.com products okay so you define these routes on your Express server and then you allow your clients to make requests to those routes now remember how in the introduction I mentioned in order to request data from the client to the backend server you need to make an HTTP request well there are actually different types of HTTP requests and these are known as HTTP verbs so these verbs pretty much are ways on how you can tell the server to perform some operation so for example you don’t always want to just get data sometimes you might want to create data by saving it to the database once it’s reach the server sometimes you want to update data sometimes you want to delete data there are different types of request methods that we use to handle these operations and you’ll learn that later on but first let’s go ahead and set up a simple get request so let’s go ahead and reference the app and we’re going to go ahead and call this get method right over here and and it’s going to take in an argument which is going to be a string as the first argument and right over here is where you can specify what route you want to register in your Express app So currently I don’t have any route handling the base SL route so I’m going to go ahead and configure a route for that so whenever the user visits this route They will receive a response but we actually need another piece in order for this whole thing to work we need what is called a request Handler and that is actually the second argument to app.get so the request Handler is just a function but in this case it’s a callback function so it would look like this so I’ll pass a simple arrow function and this callback function has two arguments okay it has a request argument which is the request object itself this contain contains everything related to the incoming HTTP request so for example if you passed in HTTP headers from the client side to the server side that would be inside the header property in the request object if you were to send data in the request body that would be accessed by grabbing it from the request body property if you wanted to access cookies if you wanted to access the IP address all of this stuff comes from the request object okay now the second argument is the response object the response object is what you can use to modify the response and send it back to the user so you can set the status code as an example you can send back uh data you can send back text you can send send back HTML you can send back text you can send back HTML you can send back a Json object whatever it is that you want so let’s go ahead and reference the response object to to send back a response so I can reference response and call the send method and I’ll just send back a simple hello world string just simple plain text so now if I visit the Local Host Port 3000 and if I go to just the base route you can see it says hello world okay pretty simple I can go ahead and also send back a Json object I’ll say hello I refresh I now see it is parsed in this Json format right over here uh I can also set the status code as well so I can do that very easily by referencing response. status and this is a method so you can just pass in whatever status code you want I’ll set it to just for a demonstration purposes I’ll set it to 2011 2011 is actually used for post requests whenever you create a resource but I just want to show you that this is what the status code is because by default the status code whenever it is successful is a 200 status code okay and after you set the status code you can actually chain these methods together so after I call status I can also just call do send and then just pass in a requ a response body so now if I refresh and let me open up the uh let’s see the network tab right over here you can see that now the status code says 2011 let’s let’s go ahead and Define a few more routes so that way you all get the hang of this so I’ll go ahead and Define a route uh called slash users now whenever you are building apis you typically want to prefix all of your endpoints with a slash API prefix and this is industry standard a lot of companies that have apis do this it’s just good practice so I would highly recommend you all to follow this approach okay so/ API SL users so this is now our route so whenever we access this in our browser we don’t visit SL users we’re visiting SL API users okay so as a second argument we need our request Handler of course so let’s pass in the request and response object and what I’ll do is I’ll simply just send back an array of fake users so I’m just going to pass in an array in the send method as an argument and in my array I’ll just provide some users so I’ll set the ID to one username ansen display name Anson we’ll keep it simple I will just copy and paste this a few more times and just change up the values so let’s do Jack and then Adam now let’s save okay and now whenever I go to the browser and let me just kind of like move this over to the to the side a bit when I go to slash API users this is the route or the endpoint I’m going to use those terms synonymously route and endpoint this is the route that I am going to be making a request to from the browser in this case the browser is our client okay we’re making a request to SL API users and then when I hit enter you can see as a response this is what I get back I get back this array and this array has three users okay and if you were getting this data let’s say on your react code you would render this out to the client so they can actually see all the users okay let’s go ahead and create one more Let’s do app.get let’s do uh SL API SL uh products request and response so now you should get the hang of doing all of this and the whole reason why I’m showing you multiple examples is that way so you are familiar with this so once again we have our endpoint our route name defined right over here/ API products and then we also have our request Handler and I’m going to go ahead and send back a response now so I will reference the response object and I’m going to go ahead and call do send and then what I’ll do is I’ll just send back an OB uh a Json object which is this in this case is going to be an array and I’ll do the same thing ID of let’s do one two 3 username or what am I doing not username uh let’s do name let’s do chicken breast and then price let’s do $12.99 okay and now if I go to the browser and if I visit SL API product I’m making a request to this route it’s going to give me that array of products and I can see this stuff right over here so now what I will do is I’ll show you how we can use route parameters to be able to dynamically pass data to the server in the route and this can actually make it so that we we can receive Dynamic data based on whatever the value of that parameter is so I’ll give you an example right now we are only able to receive all of the users let’s just pretend that this users array comes from a database we are receiving all of the users in an array but what if I wanted to actually receive only one user based on some unique identifier such as the username or the ID how would I do that well this is where route parameters come into play you can use route parameters to pass in a dynamic value in the route path and then the server would receive that request it would check what the route parameter is and then since we know that we’re going to be dealing with users because we would be visiting SL API users and then the route parameter would be placed after that we would go ahead and grab the correct user from our database in this case we’re going to grab it from our array so the way that you define a route parameter is like this so right underneath uh my AP API SL users route I’ll go ahead and set up another one but this time we will be using a route parameter so I’ll call app.get and then SL API SL users and then slash and then here’s where I want to Define my route parameter what I can do is I can use the Colin symbol and then give my route parameter a name I’m going to go ahead and give the name ID and then we’re going to pass in a request Handler so the same that we’ve been doing so far and now whenever I visit SL API SL users and then slash and then the ID whatever I pass in it’s going to go ahead and hit this endpoint so I have one endpoint or one route defined to give me all the users and then I have another route that has a route parameter that gives me a single user record based on the route parameter ID let’s go ahead and do this I’m going to show you first first how I can grab that route parameter and we do that by referencing it from the request object so I can go ahead and console log this right now if I reference request. prams this is an object that gives you all of the route parameters because you can have multiple you don’t need to only necessarily have one you might have more than one you might have an ID maybe you might have a username but typically in our in this situation we we really only need one so what I’ll do is I’ll console log this and I’ll go back to my browser and I’ll show you what happens when I visit SL API users and then slash1 and then let me show you the console you can see that right over here the console logged an object and that object contained that route parameter as a field ID and then it mapped to this value of one so hopefully that makes sense so I again like I said I can pass in literally any value I want I can pass in 500 and then whenever the server receives that request it will log uh this object ID as a field of 500 so what I’ll do is I’m going to go ahead and grab the user from the array by its ID so let me just First Take This array and I’m going to move it up top over here so that way I can reference it all throughout my code const uh mock users and I’ll sign it to this array and then let me just send back that mock users array and then what I’ll do is a couple things one notice how if you looked at the logs the value of ID is actually a string but in our case our users have a numeric ID so we want to convert that into an actual number and this is kind of like a brief little intro to how you can perform valid ation for your incoming get requests okay so what I’ll do is I will create a variable called par ID and I’m going to use the parse in method and I’m just simply going to pass in request. prrams do ID but here’s the other problem though we don’t know if uh the user even provided an ID at all well if they didn’t then it would go to the API users route like for example if I didn’t pass in an ID it would just go to/ API users so in because this is the case we don’t really need to check if ID is defined because we know that it’s going to be there but we do need to make sure that the value is valid in our case we want to make sure it’s a valid numeric value so what I can do is I can parse this uh pam. ID value and if it is a valid numeric string then it’ll convert it over to the actual integer itself if it’s some regular non-numeric string then it will be not a number so if I were to conso log par ID and then if I go to the browser and if I refresh and I just pass in some invalid numeric or some non-numeric ID and the console it will log not a number Nan which stands for not a number for the par ID value so we can use uh an if condition and we can use this is not a number function and then I can just pass in par ID okay and in this case since we’re passing in an invalid ID is Nan would return true so if it is not a number then what I want to do is I want to return perhaps a status code that indicates that this is an invalid response or this is an invalid request so what I’ll I’ll do is I will return response and I’m going to go ahead and call the status method and I’ll pass in for the code the number 400 which means bad request and then I’ll just simply call send and then maybe an error message bad request okay and I can even add additional additional notes invalid ID all right so now if it is in fact a valid number then we can perform some operations we can interact with our mock users array so I’m going to go ahead and now write the logic to find a user so const user or find user equals mock users and I’ll just simply use the find method and I’ll pass my predicate so we’re going to search based on the ID so we’re going to pass in this callback function or predicate function and we we’re going to have access to the user object that is currently in the array and we’ll check to see if user. ID matches so triple equals pars oh whoops did I oh you know I forgot this is actually par ID sorry about this it’s pars ID not parse ID so pars ID okay and now uh if the user does exist well let’s do if the user does not exist then I’ll just return response so we’re going to do the same thing that we did above on line 29 right over here so this is the point where you have different paths that your controllers or that your request handlers can take so in our case we have three different outputs and later on around the end of this tutorial you’ll learn how to unit test these these uh these functions but you can see right over here that currently I have three different outputs whether the ID that I passed was invalid so it sends back a 400 or if the user is not found then we want to send back a 404 because that indicates not found so I’ll return response. status and pass in 404 or you know there’s also the uh I think there’s a send status method so that way I can just send the status and I don’t have to send I don’t have to call do send again at the end um and then if the user is found then we’ll just return response dot send find user just like this so we have three different possibilities for this endpoint okay so hopefully that makes sense now let’s go ahead back into our app if I refresh you can see it says bad request invalid ID if I pass in let’s say an ID of a user that does not exist it says not found and you can see on the console it gives us that 44 if I pass in an ID of one it finds the user and I can see it right over over here and same thing if I pass in two and three I get all of the users that are in that array so hopefully that shows you how to use route parameters so now I’m going to go ahead and talk about query strings and query parameters and how they are used in backend development and now we can actually use them ourselves so many of you may have seen something at the end of the website address so in the browser address URL you might see this question mark and then you might see something like key equals value and then you might see an ENT symbol and you might see another key equals value this is known as a query string so right over here this question mark symbol denotes that we have a query string and they go at the end of our uh defined route over here okay so you have the domain and then the route the path and then the query string at the end and then after the question mark you basically just pass in whatever key value pairs you want so for example I have uh a key called key and I use the equals operator to assign a value to it so it’s kind of like assigning a value to a variable but only we’re doing it in the address bar so key equals value and if I wanted more query parameters in the query string I can just simply use this ersan as a delim so ersan and then the next key value pair so key 2 equals value 2 I can have as many query parameters as I want now there are different ways that you can use Query parameters in web development you can send query parameters from a page to another page on the client side so that way you can send data uh across different pages so let’s say if one page needs data from another page when you’re navigating then you can grab the the values from the query query string if you’re sending it from the client side to the serice side typically you would send a query string to uh add additional data to the request that you normally wouldn’t add in a request body we haven’t gotone to post requests just yet but I’ll stick to a get request as an example so when you make a get request remember that you are performing a request an HTTP request to get data in readon format you’re not manipulating any data at all on the server side so sometimes you might need to retrieve the data but you also want to have that data already um manipulated in a certain way on the server side so for example up top over here I added a couple more user objects so let’s say I have this users array and let’s pretend it’s from the database and let’s say I want all of these users returned back but I wanted it sorted in alphabetical order based on the username or you can also have it sorted based on the display name maybe you might also want it sorted in um from least to greatest based on the ID value since these IDs are integers so you would use a query string to do that let’s say if you also want to filter out some results from the users itself maybe you don’t want to get every single user from the database you only want to get only specific users that match whether their user matches a substring so maybe I only want to get all the users that have an A in their username field so hopefully that makes sense with query parameters and how they can be used so let’s go ahead and see how we can actually send query strings and query parameters to our server so inside my/ API users route inside the request Handler function I’m going to go ahead and consol log this request. query object remember how I said earlier the request object has everything that you can possibly get in regards to the request itself so earlier we referenced request. prams to get the route parameter so to get the query parameters from the query string we just reference request. query so let’s go ahead and send a query string when we are making this request to the SL users end point so I’m going to use the question mark symbol and then provide some key value pairs I can literally pass any key value pair I want so let’s do something like filter and we’ll assume the filter is going to be based on username um so I’ll do filter uh Anson and I’ll go into my console uh let me actually just rerun the request so you see how whenever I send a request a get request to that endpoint in the console it logs that request query object and it has the filter which is the key that I passed in the query parameter filter it is showing up as a field in that object that query object and we have the uh string Anon as the value so the query string gets parsed into a Json object by Express so we can very easily grab the values let’s go ahead and actually do something realistic with the filtering so what I’ll do is this I want to make it so that I can filter based on sub some substring so I want to go ahead and also make it so that I can also set which field in this mock users array in in these objects I want to make sure I can set which field I want to filter on so maybe I want to alternate between filtering by username or display name so for the filter value we can expect it to only be two possible values username or display name and this will tell us what uh key in the user object what field to filter by or yeah what what field to filter and then we will add an additional query parameter can call it whatever you want but I guess we can call it a value just to keep things simple and then this this value will basically be the uh the text the substring that you want to have that username contain so if I want to filter everything where it contains the an substring so a an substring then we would have to search for that okay so I’m going to send these two query parameters to the server okay so now I’m going to go into go back to the request Handler for the users endpoint and what I’ll do is this I’m going to destructure that query object from the request object and then I also want to destructure from the query object the two query parameters filter and value and I can do that all in one go like this so I can use so after query I can additionally destructure properties from query so let’s do filter and value and so what I want to do is I want to make sure that both of these query parameters exist because of course if they don’t exist then we’re not going to do any filtering at all so the easiest case that we can handle is we check to see if both of these values are undefined because if they are then we don’t need to do any filtering we just return mock users as is so we’ll you write an if case if there’s no filter and there’s no value then we will just simply return response. send and then call or not call uh pass and mock users in this do send method call okay that’s the easiest case I’ll write a simple comment when filter and and value are undefined okay and we always want to make sure that both of these query parameters are defined because you need both of them of course you can’t have a value and not know what field in the user object you want to filter by and if you have the filter query parameter defined you need to make sure you have an actual text that you want to filter uh that you want to filter based on so we need to make sure that both of these are defined so we’ll do if filter and value if filter and value we will return and we’ll call response. send and from here I should just be able to write a simple filter function so mock users I can use the filter function on the array and pass in a predicate so what we’re going to do is we’re going to pass in this callback function also known as a predicate function and this will this call function has uh the user as an argument and then what we want to do is we want to filter out all of the we want to filter all the user objects that match that have that value as a substring so it’s pretty easy we can do user. username because remember we’re filtering by by the username or actually it would be user square brackets filter okay and this is assuming that filter would either be display name or username so user filter so this would grab the correct field and then we would want to so this is a this is going to be a string so we would want to make sure we check to see if the string contains that substring so we actually have this um includes and this method returns true if search string appears as a substring of the result of converting this object to a string okay so I can pretty much call do includes and I’ll pass in the value so this will filter all of this will basically grab all of the user objects that pass this predicate so if the user and whether we are filtering by username or display name if let’s say for example let’s stick with username if the username includes the value that we’re trying to filter then it’s going to return that into a new array and then once all of the filtering is done we’re going to send the entire array back so let’s go ahead and test this out so right now if I let’s do this if I don’t have any of the query parameters at all you can see that it will just return the array as is okay it doesn’t uh it doesn’t do anything we have everything sorted we have everything the way it is nothing is sorted nothing is done let’s go ahead and add a filter so filter let’s filter by username and now notice how if I were to only have the filter but no value you’ll see how it doesn’t return anything yet the request is still pending that’s because we need both filter and value okay we’ll handle these cases as well so let’s go ahead and handle a case where we have both filter and value as a query parameter so for the value query parameter I will set this to be a n and now you’ll see this will grab me all of the user objects where the username has a n as a substring and if you look right over here it seems to be filtering correctly uh I can go ahead and do another simple case where let’s filter the username where it includes e as a substring and you can see that seems like the only username that I have that has an e as a substring is Henry okay uh let’s see what else let’s try um let’s try a I have 1 two 3 4 five so it’s missing uh this object Henry so our filtering is working great okay so let’s just finish this out um so let’s make sure we handle all the other cases where if we don’t have both of these um both of these defined then we return the same mock users that is in memory so we don’t do any filtering at all so I think the easy thing to do is actually this instead of uh doing this if check right up here where we check both a filter and where we check if there’s no filter and there’s no value what we’ll do is we’ll check if there’s fil filter and if there’s a value and if this condition fails that means it only has one or the other defined or both are undefined so then we’ll just return response. send mock users so I just realized that I’m going to fix that real quick and now when I go back to the browser if I only have one query parameter it won’t do any filtering at all okay hopefully this makes sense now that you all know how to retrieve data from the express API using get requests I’m going to show you how you can create data using what is called a post request now let’s say for example you want to create a resource on the backend and that backend will save it to a database or save it to a file or save it just somewhere doesn’t matter where it is you want to create let’s say a user so your client your front-end application will have a user form they fill out their username password email and other additional Fields once they are ready they will click that signup button when you click that sign up button it will make an API request to the backend doesn’t have to be necessarily an Express API server it can be really any API server that’s running that handles that post request okay so the front end the client side would make an HTTP request a post request to the server okay okay once the server receives that request the server needs to obviously be able to grab the data that we’re trying to send from the client side to the backend and that data that you’re sending is known as a request body so whenever you make post requests the data that you want to send to the backend server you send it via a payload or a request body you use those terms synonymously so payload request body are interchangeable terms the backend will then take that data and it will perform the necessary operations in need so typically validation if it needs to do additional parsing if it needs to make sure that it has the proper Fields it will do all that stuff before it can proceed with either saving it to a database or saving it to some external API Source whatever it is I needs to do once it’s done saving that record to the database or somewhere it will return a 2011 response which or 2011 status code which typically just means that the resource was created sometimes it might also return the new record that was created so that way if you need to use it on the client side for whatever reason you can do so now before we actually can make any post requests we do need an htgp client to actually uh make those requests and also be able to send a request body to our Express API because on the browser there’s no built-in tool that enables you to send request bodies unless if to write the code in the JavaScript console but we’re not going to do that um so there are different uh clients that you can use to interact with your API So currently we’ve just been using the browser which we limited to just making get requests by simply typing in the address in the address bar we want to be able to make post requests where we can send actual data okay so you can use tools like Postman there’s also Hopscotch which is an alternative to postman for this tutorial I’m going to keep things simple I’m going to keep everything inside vs code and we’re going to install this extension so on the left hand side or um wherever you have this extensions icon just click on extensions and you want to search for an extension called Thunder client and thunder client is a very lightweight rest API tool for VSS code it’s integrated in there you just have to install it and it allows you to make API calls to your Express server so I’ll go ahead and click install Okay and then I’m going to go just close this and then let’s go ahead on the left hand side you should see the Thunder client appear right over here as an icon that’s the Thunder client and I’ll click on it and now what I can do is I can create a new request by clicking on the new request button and you can see now it looks it it looks kind of identical to post man if you’ve used it before or really any other rest client but we have an address bar where we can uh type in the address or the URL that we want to make requests to so I’ll type in Local Host Port 3000 API users I’ll make a get request so I can select this drop down and select get and I’ll click Send and you can see that it gives us back the data just like that okay and we’re going to use this client to switch between different types of HTTP requests that we want to make so we’ll switch from get to post and then in later videos when I show you how to handle put requests or delete requests we will switch to these HTTP requests as well okay so let’s close this out just wanted to show you all how to set up thunder client so now what I’m going to do is set up our post request to be able to create a brand new user so what I’m going to do is right underneath my uh API user users route I’ll go ahead and reference the app variable and since I want to register a post request I’m going to go ahead and call the Post method so this method is very similar to all the other HTTP verb methods such as get put delete uh it takes in a path so over here I’m going to go and pass in/ API users now you’re probably wondering well should we be able to reuse the path and the answer is yes because you have a different HTTP request type being used so this is for post request and the one over here is for get requests okay when your HTP client is making requests the server knows if it’s making a get or a post request so that way there’s no confliction between these two different types of requests despite the route being the same so we’ll also pass in a request and response or we’ll pass in the request Handler function which will have these two arguments request and response and then for now I will just return a response. send I’ll just pass in a 200 status code or I’ll just pass in 200 and I’ll just console log the request body just so that we can see what our data is looking like when we send it from the client so let’s go back to thunder clients I’ll click on the Thunderbolt icon I’ll click on new request and up top where you see gets just click on that drop down and select post and we’re going to change the url and we’re going to type in Local Host Port 3000 API users okay so once again we have uh we have two different types of HTTP uh methods but they both use the same path okay so whenever I call a post request to SL API users I don’t even need to send any data for now it’s just going to give me back a 200 status code now I can go into the body tab in my thunder client and I can select Json if I want to send Json so if I try to send a request body let’s see what happens let’s click Send so in the console log for our in our terminal you can see that right now it’s actually logging undefined when I try to send it again it still logs and you’re probably wondering well what’s going on with this why is it undefined well the reason why it’s undefined is because right now by default Express is not parsing those request bodies that are coming in so whenever I am sending Json to the express server the headers set the content type to application Json Express doesn’t parse those payloads by default so we need to tell Express to do so now this is going to require us to use a middleware so this is kind of like a brief little intro to middlewares but don’t worry so much about it once we actually get into the topic of middlewares you’ll better understand how they work but all middleware is is just a function that is going to be invoked before uh certain API requests are being handled so in my case I want to make sure that right before my post request is being received I want to make sure that that middleware that parses the Json payload accordingly is being invoked so you typically want to register your middleware as early as possible so the best way to do it is doing it up top after you create your Express app instance so I’m going to go ahead and reference app and I’m going to call the use method and this is the method that you use to register middleware and the middleware that we’re going to register is actually already built into Express so I can just reference Express and call this Json method okay so now you can even read over here it looks at requests where the cont type header matches the type option so in this case this is express. Json there’s also other um uh there’s also other things that you can uh parse to like let’s say if you’re trying to send text or if you’re trying to send uh URL encoded or raw data so hopefully that makes sense so in our case we’ll keep it as Json and let’s go ahead and see what happens if I send the request again so let’s go back into our under client I’ll click Send I’ll just click it again and now watch this you can see that in the console it is logging that request that that request body that I am sending to the express server and I can literally add as many fields as I want I can add a display name let’s do Anon the dev click Send again and you can see that it is being logged right over here okay perfect Perfect all right cool now let’s go ahead and actually do something with the data so like I said right now we don’t have an actual database so all I’m going to do is just push this user to the array so uh to do that what we’ll do is we’ll assume that the request body is valid but then in the next section I’m going to show you how we can actually validate the request body so I’m going to go ahead and create a variable called new user equals so we need to actually grab all of the fields from the request body but we also need to attach an ID to the request body and once again since we don’t have a database to manage our uh IDs because typically the database is responsible for generating those IDs all I’m going to do is just take uh the last element the last user in the mock user array uh take the ID of that last user add one to it and assign that to the new user the new new user’s ID okay so what I’ll do is I’ll first do this mock users so I’m just going to reference mock users um and then I’m going to want to get the last element so mock users. length minus one okay so the length of our array is going to be seven and I want to reference the last element so that’s going to be at index six because remember arrays are indexed at arrays are zero indexed and then we’re going to reference ID and just add one I know this is kind of like a hacky way to do it but I just want I’m just doing it just for a very simple example and then what I’ll do is I’m just going to sign uh or I’m going to destructure the request body so I’m going to destructure body from the request object and then I’ll just simply use the spreader operator on the body object to take all the fields from the body object and unpack it into this new object that I am creating that is assigned to new user and then I’m just then going to uh reference mock users. push new user and then I’m going to go and just return the new user and remember we want to send back a status code of 200 or I’m sorry 2011 because if I were to send this right now you you can see that I do get back the user but it sends back sends me back a 200 and for good practice you want to make sure the post request sends a 2011 so I can just set response. status call the status method and pass into a one and then call do send so we did this in an earlier part of the tutorial where we were making get requests right over here okay so let’s go ahead and test this out click Send all right so you can see whenever I click Send it will just keep creating a new user and it’ll send it back to uh the client which is this uh Thunder client as a response and it has the ID Auto incremented so that’s pretty cool all right so aside from get requests and post requests there are also a bunch of other HTTP request methods that you can use to handle in your Express API however you don’t need to know all of them but there are three others that I think is worth knowing about okay because you will be seeing them everywhere in documentation when you’re working with apis and you yourself will need to use as well so let’s talk about it so the other three are the put request patch request and delete request methods okay put and Patch request both are used to update data but they are technically different on how you update data so to better understand put requests let’s first talk about patch request first so let’s say for example you want to update some data on the backend using our users example let’s say I want to update one of my users uh username so maybe I want to change my username from anen to Anon 123 I would do that using a patch request okay a patch request updates a record but it updates it partially and what that means is you’re not updating the entire user itself you’re only updating a partial field you’re only updating a portion of that entire user record so instead of updating everything of that user record you’re only updating username you’re not updating username and display name okay so hopefully that part makes sense now with put request you’re not actually just updating a partial entity of that record you’re updating the entire resource okay so whenever you make a request to update something on the database using a put request you’re including every single field in that request body even if not updating it because if you don’t include that field then those fields will pretty much be removed or if you’re using like a SQL database those fields will be null so the next time you fetch the data those fields will always be null of course if you’re using mongodb they’ll just be updated in the document and they won’t even appear at all so hopefully that makes sense so so think of it like this put is for updating the entire record okay so even if you only care about updating username but you don’t want to update display name then what you need to do is when you update the username to whatever it is that you want you need to make sure that you include the current value of whatever display name is otherwise it will be overridden with patch you can pretty much just update only a portion of that user record so you don’t need to include anything that you’re not trying to update so if you update only the display name you only include the display name in the request body you don’t need to include the username and if you only want to update the username then you don’t include the display name so hopefully that helps you better understand the difference between put and Patch delete is pretty straightforward it’s used to pretty much just delete records from the database okay so you only really use it if you need to delete a resource SCE whether you’re deleting a user or if you’re deleting a product or an order whatever it is okay so hopefully that explanation makes sense so let’s go ahead and set up a put request for updating a user by its ID so we’re going to reference app and call the put method and for the path I’m going to reuse the path that we used earlier for our get users by ID request so I’ll just copy this up top over here and paste this over here and like I said before we can use the same path but as long as we have different request methods it will still work fine okay and we’ll now pass in the request Handler function as a second argument in the put method call so now we also need to make sure we are uh grabbing the route parameter from the request body or from the request object and we also want to make sure we’re grabbing the request body as well from the request object so let’s do some destructuring so I’ll go ahead and from the request object I will go ahead and the structure body so I’m going to get the request body because we need that because that is what is to contain the data that we’re using to update the current user object and I’m also going to destructure the prams object and then um from the primes object right over here I’m going to destructure ID just like like that now let’s go ahead and parse the ID uh convert it into an integer and check to see if is not a number so that way we ensure that we’re only passing in numeric strings and then we can convert them accordingly so const par ID equals parse ins ID just like that and then we’ll use the uh is not a number function to check if par ID is not a number so if this condition is true if par ID is not a number then we want to return response. send status and we’ll just do 400 which just means invalid um bad request okay uh and now we can continue so what we’ll do next is we want to find the user that we’re trying to update but we want to get the user’s index though we don’t actually need to get the user object just the user index and even with the index itself we can use the index to um retrieve the user by referencing it using the square bracket operator on the array itself so I’ll show you what I mean by that so first let’s grab the index uh of where the user is located so I’ll call this const um find user index and then we’ll reference mock user users and I’ll call find index so now we’ll pass in a predicate function and we want to search for the user by its ID so I’m going to reference user which is this argument in the predicate callback function and then we’ll search for the user byes ID so user. ID is equal to par ID okay not ID but par ID because we just converted it from a numeric string into an actual string so now what we’ll do is we do need to check to make sure that the the index is not negative 1 because if we actually don’t find this user if this predicate returns false then that means the return value of find index is actually negative -1 which means that that user is not found by its ID so we’ll check if find user index is equal to1 and we’ll return a stat status code of 404 so response. send status 404 if find user index is equal to1 so if find user index is not negative 1 that means we actually were able to get the index of the user based on the predicate function right over here so that means we can use find user index to access the user that we’re trying to update okay so hopefully that makes sense now let’s go ahead and do this let’s go ahead and reference mock users and then we’ll use the square bracket operator and pass in fine user index in between the square brackets just like this so this allows me to access the element at the mock users array by the by its index and remember we’re updating this entire user object so I can just simply assign this user object to whatever this object is now keep in mind that since we are using a put request remember we are updating the entire um object itself we’re not updating only one or two Fields we’re updating the entire thing okay and we’re updating the entire thing based on whatever the request body is so let’s say for example if the request body is missing certain properties but those properties are currently existing on that user we’re trying to update then that means those properties will no longer be on the user once we update it but there are some properties though that you never will update at all so for example if you’re using a database and once we do get to it you’ll see that we’re never going to actually modify um the ID at all because the ID is autogenerated by the database server so let’s leave the ID alone so I’ll keep the ID as pars ID just like this but everything else all the other fields will come from the request body object which is this body object right over here so I’m going to just destructure body so that will take all of the field all the fields from the body object unpack it and put it into this new object right over here okay and since we are not going to be passing in the ID in the request body that’s also okay as well okay so what we just did was we kept the ID the same and whatever the user passed in the request body is going to be used to update the user okay so if there were values that we did not include in a request body well they are now gone assuming that the user had those values defined so let’s go ahead and finally return a response um let’s send a status code send status of let’s just do 200 you can send 200 or 204 but I’ll just keep it simple and send 200 and now let’s go ahead and click new request let’s select put and let’s change this to Local Host Port 3000 API users and now we’re going to go ahead and update the user using a put request by the ID So currently we only have seven users let’s update uh let’s update Jack so the ID is two so for the route parameter we’re we’re going to pass to and remember make sure you have put request selected we’re going to go ahead and select select the body Tab and let’s pass a request payload or request body so remember this okay we are trying to update Jack this user object that has the ID of two username Jack and display name Jack if I want to only update uh let’s say the username but I don’t want to update display name with a put request then I must include all of the uh current values as well okay so for example let’s update uh username so let’s update it from Jack to Jackie or Jackson and let’s keep the display name as Jack so we’ll assume that we’re using the same value which we are click Send and you can see we get a 200 okay let’s go ahead and make a get request so let’s do new request get the user by ID of two you can see now we updated the username but we also did override the display name because we passed that in as the request object we passed it in the request object as well but now watch this if I omit display name and then I click Send now watch this when I request the user by ID of two you can see that it only gives me uh it gives me the correct user but we only have username now okay that’s because we omitted the display name and so that just pretty much gets uh removed okay it’s pretty much just taking the request body and using that request body to update the entire user object as a whole of course we’re never updating the ID as well now watch this if I remove username and I click Send and if I try to to get the user of id2 it just gives me this object with only the ID field so hopefully you’re starting to understand what exactly the put request is now of course if this is not what you’re trying to do and you only want to update a partial uh the a a partial part of the user object so you only want to update the username field without having to uh worrying about passing in the display name or other fields because your user field can have your user can have a lot of different fields and it can be a nuisance to pass all of those fields in the request body so this is where patch comes in okay so we’ll work on the patch request next but I just wanted to show you this as well if I were to just pass in a invalid ID it’s going to give me a bad request if I pass in a valid numeric value but that ID did not exist in the array or that user cannot be found in the array it’s going to give me four for not found so that is good okay cool yeah so hopefully that makes sense all right so let’s go ahead and set up a Pat request so patch request basically allows us to update an entity or a resource or a record whatever you want to call it partially okay so in the put request example we are updating the entire resource based on whatever we provide in the request body so everything just gets updated as a whole for the pass request we only want to be able to update either one or two or just a partial amount of fields without having to include every single field in the record that we’re trying to update okay because it can become annoying if you have let’s say a user with 10 different fields and you don’t want to include that all the time so let’s go ahead and set up a patch request so app. patch SL API users so we’re going to reuse the same path of course because we can since we’re using a different request method and then let’s go ahead and pass in the request Handler function in the as a second argument for the patch call and since we’re going to do the same thing um with the check for the ID for the route ID sorry the route parameter ID I’m just going to go ahead and copy um actually most of the stuff up over here but I will explain again for those of you who are watching just the segmented part of the entire expressjs tutorial cuz I have this in a one hour about like a 1 hour to one and a half hour long video and also in its own individual videos as well so in case you uh are not watching the entire tutorial Series so what we’re doing here is is we are destructuring the request body object as well as the route parameter object and then from the route parameter object I’m destructuring the ID all from the request object okay then I’m going to parse the ID so I’m basically taking the ID which I’m expecting it to be a numeric value so I use the parse int function to ensure that when I passing the ID the return value of pars int or of par int with that ID gives me a valid numeric value so we use the is Nan function to check to make sure that parse ID was parsed correctly and is not a number because if you were to pass in a string let’s say you know just random name instead of a number then parse ID would resolve into Nan which is not a number so we would return response. send status then what we’re doing over here on this line which is identical to what we did up here in the put request is we’re just simply searching for the user in the mock users array based on the ID and that’s where this whole line comes in we pretty much just check if user. ID is equal to parse ID okay and additionally if uh find user index if its value is negative one that means find index the method call uh was not able to find that user um by the ID so that predicate failed so it was not able to find the user so it returns negative 1 but if it returns anything but negative 1 then that means it was able to find the user so hopefully that makes sense so we do this check right over here if find user index equals -1 then we return a status code of 404 because that means the user was not found so hopefully that makes sense I didn’t want to have to rewrite that whole thing again but I hope it is straightforward so and if it is a little bit confusing just re-watch the previous video on the put request so that that way you understand but that I only did that for people who are watching these segments AP part okay so now the major difference here is the way that we update the user record in the pull request we updated the entire thing you can see the only thing that we did not update of course was the ID but we took the entire request body and we pretty much just uh put it into took all the field values and put it into this new object and took that object and assigned it to well we override we overrided current existing user okay in the patch request we’re not going to override every single field so the body itself the request body might only contain let’s say one field that we’re trying to update so any current field
values that are in that user record must not be touched at all so they must stay the same so the way we can do that is first let’s reference mock users and pass in the square brackets find user index so that way this is the user that we’re trying to update date and what we’re going to do is this we’re going to go ahead and take we’re going to copy this mock users uh fine user index I’m going to reference it I’m going to use the spreader operator on this mock users reference at fine user index okay so I’m going to take all of the current field value Pairs and put it into this new object so all of the current values will be inside this new object and then I am going to take all of the field value pairs from the request body use the spreader operator on it and put it into this new object so basically what I’m doing is this I’m taking the existing user currently that we’re trying to update taking all of its key value pairs putting it into a new object then I want to take the request body and all of its key value pairs that we are using to update the actual user and unpack it and put it into this new object so that way it will override those current values okay so imagine if you had the current user um let’s see for example right over here the current user is currently ID of have three username atom display name atom I’m taking all of this data right over here putting it in that new object and then the request body would uh have whatever key value pairs that we were send sending over to the server so if we sent username it would override uh it would use the request body’s username field and override it with the current username field so Adam would get overridden with whatever we passed in for the request body okay and if we didn’t pass in a display name that’s okay because display name would not be touched at all and it would stay the same so hopefully that makes sense and let’s go ahead and just return uh let’s do send status of 200 because we can also send either 200 or 204 as a status code for patch as well so let’s actually try to use the patch request so first let’s grab all the users let’s make sure everything is okay so I’ll go ahead and update Jack but this time we’ll use a patch request so I’ll just change it from put to patch uh the ID is going to be number two okay so now watch this when I use the patch request I’m going to update the name the username from Jack to Jackson okay we got a 200 okay status now watch this when I make a get request you’ll see that username is updated and display name stays the same now remember in the put request if I don’t include the display name the display name will be overridden okay with the patch request I can only update what I just want to update I don’t have to include display name and put a value for it I can just update username and then only username gets updated if I only wanted to update display name let’s do display name to Jackson I can just update the display name if I want to update both so let’s update both back to Jack not password uh display name Jack Okay click Send and you can see now both Fields get updated so hopefully this helps you understand the difference between put and Patch requests you use both of them to update data but the way that you update the data is different remember put is used to update the entire resource in our case we would use put to update the entire user object patch is used to update only certain fields on that user object okay so hopefully that makes sense all right so now we will take a look at the delete request method so it’s pretty easy to use delete and it’s pretty straightforward you just use it to delete stuff on the backend server and the backend server typically deletes it from a data source like a SQL server or mongod DB uh any general database so what we’ll do is we’ll reference app and call the delete method and I’m going to reuse the same path because it doesn’t make sense to to not reuse it so now we have/ API users slon ID for the route parameter and we have this path registered with a delete method we’ll pass in the request Handler callback function now with delete requests you actually typically don’t need to pass a request body you can if you need to perhaps you might need to provide extra data in the request body so just wanted to point that out as well but typically if you’re just deleting stuff it’s pretty straightforward so you don’t really need to provide you know like a payload but if there’s other things that you would like to do on the server side and you it requires data in the payload then you can definitely pass a request body so we’ll do the same thing we’ll go ahead and grab the route parameter so I’m going to do the same thing that I did earlier for the patch request and the put request I’ll simply just D structure uh request. prams I’ll destructure the ID from request. prams um actually I’ll do it like this prams ID just like that it looks more cleaner and then what I’ll do is I’ll parse the ID to make sure it is a valid numeric ID so cons parse ID equals parse parse ins ID and then we’ll do the if is Nan check we want to make sure that parse ID is if it is not a number then we want to return a response with a status code of 400 which means invalid which just means bad request which is because of the invalid ID okay so now we want to of course just remove the user from the array itself or if again if you’re using a database once we get to that we would actually remove the user from the database in our case we have to remove the user from the inmemory array so what we can do is this so I’ll go ahead and use the splice method and uh what I need to do is I need to get the index of the user that we’re trying to remove so let’s do that so we want to get the index and then we’ll pass into splice and I’ll just remove the user from from the array so let’s do this const find user index mock users find index and I’m going to go ahead and pass the predicate function which is just going to um find the user by its ID and remember find index will return negative 1 if we’re not able to actually find the user at all in the array so we need to do a check to see if F user index is equal to1 and if it is we’ll do the same that we did in our patch input request we’ll return response. send status and we’ll do 404 because we can’t find the user all right so now that we were able to uh handle this case at this point we know that the user uh we we have the user index of where of where they are located so what I can do is I can call mock users. splice pass in uh starts and I I don’t think we need the leete count because it will just remove the element from the array um so we and I think it’ll just remove only one I think okay uh hopefully that makes sense and now uh what I can do is I’ll just return response. send status 200 and let’s see what happens so let’s go into our Thunder client let’s click new request we’ll make a request we’ll make a delete request so I’m going to select the delete method and let’s do localhost API users um I want to delete user with ID number two so I’m going to use I’m going to pass number two as the route parameter and we’re not going to put any request body we’re not going to send any request body uh let’s see parse is not Define that I messed something up let’s see oh whoops I forgot to change this to I forgot to write the rest out it’s pared ID not parse ID or parse y sorry about that um yeah this is kind of reason this is one of the downsides of JavaScript I do need a linter though I agree with needing a linter to detect these issues but it’s okay we fixed it and let’s go and run our app again so going back to vs code in the Thunder clim I’m going to go ahead and click Send and let’s just see if I can get the user by its ID so it says four for not found let’s make sure the users array is valid um let’s see so it seems like um okay so I know what the problem is so it seems like it’s sliced it spliced everything starting at the index so we actually only need to delete we need to do spec we need to specify the delete count cuz I think it removes everything after that index so let me actually fix that so so we have all of our users let’s try to delete the user so delete okay and let’s try to get all the users again okay so all of our users are here I’m not sure why though it is returning as gray this time that’s kind of weird if you ask me um but if I try to get the user by its ID it’s not found but I but I can grab the other users Okay so so um that works so um that’s pretty cool and you can see that in the browser I don’t have the user by its ID anymore so let’s just delete a couple more let’s delete three if I refresh I don’t have user of ID3 anymore let’s delete user number one okay so now I’m only down to four users left so that is pretty much how you can use the delete method okay so hopefully this makes sense and hopefully you now better understand how to use all five of these HTTP request methods we have went over get requests post requests we went over put requests and Patch requests and then finally we went over delete requests now if you want to see a list of more HTTP request methods you can go over to the Mozilla docs over here you just Google this uh HTTP request methods you can see that there are get requests there’s also a head method as well but um you know you don’t really use these that much but sometimes you will use them there’s also the connect method options Trace I personally have never really used these that much but there might come a case where you do need it but in that case you can just read up about it and you know see what you’re supposed to do with these methods and use it accordingly all right so now I’m going to go ahead and teach you all about how middleware Works in expressjs keep in mind that middleware can be defined differently in different environment but in the general sense it really just means one thing and that means it’s just a mid process between one or two or many different functions or other processes so in the context of expressjs a middleware is just a function that can have logic but the middleware function also is a request Handler as as well so that middleware function has the request response arguments as well and you can actually use the middleware function to return a response if you want to so I’ll show you a simple example of what a middleware function could look like so I’ll create a simple function I’ll call this logging middleware and remember this middleware function will have access to the request and response objects as arguments okay and additionally the middleware function or the request Handler function also has access to this next argument which is a function that you call when you are done with the middleware okay so what I’ll do in this simple example is I’ll console log two things I will consol log the request method and then I’ll conso log the request URL okay and then once I’m done with logging that to the console I’m just going to call next and that’s it in order to now use my middleware there’s two ways I can enable it globally so all of my routes will have this middleware be invoked right before its request Handler is called or I can enable it for each specific endpoint so I’ll show you both examples so let’s call app.use to register our middleware globally so all I do is I just pass in logging middleware as a function or as an argument like this okay now if I were to go into let’s say my browser if I visit the base URL of our application you can see that in the console it now logs the request type so gets what o it logs get and then the URL that we’re trying to visit if I go to SL API users it will go ahead and log that as well if I were to make any request to any endpoint it’s going to log that okay so it is enabled globally if I only want this middleware to occur for only certain endpoints so instead of logging it globally or instead of um registering globally I want to take this middle let’s say I only want to do it for this uh base URL so what I can do is I can pass that middleware function as an argument like this okay so now if I go back to let’s let’s just go to/ API users and you’ll see that nothing is being logged however the moment I go to the base URL and make a request there it logs it to the console so that is good now one more thing to mention is that uh you don’t even need to assign it to a variable and pass it in like this you can just pass it in like this if you really wanted to and then pass in the arguments request response next okay now one thing to mention is that if you don’t have the next function and if you don’t call it it’s not going to go ahead and call the next middleware so in this situation right over here I have two middleware functions uh let’s call this one middleware a okay uh middleware a will be called first and then after middle middleware a is called it has the option notice how I said option to call the next middleware the reason why I say it has the option is because in this middleware you can control the request and send back the response if you need to so this allows you to uh write additional logic that you can reuse for different endpoints that might share that same logic and let’s say for example if the incoming request is missing some kind of authorization token you don’t want to continue to the next middleware or the next request Handler so you want to reject that request by sending back uh maybe like a status code of 401 okay so for example what I’ll do is I’ll just simply log base URL and I’m not going to call the next function now watch what happens if I refresh you’ll see how it is stuck in this pending State and it it does log base URL but the client never receives a response back that’s because we’re not calling the next function so you need to make sure you call the next function in order for it to call the next middleware down the chain okay you can have as many middlewares as you want called in sequential order so I can even add two more like this and then I’ll just call next after each one and if I refresh and if I look at the logs you can see every single middleware was called and let me add one two and three so you can see that it is called in sequential order base URL 1 2 and three all being logged in sequential order hopefully that makes sense another thing that I also want to mention is middleware must be registered before a route if you’re using app.use register it so what I mean by that is if if you want a middleware to be registered for all of your routes you need to make sure that you call app.use right before you call you know app.get app.st app. put Etc okay if you were to register the middleware let’s say after you called those app. poost and app.get methods your middleware is not going to be registered for those routes so order matters in this case so I’ll show you an example let’s say I’m going to go after SL API users I’m going to go ahead and and uh call uh app.use right over here on line 44 and pass the logging middleware so what I’m doing is I’m registering the middleware for all of the endpoints that are registered after I’m calling this app.use so these two endpoints right over here will not have the logging middleware registered so I go into the browser and if I go to the base URL you’ll see that the console does not log anything if I go to SL users or/ API users you’ll see that the console doesn’t lock anything but if I were to go ahead and make a post request or a get request to this endpoint so let’s make a get request to/ API users1 uh you will see that it now logs uh it now logs in the console the request type or the request method and the URL okay so we’re remember order matters and one more thing that I do want to talk about is in the app.use uh method call you can also pass in as many uh middlewares as you want and they will also be called in sequential order as well so just one more quick example I’ll pass another middleware function and I’ll just write a console log and I’ll say uh finished logging and I’ll call next and Let me refresh and you should see that it says uh so it first it logs uh the first thing which comes from the logging middleware and then once that middleware is done it calls the next middleware okay and then the logs finished logging and now once we are done with this next middleware remember we call the next function and then it’ll just go down to the endpoint level so remember the request and response Handler is also a middleware as well so it also takes in the next function and then you can also call next in here as well but if you don’t have any additional middlewares after it then there’s no point to add that argument in the function signature okay so hopefully that makes sense okay so let’s go ahead and take what we just learned and put it into uh work so what I’ll do is since I have a lot of reusable Logic for a lot of my endpoints so notice how in this app dop put uh endpoint I have a lot of the same logic right over here that is written in the app. patch method and the app. delete method okay so what I’m going to do is I’m going to take all of this right over here I’m going to copy it and I’m going to go ahead and create a function up top over here and I’ll call this handle user by ID or maybe I should call it resolve user by ID okay because the goal of this logic is to really get that um index by the user ID so maybe I should call this resolve index by user ID yeah let me call it this instead okay so this will be an arrow function I’m going to paste the logic in here and remember because it is a middleware and the middleware is also a request Handler we have the request response and we need the next argument as well so three arguments Al together and now here’s the thing though what I want to do is I want to use this middleware right before I uh let’s see I want to use this middleware right before I call this uh request Handler because remember this middleware that I’m cre right now the purpose of this is to um grab that user index where it is located in the mock users and we want to be able to um uh have the next middleware that is called use it but in order for the next middleware to actually be able to use that information we need to be able to pass it somehow now there’s no direct way to passing uh data from one middleware to the other but but what you can do is you can attach properties to the request object since we’re using JavaScript we can dynamically attach properties very easily to the object so I can reference request and I’m going to go ahead and reference find user index so this obviously does not exist on the request object but I’m just going to assign it to this just like that okay so now in the next middleware and all of the uh succeeding middlewares that are being called assuming that we don’t ever delete F user index from the request object they will have access to this F user index property which is going to be a numeric value so once we are done we’re just going to call next okay and now one more thing that I also did not mention is that uh next actually does take an argument but it expects an error object or null so if you do pass an error object or an eror an error instance such as like this like new error this will actually throw an error at the express level if you don’t pass in anything then it won’t throw any error at all and it will just assume that everything is successful okay but we are handling errors though with uh these checks and sending back the correct status based on whatever data that we send to the server so we should be fine okay and since we’re not referencing the request body in this middleware at all because we actually referenc the request body at the final request Handler function we’re just going to remove that the structure of the request body right there so let’s actually use this for one of our endpoints first just so you all can see how this works so what I’ll do is I’ll use it for my put request to update the user by ID so we just pretty much take that middleware and we pass it as an argument right before our final request Handler which is this request and response or which is this request and response Handler over here here now since all the logic that we have inside resolve index by user resolve index by user ID um we all this logic that we see over here was moved into that middleware function so I can just delete all of this okay so I’m going to just remove all this I still will need the request body though so I will remove at least the destructuring of the request prams but I’ll leave the the structuring of the request body right over here and remember we never modified the request body at all now we do need a reference to find user index in this request Handler scope so I will need to destructure that and I can now that in the resolve index by user ID middleware function I got the index and I attached it to the request object okay so at this point if we hit this part right over here we can assume that fine user index is in fact defined because if it was not defined um then we actually wouldn’t even be uh in this in this uh final middleware at all okay so now I can access find user index from the request object but now I also need to fix this par ID because that was something from that we had before but we no longer have that but that’s fine because I can still reference mock users use f user index to uh reference the exact element at the position in the mock us array and then just simply reference. ID like this okay let’s go ahead and just test this out before we modify the other end points and see how this works all right so back into our Thunder client let’s make a put request so put and then logo host uh Slash API users so I guess we’ll update user uh with ID3 which will be adom so let’s send the request body so let’s do username let’s change this to Jackie so if I click send everything works fine if I were to get that user again the username was updated and since we didn’t provide a display name that was um pretty much just overrided okay so that is working just fine so let’s just update the other um the other uh end points as well but before let’s just recap of what’s going on so whenever I make a put request to/ API users and then the route parameter we provide which was number three it’s going to go ahead and first call the first middleware well first it will call all of its uh Global middlewares if there are any that are registered before that route in our case we only have express. Json which we need to parse that Json um into that Json into natural Json object so that is invoked first obviously then we don’t have any other Global middlewares invoked so we invoke the resolve index by user ID middleware and then it will go through this logic basically the same thing that we’ve been doing already just moved into a separate function uh the only difference is that we attach this fine user index property or we add this property to the request object and assign it a value which is the index of where the user is in the mock users array and we call next so once next is called it will now call this final request Handler which is also middleware and then from here we just simply uh update the mock users or update the user in the mock us array and then we return a status code of 200 that’s it let’s go ahead and update uh our patch request let me just copy this middleware function name pass that in there uh same thing just remove that prams destructure I don’t need all of this anymore uh and then let’s see let’s the structure find user index and I think that’s it for patch let’s just test that out make sure that patch works so I’m going to go ahead and update user number three so since we restarted the server um the username should be back to Adam and so the display didn’t be there as well I’ll just update the username using the patch request there we go and if I click send you can see the username was updated okay so the patch request is working good and of course if I were to provide an invalid value the middleware will pick that up for us you can see it says bad request invalid ID and that is handled right over let’s see should be handled somewhere over here um oh you know what we haven’t did it for we haven’t done it for the get request it we’ll do that later okay but at least uh let me do this if I make a put request to this you can see that this part gets handled by the middleware for the put request and same thing for the patch request as well we get a bad request if I were to pass in a valid numeric ID but it doesn’t there’s no user with that ID then it’ll just give us a four for and that is all being handled by the middleware that we just created okay cool let’s go ahead and do the same thing for delete uh so let’s pass in resolve index by user ID let me remove all of this stuff right over here yep and for this part we just need to uh grab the fine index user just like that so that way we know where to splice or I’m sorry it’s fine user index okay now let’s go ahead and try to delete a user so I’ll will uh delete user with ID3 if I tried to get that User it’s not there anymore okay see how user of ID3 is not here anymore okay let’s just go ahead and fix up the last one which is the get request um so let’s see uh we need to um so the way that we are actually returning the user in the get request is done different because we’re using the find method and not find index to actually get the user object itself and we’re just returning that as a response but what I could do is I could still use the same middleware resolve index by user ID and I can grab the uh find user index value from the request object and then I can just use that to reference the mock users array to return the correct user so let’s just do that just so that everything is consistent with each other so let me remove all of this and I’ll go ahead and the structure find user index um and I’ll just do this Con find User it’s always good to just double check just to make sure even though we know that find user index does 100% resolve to a user in that array but it’s always good to check just to be safe so mock users find user index and if there’s no user we’ll just return to 404 and if there is we’ll just return find user okay so we’re still using we’re still utilizing our middleware for all of our um endpoints that we’re using the user ID to search or perform operations on so now if I try to uh get the user by ID uh it says mock users oh let me fix that I think it’s mock I uh misspelled that it’s case sensitive let’s try again okay there we go so that is pretty much it with middleware I know it’s a lot but middleware is very powerful and understanding how it works is very worth it when you’re using expressjs because everything in expressjs that you’re going to be using has to do with middleware in some way shape or form so it’s good to learn how middleware Works learn the ins and outs of it and understand how you can use it to your advantage okay so hopefully all of this made sense all right everyone in this part of the tutorial I’m going to teach you all how to use express validator to validate incoming data for our Express API the reason why this is important is because sometimes the data that you expect is not the data that you receive let’s say you want to create a user and save it to a database so you obviously need a post request to to a user’s endpoint to create that user so that post request will expect a request body and we want to make sure that the username is not over 32 characters of length now we are expecting that but that doesn’t mean that the client will send a username that matches our constraints so you want to make sure that you check to see if the username is 32 characters or less now some of you might be wondering well if I’m validating on the client side let’s say if I have a react or angular project and that project has a form and when I click on the form button it will send a post request to my server well if I’m validating that form before I click that button before I submit that API request why do I still need to validate on the server side the reason why is because the API your express application does not know where that data is coming from you can literally go into the web app open up the network Tab and inspect where that post request is being sent to which endpoint it’s being sent to take that URL and throw it in something like Postman or even the Thunder client that we’ve been using to make API calls and send whatever you want and bypass the client side validation so you don’t know where the data is coming from so you always need to make sure you are validating it on the server side in my opinion I think the server side validation is the most important more important than the client side because the server side is where you’re actually going to process that data save it to a database submit it to another external API or do whatever you want with it okay so you must always validate on the server side no matter what so let’s go ahead and install Express validator so I’m going to type npmi Express hyphen validator just like this and then I’ll run my Express server let’s go into our code and we’re going to go ahead and import a function from the Express validator package just like this whoops so import and then pair of curly braces so I’ll I’ll import the query function and this is used for validating query parameters okay so there are a bunch of different middleware functions that you can import from Express validator and in case if I didn’t mention earlier yes these functions that you are importing you are using them as middleware so what that means is that we’re going to be calling them uh by passing it as an argument to our request methods such as app.get for example and then we want to make make sure we’re calling them right before our final request Handler which is also a middleware as well in case if you didn’t see the middleware section of this tutorial definitely check that part out either in the previous video if you’re watching just this Express validation tutorial or if you’re watching the entire thing just go a few minutes back to where we talked about middleware okay but what I want to do is I want to pass this query function call as if it was a middle wear so we’re going to pass as an argument right before I passed this request Handler function so it’s pretty easy we’re just going to go ahead and call query and then comma so we now have three Arguments for this app.get endpoint right over here and now what I want to do is I want to specify the query parameter that I want to validate so I’ll just do a simple one we’ll do filter okay and when you call the these functions okay in this case we’re calling query it creates a validation chain so basically it just basically means that when you call this function it returns an instance of validation chain and from here on you have access to a bunch of methods that you can use to determine what you want to validate so if you want to validate that filter is a string you can call this is string method and this returns an instance of validation chain so you can call literally the same method as many times as you want obviously you don’t want to do that but the whole point is that you can use this validation chain to perform more validations in order or it doesn’t really matter in this point but the point is is that you can use this validation chain to keep on calling more methods to validate on that single filter field so let’s say you want to validate that filter is a string and then you also want to make sure uh let’s see that is not empty okay so this will ensure that it is a string and it is also not empty now I will mention that with query parameters in expressjs they are always parsed as strings so even if you pass in a numeric value in the address bar as the query parameter for our filter or really any query parameter it’s it’s going to be parsed as a string and you’ll see in just a second so what I’ll do right now is um this so I’ll make a request so let me go into my thunder client right over here and let’s make a get request to the users endpoint and for now we’re not going to pass in the query parameter for filter I’ll click Send and you’ll see right over here that nothing happens although we are expecting an error to occur why is that the case well here’s the thing these functions don’t actually throw an error they don’t reject the request you actually have to handle that yourself so how do we handle that well remember middlewares are called in sequential order so this query function that I’m calling this is going to be the first middleware that we’re calling and then it’s going to call the next middleware so it’ll call this request Handler which remember it is also a middleware as well so inside our request Handler in the function body we need to take care of the error handling part because the query function won’t throw any errors for you it will validate the fields but it just won’t throw any errors so you as developer needs to handle that yourself so just very quickly I want to consol log this request object because I want to show you what happens under the hood I know some of you might not be concerned about it but I want you to also get full context with what is going on instead of just telling you to call all these functions so what I’ll do is I’ll make a get request to this endpoint and uh I’m logging that request object but I want to show you that you can see right over here in the request object we have this new property that is attached to that request object and express validator attach that themselves okay and it’s attached when we call this query function middleware and then now we can actually see that it’s right over here okay and I’ll go even further further let me just copy this part over here and access that direct field and show you even further what that looks like so you can see we have this context array uh or this array of context it’s an object and it has a bunch of metadata about uh the validation you can see we have Fields locations um errors okay a bunch of different stuff obviously you don’t have to worry about this but underneath the hood what happens is when we call this query middleware function it’s going to go ahead and validate um the field for you and then it’ll attach the data to this request object okay and from here what you want to do is you want to call this validation result function so let me import that from Express validator so validation result that’s a function and you want to call that function and let’s assign the return value to a variable called result so we’re going to call this validation result function and we want to pass in the request object okay just like that and what this will do is it’ll grab that field and it will extract pretty much the validation errors and you can handle that yourself so instead of having to manually do that yourself you can use this validation result to do it for you that’s why they provide this function so let’s go ahead and send a request again and now you can see that when I log that result object I now have everything in a proper format you can see that we have this errors property which is an array of errors and you can see that we have two errors one we have an invalid value which I guess makes sense because we are trying to validate if it is a string and then we’re also trying to validate if it is not empty so we have two different things we’re trying to validate so we have two errors total so invalid value and an invalid value as well but if I go ahead and pass in that filter query parameter and then let’s just give it a random value let’s just do Anson and now you can see that that errors array is no longer populated with errors because we don’t have any errors anymore because we just pass in that filter value right over here of course if I don’t pass in a value we still will get an error it says invalid value because we have this not empty call right over here and you can also take a look at the documentation or in your vs code if you just uh use the dot operator after this not empty call you can look at all the other methods that you can use to validate your Fe Fields so let’s do a validation on the length of the value for filter so let’s use is length and then this will take in options so let’s do uh Min character length we will go ahead and do three characters and then for Max will do 10 characters so now I’m going to go back to my code or my uh vender client so if I pass in let’s just leave it empty like this let’s see we should get two errors okay um if I remove the entire query parameter we should get three because now we’re calling three functions we’re chaining three functions let’s go ahead and pass in the filter and let’s do do a n so n if I click Send you’ll see that we get this error and now if you actually look at these errors you’re probably starting to feel confused on what is what you know so we can actually use this method after we call is length called with message you can actually pass in a custom error message and you can see over here it says it sets the error message for the previous validator so this with message call is going to uh the the message itself that you pass in here will relate for this validator okay so we’ll do um must be between must be at least 3 to 10 characters uh and let’s add a custom with message call for not empty so must not be empty uh okay let’s try it out so if I click Send and look at the console you can see now we have that custom ER error message okay hopefully that makes sense and if I leave this empty you can see that we have both of our errors must not be empty and must be at least 3 to 10 characters so that is good okay so now if I were to pass in just let’s say five characters now we shouldn’t get that error anymore and we don’t but if I exceed uh 10 characters it now it gives me this error must be at least 3 to 10 characters so hopefully this makes sense so this is how you can validate query parameters now let me go ahead and show you how we can validate request bodies because that’s also very important as well so similar to query parameter uh we have this query function for quate parameters but we also have a function to validate request bodies and that is the body function and you import that from Express validator just like this and it is used the same exact way so if you understand how to validate the query parameter you then can validate very easily the request body so here’s what we’ll do we’ll go down to uh our post request for the API users endpoint and right before our final request Handler we’ll go ahead and call the body function and pass that as an argument into appost so it’s going to go ahead and call this body middleware function first and then perform the validation and then it’s going to go ahead and call that next middleware that final request Handler function right over here and then similar to what we did with the query parameter in that request Handler function we want to actually uh use that validation result function to see if there were any errors at all okay so here’s what we’ll do so now we’ll go ahead and specify what field that we want to validate on the request body so for the request body I want to validate the username and then I also want to verify that is not empty by calling the not empty function and I’ll use with message username cannot be empty and then I want to make sure that the max is let’s do 32 characters so is length we’ll do a Min of five characters and Max of uh 32 and then with message username must be at least five to five characters with a Max of 32 characters and then um let’s see oh let’s also make sure it’s a string username must be a string all right and let’s go ahead and try to make a request a post request to this endpoint uh whoops let me see oh let me go ahead and do this before we do the post request I forgot that we need to go ahead and call that validation result function so let’s do that validation result result okay so cons result equals validation result and then let’s conso log result and see what happens so I’ll send this request uh oh whoops I’m sorry I was supposed to pass in request not result for the validation result sorry about that okay there we go that works okay so let’s see what the problem is okay so now we can see that username cannot be empty uh username must be at least five characters with a Max of 32 two characters so we do have our errors so that’s good okay now here’s the thing though I want to validate not just one field but I want to validate multiple Fields as well I don’t want to just validate the username field okay so what we can do is we can actually pass an array of body function calls so instead of having to pass it in like this and then uh you know pass in another middleware function let’s say if I wanted to just very quickly validate display name and do not empty like this okay let me make a request and you can see now let me zoom out a little bit you can see now I have four errors all like this instead of just passing it uh individually like different arguments we can actually just pass it as array like this so we pass in one array and then it’ll call all of these not that it will matter all that much because in the end it will still validate everything for you so let’s go back to thunder client and we’ll send some requests now with some valid data so let’s go to Local Host Port 2000 API users username Anon display name Anon the dev and if I look at my console you can see that we have no errors the moment that I omit any one of these values I’m going to get an error in that errors array right over there so if I omit username you can see that uh yep we get the errors for username okay that’s good so let’s go ahead and customize our logic now because we obviously don’t want to do anything at all when there are errors in our case we don’t so we want to make sure that we can actually check to see if there are errors or not on this result object and to do that there’s actually this is empty function and this returns true or false and it returns true if there are no errors and if there are errors it will return false so what I can do is I can useing if statement and I’ll just do if there are no errors so if result is not empty then I’m going to go ahead and return response I’m going to set the status to 400 the status code to 400 and I want to send back the errors so I’ll just send an object or yeah an object with the errors property and to actually get the errors you can reference result and then you can just call this array method and this will just give you all the validation errors as an array as it says over here gets the validation errors as an array you can map it if you want if you want to alter what is sent back uh based on that errors array you can do that if you want let’s go ahead and try this out okay so let’s omit the display name and you can see now I get that 400 status code which means bad request and that’s typical whenever you send an invalid payload so in this case we’re sending a payload with no display name and you can see I get the error uh invalid value path display name location body now of course ideally you would want to clean this up because you want to have something that is more um understanding to the client so that they understand it very easily but I’ll let you all take care of that and if I omit the username you can see now all of the errors let me zoom on a little bit whoops you can see now all of the errors appear right over here okay so hopefully that makes sense so we’re not quite done yet because we still need to actually save the valid data to our uh quote unquote database or our array in this case of users right now we’re still using this body object that comes from the request object and this data can be either valid or invalid we don’t know okay but since we are using Express validator we want to make sure that we are using the validated data of course there are different ways that you can handle this since at this point we are throwing an error or returning a status code of 400 we can safely assume that the data is valid by just referencing body Dot and then whatever field name we want but instead what we can do is we can actually use this function called matched data so let me import that up there so match data is imported from Express validator and then I’m going to go back down here and what I can do is I can simply just call let’s do this const data equals matched data okay and just pass in the request object like this and then what this will do is it’ll grab you all of that data that has been validated needed so I’ll console log this so you all can see so let’s get the username and let’s pass in a display name so now I can see that I have username and display name right over here okay and this object that is being logged is the Matched data return value which is pretty much the validated data so I would recommend you to to use this data object instead of the request body so let’s just fix that real quick so let’s remove uh this these two lines and then let’s see we’re going to replace this reference of body with data and I think that’s all we need to do all right and that is pretty much it that is how you can validate request bodies for your post requests and you can do the same thing for put request for patch request and really any request method that takes a request body and since you know how to validate uh validate request bodies and also validate query parameters you should now know how to validate other things too such as headers cookies route parameters it’s all the same thing now very quickly I wanted to show you all how you can use a schema in Express validator to make make your code look a lot more cleaner because right now if I look at this part right over here um I have a bunch of validation going on and this is just for only two fields and you can imagine if you have a lot of different fields that is being sent to uh the the server this can start to look more and more cluttered so we can use a schema to make things look a lot more cleaner and a schema really just is an object that has all of your validators defined so instead of having to have all of this being chained after calling each function all you do is you use this check schema function and you pass in the schema which is just an object and then what that function will do is it’ll create a list of validation chains so that way it can just save you a couple lines of code and make it look a lot more readable so what I’ll do is I’ll create a new folder called utils and I’ll create a new folder inside this folder or not not inside uh I’ll create not a folder I’ll create a new file called validation schemas because I want to keep everything separate and then what I’ll do is I’ll create a variable called create user validation schema I always like to be verose with my variable names but it’s up to you and then now what I want to do is I want to define the field that I want to validate so in this case I want to validate the username field so I’m going to use that as a field inside this object create user validation schema and then for username this will be an object and inside this object is where you will specify what you want to validate so if I wanted to validate the length so what you would do is you would just take the name of this method they’re going to it’s going to be the same exact thing so whatever the name of the method is is going to be the name of the field field that you’re going to configure inside this object so for example is length I’m going to go ahead and type is length just like this and so this is going to be an object and you want to pass in these options so options and then it’s going to be the same exact thing you can pass in Min and Max for options so Min of five so this will be a minimum of five characters Max of 32 characters so this is how you can validate the username and its length let’s do the same thing for uh the not empty validator so again you take the same method name not empty you can even just copy and paste it uh whoops not there right over here now since not empty does not have any options we can just set this to true but of course if we did provide options we could just map this to an object and do the same thing like this options like that same thing for the is string validator we don’t have any options configured for that so I can just take the same exact method name and then set it set its value to true however if you did have an error message like a custom error message like we have over here we can also specify that as well so for is length inside the is length object right over here I can go ahead and specify this error message field like this and I’ll just go ahead and copy this whole string and paste this right over here like that now since uh not empty does have a custom error message instead of setting this true what I’ll do is I will provide an object like this error message and then that okay and then what we’ll also do same thing for is string let’s copy that and do this and of course since you have this object over here it pretty much implies that you are going to obviously check for these two validators so you don’t need to worry about the Boolean value anymore and uh let’s see what else um okay yeah that’s pretty much all we need for this so now to actually use the schema what we’ll do is let’s remove all of this let me just make sure we have everything uh username oh whoops that was only for username uh let’s do display name I forgot about that display name and I think the only validation we had was not empty so let’s do not empty and then let’s just we’ll just do true for now okay let me go ahead and remove this whole array and then now we’re just going to call this check schem of function so let me go up top over here and import check schema just like this and let me go back to the post request so right over here we’re going to go ahead and call check schema and then now you’re going to pass in that schema definition which is just this object that we created so let’s import that so up top over here we’ll import from utils validation schemas create user validation schema just like that and I’ll pass that object in here and let’s actually see what happens so if I go into Thunder client let’s make a new request to Local Host Port 3000 okay so I am getting an error in the console and I think it’s complaining about the import uh I think it’s because I’m missing the extension at the end tojs but I realized that I uh am supposed to use MJS so let me just quickly fix this and add that MJS extension at the end because if I don’t have that extension it’s going to throw this error but if I add that extension at the end the error will be fixed okay so I just wanted to mention that very quickly but now if I were to go back into the Thunder client and let’s try to make a post request now you can see that now I get the errors right over here it’s complaining about the display name the username and all of the different errors are that’s going on with it if I pass in let’s say username and let’s let’s do let’s say if I pass in just two characters for username you can see that it’s going to complain about username must be at least five characters with a Max of 32 characters and the other two validator errors are not there because we actually provided a value and it is not undefined so yeah it’s a string and it’s not empty okay and then you can see that since we don’t have display name that is not uh since we didn’t provide that in the request body the error appears right over here okay so hopefully that makes sense and hopefully you can start to understand how using schemas to validate your request bodies is a lot more easier than just having all of your validators in the same uh in the same uh file and just chaining them after each call okay so I would encourage you to do the same thing for this query validation that we did earlier for this get request I’ll let you all take care of that yourself just for exual practice so hopefully this all made sense so now what I want to do is I want to show you all how we can organize all of our requests using an Express router the problem right now is even though we only have a few routes to find as our application grows we could have 50 routes 100 routes a whole bunch and you obviously don’t want all of it to be in one single file you want to group together your API endpoints based on what is known as a domain so what I mean by that is for example we have a bunch of user endpoints and all of this handles different operations so that is known as the user domain the user domain is everything related to the user itself so when you create a user when you grab all the users from the database when you update a user that is all part of the user domain if you see right over here I have another products endpoint that doesn’t really have any other endpoints to do much with such as creating a product and this would be the products domain so anything related to operating with the product domain would be things such as creating a new product updating a product deleting a product things like that okay that’s what I mean by domain and what I want to do is I want to be able to group together all of my users endpoints separate from the products endpoint because it doesn’t make sense to keep everything all together okay the products endpoint should be grouped with everything related to products users endpoint should be grouped together with everything related to users if you have endpoints that handle Payment Processing maybe you’re talking to let’s say uh the stripe API or some other Payment Processing API then you would have a payments domain and you want to group all of your payments and points together so we can use use an Express router to do this and what I’ll do is I’ll create a new folder inside the source folder and I’ll call this routes and then I’m going to go ahead and create a new file and call it users. MJS and then inside users. MJS we’re going to import the router from Express okay and this is a function that we can call to create an instance of an Express router it’s it’s the same way of how we imported Express like this and then we called the express function the router import is also a function so I’m going to declare a variable and we’ll assign the return value of the router function call to this router variable which is in which has a lowercase R okay so these two are different obviously so now we have our router and the nice thing about this router is it has pretty pretty much almost all the same exact methods and properties that the express app instance has so you can see that I can reference the get method the post method delete all that kind of stuff okay the router itself is pretty much like a mini application in your entire Express app that can group together all of your requests so you can register requests on the router but then you also need to register that router to express okay so hopefully that makes sense so the same way that I am registering let’s say this get request right over here for/ API users I can do it do it on the router so let me go ahead and copy uh let’s say this right over here it takes the same exact method arguments you can see it takes a path so let me paste the path right over there so/ API users and then it takes uh as many handlers as you want to pass or middleware functions so we can literally pass this exact same these exact same arguments right over here like this okay let’s just import that query function from Express validator and this is something that we did in the previous section where we talked about validation in Express okay so next thing we need to do is export this router and then we need to import it into our our main index. MJS file where we have the express app instance because we need to register our router with the main Express app in order for the main Express app to actually have these routes mapped out so users can actually visit it or clients can actually visit it so I’ll export uh I’ll actually export this as a default so export default router just like that and then next thing thing that we’ll do is we’ll go into our index. MJS file and we want to import that router that user router so import user users router from uh and then the folder is routes and then users. MJS let’s make sure we don’t have any errors in the console okay everything’s good with the import so we can register this router now so that way um we can actually access the endpoint defined at the router level over here by simply just using app.use just like this and then you pass the user router like that and since we have the same endpoint defined at the router level we want to make sure we remove this endpoint definition over here so let’s just remove that okay so now let’s go ahead and try to access that endpoint using the Thunder client so we’re going to try and make a get request to/ API users so let’s do that and it says validation result is not defined oh whoops I need to also import validation result as well and let’s try to make a request mock users uh is not defined oh that’s right because um yeah we’re using mocku okay let me quick do this I need to move this mock users array into a separate file so I can export it from that file and import it everywhere else I need it so I’ll just create a new file I’ll call this constants whoops MJS and I’ll export this mock users constant and I’m going to remove this right over here and let me just quickly uh do this this let me import it inside the index. MJS file because we are using it here so up top I’ll import and this is a named export so mock users from utils constant. MJS and we’ll do the same thing inside the users. MJS file so import mock users from and then the pathway over here okay so no more errors so that’s good let’s just try to call this endpoint okay so you can see that it works and that’s good so we know that it is working and if I were to remove this app. use call and passing in the user’s router and save now if I try to make a get request it’s going to say four for not found because we did not register that router so hopefully this makes sense so now what I can do is I can take all of my end points that are relevant into users and place it inside this users. MJS file and then register those endpoints at the router level so let’s do that so let’s go ahead and do the same thing for app. poost API users so I’m going to go down here and I’m going to reference router. poost and I’m going to pass in those same exact arguments that I had passed in to app dopost so you can see right over here we pass in for the first argument the path and then all of our middleware functions let’s just make sure we have all of our Imports so we need to import uh check schema from Express validator we need to import the create user validation schema as well so let me import that create user validation schema okay and then uh let’s also we already have validation result imported we are using the match data function that comes from Express validator so let’s import that and this should work so now let me just go back to the index. MJS file remove this app. poost because it’s redundant and uh let’s go ahead and try to make a post request and you can see that it’s working just fine let me pass in a request body and then let’s see the result and you can see that we get a response back and of course if I were to just remove this it would say four for not found Okay and like I said you could do the same thing for all of our end points for the users domain so uh what I’ll do is I’ll move uh the get user by ID in there so let me just copy all of this and let me just delete this so let’s go up here I’ll put this right underneath here okay and then we do need to resolve index by user ID middleware function and since that is defined inside the index. MJS file we need to uh we need to of course export it or whoops not this one this one right over here let me do this let me create a new file inside utils I’ll call this middle mware middlewares MJS and let me export this and let me make sure I am importing mock users from constants MJS okay this is good so now we can import well first let me remove this and uh I’ll import that middleware first from utils middle wees resolve index user by ID because this index file is still using it and then what I’ll do is I’m going to go ahead and import this inside the users. MJS file so that gets imported right up top over here as you can see resolve index by user ID for this middleware um and I think we are good for uh this end point right over here and I did I did remove it so that’s good so now let me go ahead and just make sure my other endpoints work okay uh let’s do three okay so our end points are working so that’s good uh What else let’s go ahead and move these three end points into users. MJS as well so I’m just going to paste them all over here and just change app to router just like that and we’re using the same resolve index by user ID which like I said we imported up top over here from that new middlewares MJS file that I just created okay and uh there’s nothing else that we need to import because it’s using mock users which we already imported already um and the request and response object comes from this callback function so we’re good to go with the rest of our endpoints so look at our main file now look at all the this now we have cleaned up our index. MJS file and anything relevant to users I can just go into the routes users. MJS file and look for the the corresponding endpoint that I need to look for okay let’s just make sure let’s just make sure our other endpoints work okay that’s good okay and if I take a look at this I have successfully updated the data and Patch should work just fine as well okay patch is working just fine I was able to update my data using put and patch and let’s try delete so I just deleted the user of ID3 so if I try to get that User it’s going to say four for not found and if I call users it’s not going to show that user in the array okay so that’s good so hopefully this all makes sense so now I can easily just clean up my index. MJS code so let me remove all all of the Imports that we’re not using anymore so all of this stuff we’re not using anymore all of this stuff over here um I’m going to delete logging middleware because we’re not using that anymore let me remove these coms down here okay let’s go ahead and create another router for products so I’m going to create a new file and I’ll call this products. MJS and it’s going to follow the same a structure that we did for our users router we’re going to import the router from Express we’re going to go ahead and create the router instance by calling the router function and assigning that return value to the router variable and then we want to also make sure we export the router as a default export and since products only had we only had one endpoint for products I’m just going to go ahead and copy all of this let me remove that and we’ll call router. getet paste this there and since we’re not using any other Imports or we’re not referencing anything else aside from just this response argument in the function we don’t need to worry about importing anything okay and the last thing that we need to do is import the products router like this so import products router from uh and then the path to that products MJS file and then we need to call app.use and pass in products router like this so now if I try to make a request to products I can get the list of products and of course if I were to remove this app.use uh with the products router being passed as an argument we’re not registering that products end point or that products router so we can’t access that products endpoint so hopefully this makes sense now one more thing that I will do and I’m only going to do this because I want to structure this entire project in a way for future videos for future tutorial videos what I’m going to do is I’m going to actually create a new file called index. MJS and what I’m going to do is I’m going to import the router as well and I’m going to create an instance of this and you don’t have to do this if you don’t want to but personally for me I prefer organizing everything like this because it makes it so much easier I’m going to also export this router as a default export and what I’ll do is instead of having all of my routers being imported in the index. MJS file because you might have a lot what I’ll do is inside this index. MJS file in the r folder I will import all of my routers in here so you can kind of think of this like a barrel file if you’ve ever heard of that before so let me import users router from users. MJS and then we’ll do the same thing for products router import that from products MJS and then what you can do here is you can use router and then call do use and in case if I I mention earlier you can also register middlewares the same way that you would register middlewares on the express app on the router itself and that would of course register middleware at the router layer so not for all of your routes but for all of the routes for your router specifically okay so you can register middleware only for your users routes and it won’t have anything to do with the products rout at all okay but I’m going to go ahead and pass in the users router like this and I’ll do the same thing but for products router like that and then I export the router as a default export from this index. MJS file and then I can now go into my index. MJS file in the root Source folder right over here remove these two Imports import um let’s do this import routes from and we’re going to import this from index. MJS so we’re importing this root router that we’re using to register all the other routers okay and then I can go ahead and pass routes into app.use so I only need to do this one time because I already have all of my routers registered with this root router right over here and I’m registering that root router with the main Express app so it’s still going to work the same exact way it doesn’t matter whichever one you prefer to do but I just prefer doing it this way because I think it makes it a lot more cleaner for the index file itself okay and one one more thing that I will do though is you can also set um a prefix for all of your routes because notice how right now I am I need to prefix everything with/ API okay SL API products SL API users Etc so hopefully all of this makes sense and you can now see how or how much more organized your entire application looks so you can you can go ahead and add add more endpoints for products you can add more endpoints for users and you will know where every single thing is without having to scroll through one file try to look for it all right everyone so the next topic that we’re going to talk about are HTTP cookies so cookies are pretty much a simple concept but a lot of people tend to get confused about it they get confused on what it is how to use it how it’s used in realc ations but most importantly they kind of don’t quite understand what’s the purpose of it so I’ll do my best to explain it to you all in a simple way so cookies or HTTP cookies they’re literally just small pieces of data that your web server sends to the browser in our case since we’re using Thunder client you can pretend that this is our web browser so whenever I make a request to this URL it will send me back a cookie but currently our server is not sending any cookies but you can see over here I can whenever I uh make make a request I can go ahead and click on this response section over here and then select cookies and see if there were any cookies sent back from the server so the server sends a cookie to the user’s web browser or the client or whatever and then the web browser or in this case our Thunder client can store the cookie if you actually go into your browser right now and if you were to open up the dev tools so let me actually do this let me go to Local Host Port 3000 and let me Zoom a little bit and let me open up my Dev tool so right over here and if you actually were to go to uh this Chevron this this double Chevron arrow and click on application you can see this section where it says cookies now currently I don’t have any cookie stored on this domain but we can change that we can make our web server send the cookie back to the web browser the web browser can store that cookie and then what happens next is the web browser can actually send that cookie back to the server on any request you need to make now you’re probably wondering well why is this important well it’s important because by default h HTTP is stateless and what that means is that whenever you make a request the server doesn’t know who that request is coming from it doesn’t know who the user is and knows nothing so if you wanted to build let’s say an e-commerce website and you wanted to implement some kind of cart system where you can add items to a cart and delete them from a cart and you want it to make it functional where when the user adds items to the cart and they close a website and go back on the website that those items are still in the cart after they leave and come back you need to use something like cookies because the server doesn’t know who the user is it doesn’t know what items they added but when you use cookies you can send the cookie back to the server and the server will then know who that user is and so the next time the user comes back the user can have all of their items on the cart displayed so they don’t have to re everything all over again now most of the time in realistic large applications where you have authentication you use cookies alongside with sessions but we’re not going to
get into sessions just yet we’re primarily only going to focus on cookies right now okay but hopefully that explanation makes sense just remember that HTTP is stateless and using cookies enables the server to send a cookie to the web browser and that cookie typically is going to be some unique value so that way the server when they receive it they can distinguish whose cookie this belongs to and then they can send Dynamic data based on the cookie value so I’ll show you an example so let’s go into our code and what I’ll do is inside the base URL I’m going to go ahead and set the cookie whenever the user visits this endpoint to do that we have to modify the response object by calling this cookie method on the response object and this takes in uh a total of three arguments options is optional but you can pass in a name for the cookie so I’m going to call this hello and and then I’m going to set the value of this cookie to be world and then you can pass in options so let’s say if you want to have the cookie expire after a minute then you have to specify that in milliseconds so 60,000 M milliseconds is 1 minute and let’s go ahead and test this out so I’m going to go into the browser and if I refresh you can see that I now have this cookie and I can see that every time I refresh you can see the number just jumps up to 49 50 well now 51 53 54 so it’s going to expire after 1 minute okay I can have it expire after an hour so let’s do 1 minute time 60 so that’s 1 hour right there so notice have I refresh you’re going to see that let me kind of zoom in a little bit right over here so you’ll notice if I refresh it goes from uh I guess the 14th hour to the 15th hour this is in uh 24hour time clock and uh I think it’s in UTC time currently it’s 7:24 so I think plus 7 hours gets you um I think 15 is what 3:00 I think so plus 7 hours yeah yep that’s right plus 7 hours yep okay and if I were to multiply this by two so expires in 2 hours if I refresh you’ll see now it expires at the 16th hour which is 4:00 p.m. 400 p.m. so hopefully this makes sense okay and let me just also go into my thunder client and if I click Send uh let’s see uh oh I’m visiting I’m visiting the wrong endpoint let me visit the slash endpoint and see how now I can see that I have a cookie right over here and you can see that it shows you the domain the cookie name the value all the stuff okay so hopefully this shows you how the browser and how your clients can store cookies but now let’s actually see how it’s being used like how do we actually make sure that we are sending the cookie back to the server because right now we’re only receiving the cookie that is stored in the browser but we’re not really doing anything to actually reuse that cookie so the next thing that we’re going to do is this what I’m going to do is I will go into um any endpoint so let’s just use the products endpoint because we haven’t really done much with this and what I’ll do is I want to go ahead and grab the cookie from the request object okay so I’ll console log this right now and I’m going to visit SL API products so let’s go to the browser and since our cookie uh expires in 2 hours we’re going to be fine so we’ll still have the cookie if it expires though and your browser doesn’t have the cookie then of course that cookie is not going to be sent but let me go ahead and close this and let’s go to whoops didn’t mean to open that let’s go to SL API products and let’s look at the console and you can see right now uh whenever I visit that endpoint it says undefined now you’re probably wondering well why is that the case are there really no cookies well let me show you this okay if I were to log it from the headers and if I refresh that page you can see now we actually have the cookies and this is access through the headers but the problem here is that it’s not pars okay we have it in this string format so we have two options we would have to parse it ourselves manually or we can actually use a third-party package called cookie parser to parse the cookies for us so just to confirm with you all the cookies are in fact being sent to the server it’s just that they are not being parsed the way that we expected it to so let’s go into let’s see our terminal we’re going to install cookie parser so cookie hyphen parser and you can see that it has literally like almost 3 million downloads so it is a very popular package in the node.js ecosystem and let’s install cookie hyphen parser and then what we’ll do is we’ll run our server again and now we need to actually enable cookie parer remember that a lot of things that you’re going to be installing as third party packages in Express is going to be middleware okay so in this case cookie parer is also middleware as well so we’ll import that middleware so import cookie parser from cookie parser and then this is a default export so what we’ll do next is we’ll simply just enable it but we want to make sure we enable it before all of our routes are being registered so you see how over here where I have app.use and then I pass in uh that router that router from this file over here and this is what registers all of our routes we want to make sure that we register it before otherwise it won’t parse the cookies for those routes and then we won’t be able to use it so right before um we’ll do app.use and then cookie parser it’s a function and you can also pass in additional arguments into the cookie parser function call if you need them so for example let’s say if you needed to uh parse a signed cookie which is really just a cookie that has a signature then you can pass in a secret and this secret is used to actually parse the signed cookie so that would just be like a regular string like this or whatever the secret is but we’ll leave it alone for now cuz we don’t have any signed cookies okay so now that we’ve enabled the middleware let’s go back to products. MJS inside our routes folder and I’ll go ahead and console log both request. headers do cookies and request. cookies like this and you can see there’s also a sign cookies property as well for sign cookies so let’s go into Postman or not Postman what I’m talking about thunder client and let’s go to API products so we still have that cookie because it has not expired I wonder if there’s a way to actually see the expiration date of these cookies on the Thunder client perhaps not I don’t know but it’s okay we know that it is not expired though so I’m going to go ahead and do this I’m going to send the request okay and let’s look at the server and or let’s look at the console and you can see that we log both the header cookies and the parsed cookies right over here and you can see that it was correctly parsed hello is the field name and then world is the value so that is how we can use cookie parsers to parse the cookie let’s say for example I wanted to check the value I wanted to check the field and the value of a cookie and based on that field and the value of that field I can determine the response that I want to give back to the user so let’s just very quickly pretend like this hello world Cookie is required in order to actually retrieve all the products so what you would do is something like this you would check to see if request. cookies Dot and then the field name which would be hello and then you so you want to make sure this is defined and then you would want to make sure that hello is equal to some certain value in in our case since we set the cookie on the server side and the value that we set was world we can have it check to see if it’s equal to world and if it is then we’ll send back the response of all the cook of all the products and if it’s not then what we’ll do let me actually use the return keyword and if it’s not I’ll just return a response that says message sorry you need the correct cookie and this is just to show you how you can use cookies okay or how you can use cookies to determine the output of your server response so if I click Send right now okay nothing special but now watch this I’m going to go ahead and uh let’s see I’m going to remove this cookie right over here and I’m going to go ahead and click Send and watch what happens you see how now since I don’t have that cookie it says sorry you need the correct cookie now if I go back to the browser the browser is a different client okay so right now we’re using two different clients we’re using the web browser and we’re using our Thunder client so since the browser still has a valid cookie I can still get this data but let me go back into my browsers Dev tools and let me clear the Cookie by simply just deleting it and watch this if I refresh the page you see how now it says sorry you need the correct cookie so this is how you can start to understand how authentication begins to work the server sends a cookie back to the client so that’s basically saying hey when I send this cookie back to you you need to send this back to me in order for you to make future requests to access any data or any endpoint at all the browser stores that cookie and then any future request that you want to make from the browser or the client from Thunder client you need to pass the cookies from the browser or the client or wherever when you send the cookies the server will check for the cookies if you have the cookies and it’s a valid value then you will send the data back to the user if the request does not have the cookie or if they do but it’s not a valid value then you’re going to send them a different response so hopefully you can start to see how cookies can change the output of your application and how you can use it for you know authentication and authorization so one more thing that I will show you is this I’m going to go ahead and set the max age of the cookie to 10 seconds and so what I’ll do is this so since this route is the route that actually sets the cookie itself you can pretend like this is the route that you must visit first in order for you to kind of like authenticate have the cookies set on the server side and sent back to the browser and then be able to access the quote unquote protected route hopefully that makes sense okay so right now if I try to go to API products I cannot access uh the resource over here and you know what let me do one one more thing I’ll also send a 403 which means unauthorized or you can send a 401 back so you see 403 Forbidden okay so now let’s do this let’s go back to the base route and kind of like quote unquote authenticate because this is what gives us the cookie we can we we can see the cookie sent back and now watch this if I try to go to slash API products I can get this I can get this response back but notice how after that 10 seconds pass it says sorry you need the correct cookie so the cookie expires after 10 seconds and you can see that we don’t even have any cookies anymore CU it automatically clears it for us so I can go back to the base route reauthenticate call the API products route and I can make as many requests as I want to this endpoint until once the cookie has expired and once it expires it gives me the alternate response okay so hopefully this makes sense now since we are already talking about cookie parser and using cookies I might as well just talk about this as well if you ever need to set sign cookies which like I said earlier it has a signature uh you can go ahead right over here and set signed to True Whenever you set the cookie but in order for you to actually uh parse cookies that are signed you must you must you must provide a secret like right now if I try to refresh or if I try to go to the base URL you’ll see that it says cookie parser secret required for signed cookies so let’s go ahead and pass a secret right over here let’s just do Hello World literally it can just be any string value you want that is just going to be used for signing cookies okay so now watch this okay before we added this signed property in the options when we set the cookie we were just able to see the Value World so let me just show you this real quick let me just kind of delete this and delete that and just show you very quickly see how the value is just World okay now let me go back and set sign to true and put in that secret so now watch this let me just delete this and if I refresh the page you see how now the value isn’t just world you can actually see the value is here but because now it’s signed it has the signature and in order for you to actually use the sign cookie well because we already are enabling the middle already it will just parse the cookies for us but remember how earlier we took a look at the request object and there were two properties related to cookies there was cookies and then sign cookies right over here so we want to reference sign cookies so watch this let me just Refresh on this page let me change the max age of the cookie to 30 seconds so three so 30,000 milliseconds and let me go back here so now let me go to/ API products you see how now it says sorry you need the correct cookie this is because we are checking just the cookies and not sign cookies if I look at the console right now you’ll see that this is the raw cookie over here that comes from the headers that is not parsed into an object so you see you have the key and then the value right over here exactly what you saw in the browser then you have this object an empty object which is the request. cookies property so an unsigned cookie but because now we have signed cookies all of those parsed sign cookies will go into um that sign cookies object in the request object so you have this object right over here okay so you can actually just reference hello on the sign cookie like that so if I refresh this page uh well we don’t have a cookie so we need to go back to the base URL quote unquote reauthenticate get the cookie set and then now let’s go back to the API products route and if you look at the logs you can see that whenever I reference the sign cookies object and reference hello it gives me this value of world so we can just very easily modify um this part over here if request. cookies instead of that we can just do if request. sign cookies. hello and of course you would need to keep track of what cookies are signed and what cookies are not signed so that will indicate which property whether cookies or signed cookies that you would that you would reference so if request. sign cookies. hello and request. sign cookies. hello is equal to world then we’ll send back this response so let’s save and now our cookie likely likely expired by now so let’s go back to the base URL get that cookie again go back to API products and now we have access to the resource so hopefully this all makes sense in this part of our tutorial we are going to talk about sessions and Implement them in our Express server sessions represent the duration of a user on a website by default HTTP is stateless we don’t know who is making requests to our server so we need to be able to track requests and know where they are coming from one common usage of sessions is to manage user authentication sessions are created on the server by generating an object with a session ID when an HTTP request is sent to the server from the web browser the response can return with instructions to set a cookie with the session ID so that it can be saved in the browser this allows the browser to send the cookie on subsequent requests to the server the the server can then parse the cookies from text to Json then verify the session ID was sent from the client and determine who the request was sent from whenever the browser sends the cookies on each request the server can look up which user pertains to the session as the server maintains a mapping of each session ID to the user we’ll get started in implementing sessions using the express session Library so the first thing that we’re going to do is install the express session package so in my project terminal I’m going to type npmi Express hyphen session and then we need to go into our index. MJS file or whatever root file you have where you create the app instance or the express instance and then you’re going to import session and then from Express pyph session like that so this session import is a middleware function and we can register it by simply just using app.use so app.use and then session just like this and you want to make sure that you are calling app.use right before you are registering any endpoints in your application so remember that I using this router that is imported from uh routes right over here and this file over here has all of my individual routers for products and users okay so what I’m making sure is I’m making sure I’m calling the session middle work function before my routes are being registered so now the next thing that we want to do is configure some options for Express session so the first thing that we will do is set a secret so I’m going to pass in an object and so for the secret this is going to be a string now ideally you would want this to be something that is sophisticated because it is used to actually sign the cookie and if you have it something guessable someone can easily use that value to decode signed cookies for now just for development purposes I’m just going to use anev but just keep in mind you would want this to be something more complicated and not guessable kind of like a password I’m going to set this property called save uninitialized now this property alongside with the next property I’m going to set called resave both of these have to do with session stores we currently don’t have any session stores configured by default Express session does use an inmemory store but you want save uninitialized sets of false when you don’t want to save unmodified session data to the session store so what that means is by default if you have every single user visiting your website and they’re not doing anything they’re just visiting it it will if you have save initialized set to true it will actually save a session object to the store even if the session object has nothing at all and that can actually take up memory and you probably won’t want to have a bunch of random session object objects living in your session store so ideally you would want this set to be set to false and it’s recommended if you’re building something like uh user authentication managing user sessions things like that the other property that we want to set is resave okay and this really has to do with um forcing a session to be saved back to the session store even if the session itself was never modified at all you’ll better understand what I mean by modifying the session once I show you how to actually do it and what it affects how it how it affects the actual session itself but for now don’t worry about these two properties just set to false the other property that I want to set is this cookie property and this is where we can actually configure how long we want the cookie to live because in case if you didn’t know cookies can actually expire so this is good if you have a user login system where let’s say you want the user to be logged in to your website a Max of 24 hours so you can set the this Max H property and uh the value is a number and it’s measured in milliseconds um so for example 60,000 milliseconds that is 60 seconds uh times let’s see 60 so that’s 1 hour so let’s say if I only wanted the user to be logged in for exactly 1 hour then the cookie will expire after 1 hour and that cookie will no longer be valid and so whenever they send it back to the server the server will see that the cookie is not a valid one at all and remember that the cookie that is sent from the browser to the server is what is being used by the server to identify who the user is so I’ll keep everything simple and use my base URL endpoint and what I want to do is inside the request Handler and you can use any endpoint you want I’m just going to go ahead and console log request. session and I want to conso log the session ID as well so you can either reference session ID or you can reference session. ID and I’m going to go and make one API request to this endpoint and you’ll see that when I make a request I can see the session object as well as the session ID being logged and you can see the session object has this cookie property which is an object and you can see that the expiration date is over here so it’s in UTC time currently it’s 2:44 a.m. so uh I think I’m 7 hours behind that time zone so that would be 9:44 and then expires in 1 hour so the date the expiration date time is correct but let’s focus on this session ID right over here okay so I’m going to make another request and notice how when I make another request you can actually see that not only does the expiration date update but also this session ID is regenerated I can create another one one and another one so every single time I click Send it’s going to pretty much like create a new cookie and also create a new session and this is actually not necessarily good because we never can actually track who the user is that’s using our application so this is where you need to modify the session data object when you modify the session data object Express session will create a cook or it will set the cookie and then that cookie will be sent to the browser or the client side the client side will store that cookie and then on subsequent requests or future requests that cookie will be sent to the server assuming it has not been expired okay the server of course will go through the express session middleware because remember Express session is a middleware so it’ll go through this whole session middleware and then it’ll validate that cookie make sure it’s not an invalid cookie so if the cookie is not expired or if it’s not invalid then Express session actually won’t generate a new session or session ID at all okay so hopefully that part makes sense because by modifying the session data object we can begin tracking users that are using our website our API if we don’t then we’ll just always have generated sessions all the time brand new sessions all the time okay and remember if you had save uninitialized set to true it would save all of these sessions even if it’s not modified to the session store so that would use up a lot of memory for no no good reason whatsoever so what I’ll do right now is I’m going to modify the session object by just simply referencing request. session and I can attach Dynamic properties onto this session object so let’s do a simple one I’m going to go ahead and reference visited and I’ll set this to true and I’m just going to remove uh I’m just gonna remove the session oh I’ll leave I’ll leave everything alone for now and now watch this okay let me go into my thunder client and I want you to take a look at what happens now when I make my first request so the server just restarted because we’re using node modon so whenever I make changes it’ll restart the server but I just made one request and you can see this is my cookie and this is my session ID notice how now when I make a new request every single time you see how now the session ID is the same every single time okay every single time I make a request session ID is the same and the reason why this is good is because now I can actually track the user you can see that we have this visited property on the session object and since the ID is not going to be generated every every single time the server itself knows what the session ID is they can look up the session ID and attach the correct session data to the incoming request object so we’ll know who which which user is so let me show you an example okay so what I’ll do is I’m going to go ahead into any endpoint right now I can go into any endpoint and what I want to show you is if I go into let’s it’s let’s do SL API users so this endpoint gets a list of all the users and I’ll just console log request. session and request. session ID and I’m going to go back into my thunder client so remember the server just restarted so because we are not using a persistent data store for our sessions everything gets wiped out because everything is currently in memory so I’m going to go ahead and click Send for our base URL I’m going to make a request to the base URL first because that is the endpoint that will actually set the cookie for us okay it’ll it’ll modify the session data which will set the cookie and then send it back to the client so if I click Send okay you can see that I have my cookie generator right over here and also if I click on cookies on Thunder client and if if you’re using the browser or if you’re using Postman you can also look at the cookies yourself but you see how I have this cookie right over here and you’ll notice how uh everything after these let me see if I can zoom in a little bit you’ll see that everything after these first four characters all the way up until this dot so this whole thing right over here is actually our session ID you can see that they match if I put them side by side you can see that they match right over here and then and of course everything over here is the signature of the cookie because it’s signed All right so now that we have our cookie from the server now I want to show you what happens when I visit a completely different endpoint so let’s go to API users because that’s where we’re also logging the session data as well okay so right now we have a cookie we’re sending that cookie to the server the server is going to make sure that cookie is a valid cookie and if there’s any data for that session ID that was retrieved from the cookie that was sent to the server if there’s any any data in the session store it’s going to map it to that incoming request object okay so basically this session object comes from the session store essentially it get it kind of gets restored but let me make a request so I just made a request just now and notice how when I made that request okay I get the same exact cookie right over here okay you see how I have the same session ID same session ID in a completely different endpoint you see how this object now logs visited true whereas before the previous one didn’t obviously because we didn’t have a cookie set properly when we visited this base URL okay but when I visit this base URL we modify the session object so then that will set the cookie and send it to the browser we make another request to the user’s API so so when we do make that request request. session now has that visited true property set and it has the same exact session ID so it’s important to understand this because now we can actually build out some kind of authentication system and know who each user is one more thing that I do want to show you is I want to show you the session store currently so remember that by default the session store is in memory so it saves everything in some data structure and it lives on the server and of course this is not good because when it’s volatile so if the server goes down and you may have seen this already we have to visit the website again and have a new session created for us so I just want to show you this real quick so let me reference console.log request. session store and I’m going to call this get method and I can pass in uh any session ID okay and then uh let’s see we have to pass in a callback function so that’s okay let me actually do this instead so I’m going to pass in request. session. ID and a callback function so let’s see error and session data and I’ll just do if error throw error and and then I want to console log the session data just so you all can see what this looks like all right so now let me do this in my browser okay so I have these cookies set which are not going to be valid anymore because we just cleared we just uh restarted database so now if I go to the base URL first we have have the cookie set and let me just kind of go to my console and scroll down okay so this is our session ID now if I’ll go to the user Point okay same cookies but notice how this is coming from this part right over here line 29 so notice how when I called request. session store.get I can pass in any session ID and of course if it exists then it’ll give it to us which I’m logging it right over here on line 29 so that’s where it’s coming from okay so that is how the session store stores these session object data so I hope that makes sense because I really want you all to see this visually because just by saying it it kind of doesn’t really help you understand how things are being saved underneath the hood but at least it helps you better understand that now we can see that this session data is stored in some data structure on the server in memory but in later parts of this tutorial I’m going to show you how to use an actual database to store the session data so that way when your server goes down the session data gets restored so I did want to provide another example with how to use sessions and express so what I’m going to do is show you all how to set up this fake authentication system it’s not like a real authentication mechanism but the goal of this is to help you understand how we can map a single session ID to a realistic user in our application so I’m going to go into my main index file and I’ll just set up the route inside here instead of having to create like a new router and such because I want to keep this simple so I’m going to reference app and whoops sorry about that I’m going to reference app and I’m going to call the Post method to set a post request and the endpoint for this will be/ AP SLO and then we will need a request Handler I’m not going to do any validation on the request body um just because like I said I want to keep it simple we’ll just assume that the payload that we’re sending the request body that we’re sending to this endpoint is correct all right so let’s go ahead and grab the request body and then what we we want to do next is uh let’s go into our constants MJS file if you don’t have uh a list of mock users then you could just simply create one or like I said you can just pull the code from GitHub but I did actually do this earlier I provided a bunch of passwords for each user object so that way we can actually use this example so go ahead and make sure you have a username and a password these two are important okay so what I’m going to do is whenever we we make a request to this endpoint we’re going to go ahead and look up the user by the username and we can assume that the username will be unique which is pretty standard in applications so I’m going to go ahead and destructure from the request body and I’ll do this all on this one single line I’ll D structure username and password and of course we are assuming that these fields do exist okay again I I would recommend you yourself uh validate your actual uh request bodies and if you don’t know how to do that check out the section where we talked about validating post requests or validation in general and you’ll learn about that so what I’m going to do is now I’m going to reference mock users but I do need to import that into this index. MJS file so let me go up top here and import mock users from utils consents JS and then I’ll simply just do a search on the user so const find user equals mock users find and then we’re going to pass in the predicate so we want to search for the user by username so I’m going to pass in this predicate function and that the argument for that function is going to be the user object so I’m going to reference user. username and compare it to the username that we’re sending to this post request so this will search for the user by the username and if it does not return a user fine user will be undefined so from here let’s set this up so what we’ll do is we’ll check to see if find user is undefined so if if not find user okay then what will happen is we’ll return a 401 return response that’s status 41 which just stands for uh unauthenticated so let’s just do send message you can also just send the message as bad credentials like that so of course if the user is found then this whole if statement would not be executed but if it is not found then it would return a 401 next check that we want to perform is checking the passwords making sure that they match and like I said we are checking raw passwords that’s okay for now later on you’ll learn how to actually hash the passwords and save it to the database and then also be able to compare hash passwords so I’m going to go ahead and write another if so if find user do username oops sorry not using password I’m going to do if it’s not equal to password then I’m going to return the same exact response right over here um okay let’s see okay that’s fine and then I could probably also just you know what I could probably just combine this into one single statement so if there’s no user or if the passwords don’t match then we’ll just send this back I guess that can work fine now remember the main purpose of this endpoint is to modify the session object because we want to stop generating new session IDs every single time we want to be able to allow Express session to generate that session ID once set the cookie and then send that cookie back to the browser or the client so that way when the client sends another request we can use that session ID and look up the session data and from the session data we can see which user actually belongs to this session ID so what I’ll do here is whoops what I’ll do here is I’m going to reference request. session and then I’m going to attach this Dynamic Property called user and I’m going to attach the fine user value to this user property so remember we can attach Dynamic properties to objects in JavaScript so I’m going to do that right over here and then this should modify the session object and that will have Express session set a cookie and send it back to the browser or the client as a response okay and then the browser will have that cookie and now they can use that cookie to send it to the server and the server will know who that user is so watch this uh let me go ahead and return response. status I guess 200 would be fine for logging in and then send let’s send back the user that was authenticated okay so this endpoint should work let’s just test it out so let me go ahead and make a new request post request Local Host port th/ / o and we’ll pass in a username so let’s actually uh let me go into my mock users array so I’ll do Anson and then the password for Anson is hello 123 so Anson and then password okay so now you can see that right over here I have logged in okay obviously you wouldn’t want to return the password back but like I said just a simple example if I look at the cookies I can see that I have my cookie right over here okay this is my session ID right over here so now that I have logged in and I have a cookie set on this client side right over here I can now make requests to the server and the server will receive that cookie it’s going to parse it and it’s going to take that session ID that I got from the cookie and then map the session data object to that session ID itself so what I’m what I’m going to do now is this I’m going to go ahead and set up one more endpoint app.get API status and this is just going to show the authenticated status of the user so whether the user is authenticated or not in in this context we can tell if the user is authenticated by checking to see if request. session. users defined because remember this right over here is what actually indicates that the user is quote unquote logged in the moment that we modify the session and we’re only doing it when we find the user and the passwords match okay so what I can do is I can just Che simply check uh let’s do this I can use a turn operator so return request. session if user is defined at all then what I’ll do is I’ll returnal response status code of 200 and I’ll just send back request. session. user and then if the user is not defined on the session object then I’ll just send back a 401 so I’m just going to copy what I have up here but I’ll just simply say un uh not authenticated okay hopefully this get request that I’m setting up makes sense so we have one endpoint that actually does the core authentication the other endpoint gets the authentication status hence why I call this endpoint uh SL API status so our server just restarted so again everything is in memory so it gets cleared so we do need to reauthenticate again so I’ll just show you real quick let me delete all the cookies okay me just okay so let’s click send to the same endpoint for/ API we’re going to send this username and password payload okay so I just got back a cookie right over here and now watch this if I were to now visit the status endpoint API status endpoint and make a get request to it you’re going to see that the response is going to be the actual off user okay the response is the actual off user watch what happens if I clear my cookie okay so if I clear my cookie right now and if I try to access this endpoint you see how it gives me a 401 unauthorized error see not authenticated right over here and remember that I cleared the cookie from my client so the server received the request and received this get request without any valid cookie okay and since there was no valid cookie there was no mapping between that session ID from the cookie to a user that’s in the session store so hopefully that makes sense and additionally what I’ll do is let me just quickly reference request. session store get and let me call the get method and let me pass in that session ID session ID and then error session I’m just going to log the session just to show you all how everything again is stored in memory so let’s go ahead and do this let’s make a post request to SL API of course if I pass an invalid password it’ll say bad credentials if the user is not found same thing so let’s log in okay I have my cookie right over here and now let’s visit the status endpoint for SL API status okay we’re good to go with that and if we look at the console I want to show you that right over here we are logging the user in the session store okay right over here so if I go back and click Send you’ll see that it’s logged every single time we’re grabbing the session data from the session store and the session data object that we retrieve by that session ID has this cookie property that gives us information about the cookie and then it has this user property which is the user object itself so that is how the session ID maps to a user on the server side so I hope I really hope this makes sense because if you understand this then you can understand really anything with sessions and I really hope that all of this makes sense because I can understand sessions are kind of a little bit difficult to understand but by seeing how the data is saved on the server side and how we can actually retrieve it so easily like this and map it to the session ID that can help you understand sessions a lot better now what I’ll do is I will authenticate on Thunder client with this set of credentials and then I’m also going to authenticate on Postman with a different set of credentials just so that you can see how with different clients we can authenticate with different credentials and we can see the status of our authentication and then you’ll actually see how the server manages multiple different sessions so let’s just very quickly uh let’s see okay so we’re not authenticated so let’s make a post request to SL API with uh username Anson and the password hello 123 okay so we’re authenticated here uh let me grab another set of credentials so Jack and hello 124 so let me go into post man make a post request HTTP Local Host Port 3000 API off let’s click on body Tab and then select raw and then make sure it’s set to Json whoops and then so now set username to Jack and the password was hello 12 4 okay and remember we’re in a completely different client right now Postman is its own environment obviously and just to show you this we don’t have any cookies set right now so the moment that I click uh send right over here so I just made a request and you can see it’s right over here if I click cookies now you’ll notice how on my Postman client I now have this cookie and of course this cookie is different than the cookie that we have on Thunder client because we’re two different users now that’s the thing that I’m trying to show you we’re two different users you can see that the cookies are different okay so if I were to visit this API status endpoint with a get request you can see that uh it tells me um let me see here we go I don’t know why that was formatted like that okay so you can see that in on Postman I am logged in as Jack and then on the Thunder client I am logged in as Anson see uh whoops right over here look at the response I’m logged in as Anson so now we have two users that are quote unquote logged in and you can see that the session store contains both users they contain Jack and and Anson so hopefully this also helps you understand how the server can manage not only one but many sessions and map each session to different users now I’ll show you even one more example where we can set up a virtual cart system for authenticated users so to keep things simple I’ll set up a simple post request and then the end point will be SL API SLC cart pass in our request Handler and then we only want the user to be able to add items to a cart if they are authenticated so if let’s say request if there’s no request. session. user return response I’ll just send status of 401 okay however the user is authenticated the next thing that we want to do is of course check to see if the cart already exists on the session object because if it doesn’t we need to add it if it does we can just simply add the item to the session cart now of course the request body itself will just pretty much be data relating to an item that we’re adding to the cart so just to keep things simple the request body for this endpoint will just have a name for the item and the price for the item that’s it so let me just destructure the request body from the request object and I’m going to rename this to item and we’re going to assume that the field and all the the values for our request body are valid but I encourage you to practice and actually validate your request bodies so first thing we need to do is check to see if the cart exists on the session object and that’s pretty easy to do I’m going to go ahead and destructure the cart property from the session object so cons cart and then inside these curly braces where the cart variable goes equals request. session so if C is already defined I could just simply do cart. push item and this should be able to just modify the cart and then if the cart doesn’t exist then what I can do is I can reference request. session. cart equals an array and then pass in that item as the first element in this card array just like that and once we’re done we can just return a response status of 2011 and I’ll just send back the original request body so let’s test out this logic let me go into Postman so I’m currently not authenticated that’s okay if I try to make a post request to API slart it’s going to give me unauthorized that’s perfectly fine so let’s first authorize so make a post request with our credentials to SL API off so we are authenticated and now let’s go ahead and add items to our cart so name orange and then price let’s do oops that should be a number let’s do 199 click Send okay so that’s our cart okay so now I can see that this was the item that was returned so that’s good so what I want to do now is I want to actually see the cart so what we can do is make a get request to off SL status and this should return I guess only the user but we want to get the cart so let me do this uh let me set up a quick app.get route for the cart itself so I’m just simply setting up a get request for/ apsc cart and then I’m going to do the same thing up top over here if there’s no user defined in the session object then they are unauthorized so we’re going to return a 401 and then I’m just simply going to return response. send request. session. cart and if cart is undefined we’ll just return an empty array like this using this double double question mark operator okay so if cart is undefined will return empty array so let’s test this out again so we need to reauthenticate so let me do do this okay so make a post request to the Au end point so now we are logged in and now I can verify I am logged in so that’s good so if I try to get my cart you can see that I have this empty array but if I try to add items to the cart and if I make a get request you can see that I actually have items in the cart so pretend like this is the API that your front is calling and then as you want to add items to the cart for the user you would just pretty much add it to the session data and then whenever you want to get all the users items in the cart you can just grab it from the back end like this and I can add more items let’s do uh Gatorade and 299 and let’s make a get request and you can see now I have two items in my cart and let’s go back to postman and authenticate as Jack So currently on Postman we are unauthenticated I’m going to make a post request to the/ API SL off endpoint and pass my credentials so now we are authenticated so that’s good and if I try to get my cart for Jack you can see it’s just an empty array because we don’t have any items in our cart so let’s fix that let’s add some items to the cart so let’s do name broccoli and then $4.99 okay so now I added broccoli to my cart as Jack when I make a get request this is my virtual cart that comes from the back end and then on Thunder client where I am authenticated as anen this is my own virtual card so each user each session has their own data okay each session maps to its own user and then it maps to its own virtual cart for that user and whatever other session data that we need to add we can just very easily attach it to the session object itself so I hope all this makes sense and like I said I wanted to give you all multiple examples because I understand sessions can be a little bit tricky to understand sometimes but what we’re going to do is move on to actually learning how to set up authentication with a library such as passportjs in this part of our tutorial I’m going to teach you how to use passportjs to integrate authentication for your express application we’re going to be using a local strategy for passport which just means that instead of using a thirdparty provider like Google Facebook Twitter we’re actually going to be using credentials that are saved on the actual applications database in our case we don’t have a database so it’ll be saved in an array but the idea is for local authentication the application saves that information compared to using just a third party provider to log into their application I’ll show you how to use local authentication and then in later parts of the tutorial I’ll show you how to use OA 2 so that you can learn how to integrate thirdparty providers to log into your application using something like Discord or GitHub or Twitter so let’s go ahead and get started the first thing that we’re going to do is install passport so I’ll type npmi passport and since we’re using a local strategy we need to make sure we install the correct strategy package so aside from passport we need to also install passport hyphen local again if you were using using let’s say Facebook as the way to authenticate users to your platform then you would have to install passport hyphen Facebook as the strategy and all it is is just a package that you install with passport so let’s go ahead and hit enter and this will install the packages for us and let me just go ahead and run my server and now we’ll go ahead and configure everything in our application so what I need to do is I first need to import passport so import passport from passport now passport integrates really well with Express session and many times you will actually use express session with passport or vice versa passport with Express session you don’t need Express session with passport but it is highly recommended and many people do in fact use both of them together because passport will take care of mapping that user that was just logging in with the session ID if you need to recap on sessions check out the previous section of the tutorial where I actually showed you multiple examples of how to use express session so what I’m going to do after importing passport is I’m going to enable it so where I am registering the session middleware which is right over here I want to make sure I’m registering passport after I enable the session middleware because that needs to be done before and then we also need to make sure we enable password before we register our routes so in between the session middleware being registered and where we are registering our routes I’m going to go ahead and call app.use and I’m going to reference passport and call the initialize method just like that okay and then since we are using sessions I’m going to call app values again and pass passport. session primarily this will take care of actually attaching a dynamic user property to the request object called user and then you can actually access that user object by simply just referencing it from the user or from the from the request object and then you can know who the actual user is that is making the request I’ll show you how that works later on so that’s all we need to do inside our index. MJS file so next thing I will do is I’m going to go into my source folder I’ll create a new folder and I’ll call it strategies so this is where I will have all of my strategies so right now we currently will only have a local strategy so I’ll create a file called local strategy. MJS and what I’m going to do is import passport let me zoom in a little bit so import passport from passport and then we want to import this strategy class and it comes from the passport local package now all of the strategies will have this strategy class so if you installed the passport Facebook package it would have its own strategy class just wanted to mention that and then what I’m going to do is I’m going to call passport. use and this is where we tell passport to actually use our strategy okay so we need to pass in an instance of this local strategy right over here of this strategy class so I just need to Simply create a new instance so new strategy like this now the strategy Constructor can take in uh actually two arguments I don’t know if you saw right over here you can pass in options or you can pass in this verify function for now I’m going to just ignore the options cuz you won’t really need this and later on on in the video I’ll explain when you’ll actually need this options but I’m just going to specify this verify function so that’s just going to be this callback function right over here and this callback function takes in three arguments it takes in the username password and it takes in this done function now since my application takes in a username and a password this works perfectly the way that these arguments get passed to this callback function is whenever you make a post request to your endpoint that takes care of of handling authentication the passport will look for the username and the password inside the request body that was sent to that post request endpoint and then they will it will pass it in as arguments to this callback function so this is assuming that we do in fact use a username to authenticate now sometimes you might not use a username you might use something like an email or maybe the username might be named differently so that is where you actually need to pass in this options right over here because you need to tell passport that we’re actually not using a username field but we’re using let’s let’s say the email address field so what you would do is you would specify this username field and then you’ll tell passport okay the actual username field is the email field like that then passport will look for the email field in the request body and then send that as the argument for username so I just wanted to mention that I’m going to leave this out for now and then once we finish implementing this strategy I’ll show you how it actually works so what we’ll do is inside here this verify function think of it like this this is the function that is responsible for doing a couple things but the main thing is to validate the user so you need to make sure that the user actually exists and then you need to check to see if the passwords are the same the password that we sent to the server and then the password that was attached to the user object itself from the database or in our case an array so those are the two main checks of course there might be additional checks that you would want to perform but generally those are the two major ones so again the first thing that we need to do is search for the actual user right now I don’t have a database set up set up but if for some reason you might have one already configured then what you need to do is just use whatever database module you’re using to to interact with the database search for the user by the username in this case find the user and then once you find the user check the passwords so let’s do that so I’ll go ahead and declare a variable called find user and I’m going to import that mock users array so this array just has a bunch of users right over here with a user Name ID display name and password and I’m going to use the find method to search for the user by the username so user. username is equal to username okay so this will search for the user by the username if the user is not found then we actually want to throw an error but before we throw any errors let me actually wrap all this inside a TR catch just like this so so that way now when I throw my error right over here and I’ll say for the message user not found that error will be caught inside this catch right over here okay now let me go ahead and do this if the user is not found we’ll throw an error I’ll handle the error case in just a bit but I want to move on so let’s say if the user is found we want to check the password so if find user. password is not equal to the password that was sent to the server then we’re going to throw another error we’ll just say user or password I’ll say invalid credentials okay okay so now let’s handle the errors that that could be thrown so we’re going to catch those errors inside this catch block right over here and what we want to do is we want to go ahead and call this done function when we handle the error so notice how this done function it takes in two arguments it takes in an error and it also takes in a user which could be a falsy value so of course when an error happens that means the user itself uh was not validated correctly okay so that could be either the user was not found or the passwords did not match so in this case we want to make sure we do pass in that error object and for the user we can just pass in null like that and then this will just pretty much move on from this verify function into the next step which we will get into okay so that’s what we have to do for the catch of course when we are done validating the user if both of these uh cases are false so if the user actually is found and the passwords are actually correct they do actually match then we want to make sure we also call the done function but this time there are no errors so we’ll pass in null and then for the user we’ll pass in the US user that we found like this and that’s it for the verify function okay so like I said for the database you would query the database find the user check the password if the user exists of course and then any errors that are that could be thrown would be caught inside this catch block right over here hence why we’re using try and catch and then if everything is good you’ll call the done function passing null for the error cuz there were no errors and then passing that user instance any errors would be caught with this catch block and then you would call done passing that error instance and then uh passport would take care of handling that error for us okay so the next thing that we need to do is we need to actually register our middleware our passport middleware because right now all this does is it validates the user but there’s still a whole bunch of things that we have to do especially since we are using passport with Express session okay so we need to import this uh local strategy file into our index file but first let’s actually export this password. use call so I’m going to do export default password. use and I’ll import it right over here like this so import and then the path to the file so this will literally import this whole thing right over here into our index file okay and then now we need to set up an endpoint that we can actually use as our authentication endpoint where users will make a request to or the HTT client will make a request to it’ll pass in the user and password in the request body and then that endpoint will take care of invoking our passport middleware so it’ll actually invoke this verifi function let me just quickly log out the username and password let me just do this username and let me do the same thing for password so that you all can actually see what’s happening underneath the hood okay so let’s go ahead and set up our endpoint I’ll just do this inside the index. MJS file um just to keep it everything simple if you’ve been following along the entire series I recommend you put everything in its own router but let’s go inside our index file and let’s set up let’s do this app. poost so the path will be SL API sloth and then we need to pass in passport. authenticate like this and we’re going to call the function like that and then we want to also pass in our final request Handler so let’s do that request and response and then uh let’s go ahead inside this authenticate function call we need to specify what strategy we want to use and it’s literally just going to be the name of our strategy in our case the strategy for Loc local is just local so we’re just going to pass in local like this okay that’s literally all we have to do of course if you’re using Discord strategy you would pass in Discord for GitHub you would pass in GitHub for Google you would pass on Google like that and vice versa so hopefully that makes sense okay so now what I’m going to do is I’m going to go ahead and make a request to uh SL API o making a post request to it and you’ll see how it’s going to go ahead and invoke this passport. authenticate middleware function and then it will call this verify function so let’s do that let me go to Thunder client Let’s do let’s do this okay so post request to our API off endpoint that we just set up click Send okay so ignore this error for now I’ll address that in just a bit but let’s take a look at the console and let’s see what’s going on you can see right over here username and password are being logged so that verifies that we are actually inside this callback function so passport actually called this callback function right over here and then all of this logic is being performed okay so it’s going to go ahead and search for the user if the user not found it’ll throw a user not found error so let me type in a username that doesn’t exist in our array so when I pass in this username an nansen you see how it says user not found that’s the error that I manually throw the that L thrown over here and then it gets caught right over here and it calls the done function okay notice how if I actually don’t even pass in if I pass in a null value for error we actually won’t even get an error this is a completely different error I’m not sure why it says 41 unauthorized but um yeah see it doesn’t throw that error but it gives us that instead okay but of course let me pass the error back click Send and pass in invalid username it will say user not found let’s say if the user is found but the credentials are invalid and so I’m going to pass in the wrong password it’ll say invalid credentials so before I move on let me just show you real quick about the username field that I mentioned earlier so let’s say for example you are expecting the user to provide the email address as their username so let’s say the we have email let’s just do an@ gmail.com as an example so watch this what we need to do is we need to pass in that options right over here and then we need to pass in this username field and just specify the field that’s going to be our username which in this case it’s going to be email and if I click Send you’ll see now I can actually use the email field as my username and if you look at the logs let’s show you right over here okay right over here username an@ gmail.com okay you can of course change in you can change up the arguments change the email like that if you want to so hopefully that makes sense and that shows you how you can use the username field if let’s say the username field was something else let’s say if it was something like user uncore name for whatever reason then you can just specify that okay and of course if I try to send this this one no longer work if I try to use username like this that will not work I have to explicitly say user uncore name so that way passport knows which field to look for so I hope that part makes sense okay let me just remove this part part okay so now the other thing that I wanted to talk about was this error that I just that I just encountered so you see how it says fail to serialize user intercession so here’s the thing we actually successfully were able to authenticate by checking all these credentials and verifying that it was correct but because passport needs to actually serialize the user into the session we need to actually Implement two functions okay because right now we don’t have have those functions implemented that is why we are getting this error so what we need to do is inside our strategy file I’m going to go ahead and reference passport and I’m going to go ahead and look for this serialized user function so I’m going to call that and this function takes in an argument which is a callback function like this and this callback function takes in two arguments this first argument is going to be the actual whoops the actual user that we are trying to see iiz okay so first of all what exactly does this function do well this function is responsible for actually taking that user object that we just validated and then storing it in the session okay and that’s the reason why I mentioned earlier that passport integrates very well with Express session so it takes that user that we just found from this verify function and it’ll take care of storing it in the session data okay the second argument is going to be the this done function so inside this serialized user function you don’t really need to do anything but just call this done function and it takes in two arguments it takes in an error in this case we’re not really doing anything so we just pass a null for the error and you’ll notice that right over here the suggested uh name for the field it says ID you can actually pass in whatever you want for this second argument that relates to the user so for example I can just pass in user like this okay now
depending on what you pass in to this second argument actually ends up being the argument that will be passed into a call function for this the serialized user function don’t worry about that right now I’m going to implement it in just a second but what what I want to do instead of passing just the user object I want to pass in the ID of the user like this you want to pass in something that is unique okay so either the ID or a username something that is unique that can be used to search for the user either in our array or a database okay so now let’s move on to the next function that we need to implement so deserialized user is the next function and this also takes in a callback function and this C function takes in two arguments it takes in whatever it was that you passed in to the done function for serialized user so notice how I pass in the ID so this actually gets passed into this callback function for deserialized user okay and let me actually show you this stack Overflow post because I think this post is very helpful for a lot of people so I want to show it to you all so right over here they kind of give you like an explanation to how all this stuff works but I want you to pay attention over here they have they were able to provide the user was able to provide a visual flow so you can see over here we have both our serialized and deserialized user functions so whatever they pass into that done function for serialized user that pretty much gets saved to the session okay and I’ll show you later how that looks like um in as an object but it gets saved and it gets passed right over here okay well it doesn’t really get passed per se it’s just it’s just that we the deserialized user will use the ID to actually search for the user inside that function that we’re going to implement okay if we were to pass in the username then it would look up the username in the session data and it would use that to search for the user in the database okay but I just wanted to show you this very quickly because I think this is extremely helpful for a lot of people instead of just not mentioning it at all so the second argument for the call back function for deserialized user will be the done function as well but this time inside der serialized user we actually need to search for the user itself now again serialized user is to tell passport how to serialize that user data into the session so in other words it’s going to store that user ID into the session data okay and that’s really all you need deserialized user is how we can take that ID and kind of like unpack reveal who the actual user is and then what happens is it takes that user object that we were able to retrieve via the ID and it stores that user object into the request object itself okay so later on you’ll see how we can reference request. user when we make requests but what we need to do inside der serialized user is search for the user either in our database or in our array so what I’ll do is let me use a TR catch and first I’ll search for the user so cons find user equals mock users and I’m going to search by the ID this time so user ID is equal to ID if the user is not found I’ll throw an error and we’ll catch the error inside this catch block right over here and then we’ll call the done function and we’ll pass in an error we’ll pass in the error that we caught and then we’ll pass in null for the user because the user was not found and then if the user is found we will call done passing null for the error and then passing the user instance like this okay so again we’re searching for the user if it’s found then we will call done and then password will take care of taking this user object and attaching it to the request object itself if the user is not found then it will just call the done function inside this catch block with the error and then password will handle the error for us okay so now let me go ahead and write some logs real quick because I I really want to show you all how this all works and I want to show you the order of operations okay because it’s very important it’s it’s one thing to actually write the code but it’s another thing to actually understand how this all works CU When I first was trying to understand all this I never I didn’t know anything about this at all until I really dug deep into researching how all this stuff works okay so let me write some logs okay um okay so let’s go ahead and do this let’s make a post request to SL API off so notice how right now it’s it’s still processing the request it’s not going to send a response back don’t worry about that yet but let me just show you what happens right over here let me going me go down over here restart oops let me just restart my server you kind of saw the logs up there but let me just resend the request okay so you can see right over here uh first we’re inside the verify function because that’s where we are logging the username and password and then after everything is successful okay cuz we did pass in the correct credentials you can see how we’re inside serialized user and it logs that user object right over here okay so then you’ll notice that nothing else happens don’t worry the reason why nothing happens currently is because after we call serialized user what happens is it’s going to go ahead and call this next middleware fun function which is going to be our request Handler function so we aren’t doing anything inside here so why don’t we actually just send a response back okay and let’s try this again okay so we’re good and everything is good whoops let me do send status sorry about that send status okay okay so everything is good uh what’s going on here user is not defined uh seems like we got okay don’t worry about that I will have to address that oh whoops I’m sorry let me fix this real quick I passed in user instead of fine user let me fix that I apologize hopefully you all caught the error yourself very quickly okay so let me do this again so first I’m I’m going to click Send good and that error just happened earlier because when I made a second request it actually tried to call the deserialized user function so I’ll explain that so the first thing that happens is when we first log in we call serialized user once that’s all we need to do is call it once this function this call function needs to be called when we log in and we’re only going to log in one time obviously until we log out and then we log back in okay once we have logged in any request that we make later on what happens is passport will then call the Callback function for deserialized user so this callback function is going to get called if I make another request okay so let’s see what happens I’m going to click click Send see how now uh let’s see okay yeah right over here see how right now it’s going to go ahead and call deserialize user inside deserializer and it says deserializing user ID of one okay and uh again we’re it’s calling uh serialized user because we’re actually trying to call the login endpoint but you’ll notice that if I try to call another endpoint it’s not going to call serialized user okay but you can see the order of how things are working let me go ahead and Implement another endpoint let me do this let me Implement app.get API let’s Implement a status endpoint and this endpoint is responsible for checking to see if the user is authenticated or not okay so remember how earlier I said that the user object will be attached to the request object so if I were to console log request. user and let me just go ahead and write inside because we have a bunch of logs everywhere so I want to label everything and then what I’ll do is this so I’m not going to send the response back I’ll just log this right now okay so let’s redo everything let’s log in so let’s go ahead and call this endpoint so it goes ahead and we log in it calls serialize user and then inside serialize user we log the user that’s fine now let’s make a get request so let’s let me hit new request okay I’m going to make a get request to that new endpoint sl/ status and now inside this status endpoint uh we want to make sure that we are only sending a response back the user response back if the user object actually exists on the request object and that’s a good indicator to let you know if the user is authenticated or not so if request. user I’ll return a response with the user object U and of course if the user is not defined if this property is not defined and it’s there’s no value then we’ll just simply return response uh let’s do send status 401 and let me actually just quickly use I’m going to use a turn operator instead return request. user so let me just copy that and then response then status 41 so now I can remove this okay hopefully that makes sense uh oh whoops sorry about that okay should have been colon so this is a turning operator over here all right so let’s go ahead and do this let’s log in right now so I’m going to make a post request to my authentication endpoint click Send okay we’re good now let’s go ahead and make a get request to the status endpoint uh let’s see user is not the find I might have an error somewhere else [Music] um what’s going on over here oh whoops I forgot it’s not User it’s request. user okay um let’s re log in so you’ll see that when I log in we are inside serialized user so that gets called that’s fine so now we don’t need to log in anymore because we’ve already logged in one time so we should be logged in so if I click this right over here you can see that I can access my user reference because I’m logged in as ansen and notice how when I make a request to this endpoint it’s going to go ahead and call the deserialized user function you can see the logs are right over here and again what happens is the deserialized user function will use that ID from the session store okay CU that’s where the data is really being saved inside the session store and also the session object itself and then it will use that to search for the user in this case we’re only saving the ID let me also show you one more thing that was also mentioned in that stack Overflow post as well let me console log rec. session and let me just do this oh whoops it’s whoops sorry about that it’s request. session yep okay all right so let me do this again and let me go down here okay you notice how right over here and the reason why I’m showing this because again I want you to understand how all this works notice how now the session object has this passport property and if you saw the part where we talked about Express sessions you’ll remember that as soon as you modify the session object it sets the cookie and sends it to the front end or the client so if you see right over here if I look at cookies I actually have this cookie right over here and this is my session ID on the server okay so as soon as it as soon as we modify that session which passport is modifying the session for us so it attaches this passport object to it and then it notice how it takes this ID and then Maps it to the user like that and that’s assigned to the passport object and now watch this if I were to go back to serialize user and if I were to change this to let’s say username so let me do that real quick so let me change it to username I’ll just remove this log right over here so let’s search by the username okay and now I want you to see what happens so I’m going to log in right now okay so I’ve just logged in and I’m going to make a request to that off/ status endpoint and now if you look at the logs you can see that we are we serialized the user by using that username field now some of you might wonder well why can’t we just pass in the whole user object so let’s say for example instead of just passing in the ID or just the username I pass in the entire user object right over here so since we have the user object I probably don’t even need to search for it so you know what let me just comment all this out and I’ll pass in I’ll just replace all this for now I wouldn’t recommend this but I’ll just show you what happens so let’s reog in and you can see how now passport. user has the entire user record populated okay so let me explain to you why you probably don’t want to do this because your session data you don’t wanted to have a bunch of information that could possibly go stale okay because think of it like this right something like the ID is never going to change okay the username might change every once in a while but the ID is never going to change if let’s say the display name changes and then you deserialize the user by simply grabbing that user from the session data and then you grab everything including that stale display name that’s going to be returned back to the client if they request it okay so if you make changes to the database it’s not going to be synced up with your session data you’ll have to manually update that yourself and that is going to be an additional uh you know scope of work that you’ll have to take care of and you also don’t want to just store a bunch of properties inside the session data that you don’t really need because it’s just going to take up a lot of memory and you’re going to you know clog up your entire database with all of the stuff that you don’t need all you really need is just some unique identifier such as the ID or the username and then you’re good you don’t need anything else aside from that okay the Der serialized user function is responsible for finding that user and then attaching it to that request. user object that’s all it is okay so again you could do it but should you probably not all right so I’m just going to change everything back to using the ID and then let’s go ahead and take a look at this so I’m going to log in I’m good here I can log in as any other user I want so watch this uh oh and one more thing I’m going to show you notice how if I delete my cookies and if I try to call this endon again is going to give me a 401 unauthorized cuz I don’t have that cookie anymore okay which of course makes sense but let’s try to log in as a different user so let’s log in as Adam so the password is hello hello so I am logged in as Adam okay so now if I make a get request to the status endpoint my credentials will be Adam adom so now you’ll see in the log that this is what we have okay so I hope all this makes sense and I hope you better understand how to use passport now um and what I’ll do in the next part of our tutorial is we’re going to go ahead and actually set up a database and then you’re going to learn how to use the database to create the user and also save the user to the database and then we have a fullon login logout mechanism before I end this part of the tutorial though I do want to show you one more thing on how to log the user out in other words just destroy the session okay so what I’ll do is WR over here so I’m going to set up an endpoint it’ll be a post request so app. poost apith logout let’s pass our callback function and then first let’s just check to see if there is uh no user defined which means the user is not actually logged in then I’ll return a response and I’ll send a status of 401 which means not authenticated and then if they are logged in we’ll just reference the request object and then we can just call this logout function and then we do need to pass in a callback function for this okay and then all I’ll do is this if there’s any error I’ll just return response send status 400 I guess and uh I think there that’s really all we need to do but if there’s no errors I’ll just send a response back of 200 okay let’s test this out now so let’s log in and then let’s see our status so we are logged in let me go ahead and make a new request so it’s a post request so SL API SL SL logout and you can see now we are logged out and uh okay so our cookies are still going to be present on our client but if I try to make a request to the status endpoint it’s going to say 401 unauthorized because even though we are sending cookies to the server the server knows that that cookie is not valid okay so even if I try to uh well now if I actually try to send a post request to here you can see that it gives a 41 unauthorized because we are not logged in okay so it doesn’t matter if we have the cookie this cookie is no longer valid so it’s going to give us a 401 okay so hopefully uh this makes sense and in the next part of this whole tutorial series I’m going to actually set up a database and then we’ll actually convert everything over and then you’ll learn how to actually encrypt the password as well instead of just comparing raw passwords right now which is what you don’t want to do so I’ll see you in the the next part of this tutorial all right so now in this part of our tutorial I’m going to show you how we can actually connect to a mongodb database using uh mongodb as well as so what we’re going to do is first obviously make sure you have mongodb installed on your local system I do already and I’m going to go ahead and install mongus which is is a node module so let me go into my terminal and let’s do npmi whoops Mongoose like this okay so we’re good with that so now what we want to do is let’s just go ahead into our code and we want to actually connect to our database so it’s pretty easy so all we have to do is first import so let’s do import from and I’m inside my index file right over here okay and then what I’ll do is write down over I guess write over here I’ll go ahead and do doc connect and I’m going to pass in the URI so mongodb is the protocol and then the host name so Local Host and then Port 27017 you don’t have to provide the port if this is the port that you use because by default it will use port 27017 but let’s say if your mongod DB is running on a different port then you must specify that Port because the package uses this port by default okay so I’m going to Omit that but then I’m going to specify the database name so I’ll just call this Express uh tutorial and then what I’ll do is disconnect function actually returns a promise so I’ll just use then and I’ll conso log connected to database and then I’ll also use a catch if there are any errors I’ll just simply whoops write a log error and then I’ll log the error so let’s start up our server let’s make sure everything is working fine okay so you can see right over here it says connected to database all right cool so let me go ahead and open up my mongodb GUI my graphical user interface let me just zoom in a little bit so this is mongodb compass you can use whatever you want I’m just going to use this for now so I’m going to connect to my mongodb database I’ll click connect okay so we are successfully connected to to the database so that’s great so now let’s go ahead and set up our very first schema now some people might wonder well why are we using Mongoose and not using like the regular mongodb package for example let me just show you this one over here some people might wonder why we’re not using this node.js driver to interact with our mongodb database the reason why is because realistically in projects you’re not actually going to be uh writing actual query like they do over here you’re going to be using an OM for many realistic projects because they are very safe to use for your codebase it’s the same reason why many people use orms for SQL because it just takes care of a lot of things for you and it also takes care of structuring your data it makes it a lot more easier okay so I just wanted to mention that in case some of you might wonder why we’re not using the regular mongod DB driver but instead we’re using mongus okay and Mongoose is very popular many people use Mongoose if you look at the node module on the website you see there’s 2 million downloads so it’s not going anywhere anytime soon okay anyways let’s go ahead and create our schema so we’re going to create a new folder and I’ll call this I guess mongus and really what a schema is is it’s just a way for you to Define your database uh collection you want to you want to actually sh sh how your data is going to look like and we do that using a schema so I’m going to create a folder called and I have my folder called schemas and inside that schemas folder I’m going to create a new file and I’m going to call this user.js okay and this is where I’m going to create my user schema because what I’m going to do is I’m going to replace uh my endpoint where I create a user so right over here I’m going to replace this so instead of actually saving it to the array we’re going to to just fix this to actually save it to the database okay and then I’m going to show you how we can replace how we can actually use our database to perform the uh authentication validation instead of using the array so the first thing that we need to do is we need to go ahead and of course create our schema so I’m going to go ahead and import schema from like this and then I’m going to go ahead and create a variable I’ll call this us user schema equals new schema just like that and over here we can Define our Fields so what does our user look like so we have a username a display name and a password so let’s set up the username field and we need to specify the data type okay now obviously we’re using JavaScript so there’s no data types in JavaScript or there’s no explicit typings in JavaScript is what I meant to say not data types there’s no explicit typing that we can set to this username field so there’s actually there’s one thing that we can use so let me actually do this import uh let me actually do this instead let me import mongus and do mongus do schema instead and then to set the field for username to basically tell mongus what data type this is we’re going to use mongus do schema. types and here we can reference which data type we want to Define our username as so your our username is going to be a string so I’m going to Define as a string like this and then we’re going to set the display name same exact thing oh whoops this should be comma sorry about that and then the last thing was uh password okay let’s do that password okay great now additionally let’s say some of your Fields might be required ired so what you can do is instead of assigning this type to your field you can actually assign an object to that field and then you can specify type the field type on that object and set it to that mango. schema. types. string and then you can set this uh field called required like this and set it true true like that so I’ll do the same thing for our password as well uh let me just go ahead and I’ll just copy and paste this okay another thing that we can do is for our username we can mark this field as unique by simply just using this unique field and set this a true so that way if there is already an existing user document in the user collection that has this username let’s say ansen and if we try to save another document to the user collection with username set to Anon it’s going to throw an error okay so that’s hopefully that makes sense okay so we’re pretty much done with our schema this is a pretty simple schema so now what we need to actually do after we create this schema instance is we need to actually uh compile it into a model and that’s actually pretty easy so what I can do is I can uh create a variable I’ll call this user and then we just need to reference mongus and then we just call model and then we need to give a name so I’m just call this user and you pass in the schema so user schema like this okay and you use this model to actually perform operations for that user collection for the database so if you want to search for a user you would reference this user model and you would call this find one method like that okay but let’s go ahead and just export this model so we’re pretty much done with our schema and our model all right so now we can go ahead and save data to a database save a user to a database and we’ll go ahead into our user endpoint so I already have one set up right over here already and you can see I’m inside my user router uh right over here so I’m going to just use reuse this endpoint but I would encourage you if you don’t if you are not using routers I would encourage you to do so but if you don’t have it set up just create your own uh / API us endpoint or whatever endpoint you want to create the user I’m going to remove all this stuff out over here and I’m also going to just remove this validation check because I don’t want to combine too much stuff because some I know some of you may have not watched the previous parts of this tutorial and I want to make sure you at least understand the purpose of what we’re trying to do instead of just adding all of these dependencies on top of it but if you have been following along then I encourage you to perform the validation check yourself so that way it’s better practice for you okay but we’re going to pretty much start as if we’re doing it from scratch so don’t worry so what we want to do is we’re going to send the post request to this endpoint and we’re going to send the username password and um the display name okay so const body we’re going to destructure the request body from the request object and since we’re not doing validation right now I’m just going to assume that the validation uh has happened so that means that I’m going to assume that the request body is correct but of course like I said you want to always make sure you are validating everything okay but we we’ll assume just for tutorial purposes we’ll assume that the request body is valid and then what I’ll do is I’ll just go ahead and do this I need to First import that let me remove that I need to First import that user model so import user uh import user from schemas user okay so I just imported the user model and then what I need to do is I need to create an instance of that user model it’s very easy all we do is first declare variable I’ll call this new user equals new user like this and then this Constructor the user Constructor I can pass in the object the body object which contains all the fields that we want to save to the database for the user so once I do that I need to then actually save that user to the database so what I’ll do is I will do this declare variable called saved user now to save the user to the database we just simply call the save method on this new user variable because that’s the user instance but this method is asynchronous so we need to make sure we are using a weight behind this new user. save call but of course to do to do that we need to add the Asing keyword in front of our callback function okay and then let’s also make sure we are handling errors accordingly so what I’ll do is this I’m going to go ahead and since this function can likely throw an error I’m going to wrap it inside the try catch like this because this is just creating the instance it’s not going to throw an error I don’t think the Constructor the Constructor will actually error out it’s only when you try to save then mongodb could failed to save the user maybe because uh the username that we’re trying to save for that new user already exists in the entire user collection so it could error out so first if there are no errors at all and we’re good then I’ll just return a response so let’s set the status code to be 2011 whoops it’s response. status 2011 and then send back the new user like this and if an error does happen uh I’ll just log the error and I’ll just send back a status code of 400 which just means bad request oh whoops should be return misspelled that okay let’s test this out let’s go into Thunder client let’s make a post request to our users endpoint okay and let’s pass in the username anen password let’s do hello one 123 and then display name click Send uh is our server up oh well I forgot to name this user. MJS not user.js so let me rename that um um and I guess I will click yes to update the import so inside my routes file yep yeah so the problem was that I needed to actually add user do MJS here as well okay um all right so now our server should be up and running click Send okay and now you can see the data was saved to the database let’s go into mongodb let’s refresh see how the express tutorial database appears over here and we have our users collection and I can now see my user in the users collection so that’s wonderful and watch what happens if I try to click Send again it’s going to say bad request and the reason why is because uh you can see over here it complains about a duplicate key error and that’s because I marked the username as a unique field okay so if we try to save that same username to the database again it’s going to throw an error so hopefully that makes sense now additionally what I’m going to do and this is really just for the people who are in fact wanting to validate their schemas I will add the schema check right now so what I’ll do is right before we call this request Handler function I’m going to call that check schema function and I’m going to pass in the create user validation schema and like I said all the code is going to be in the description so if you do want to do some of the things that you may have missed from earlier just go to the GI up link and grab the code and you can see everything from there but I’m just using this validation schema and I have this password uh that I didn’t have this before but I just added this just now so I have this password field right over here and then I am making sure that password is not empty and you can see that I’m making sure that the username has all these validators that are applied to that username field same thing for the display name okay so by calling this this will make sure it checks the request body and performs the necessary validation on it this middleware does not actually throw an error we need to go inside the request Handler and actually check if there are any errors so the way we do that is we just simply declare a variable called result and we call this validation result function I think that is imported yep it’s imported right up top over here from Express validator and we pass in the request object into validation result and what this will do is it’ll actually grab that um this Dynamic Property that was attached to the request object that Express validator does for us and it’ll give us the information about what the statuses of the request body it’ll tell us if there are any errors it’ll tell us if everything is good if there are no errors so what we can do is I can just simply say if result uh dot let’s see is empty so this just basically means if there are no errors then we can proceed but I’ll make sure I do this if there are errors so if the result is not empty that means there are errors I’ll return a response and I’ll just simply do this return response. send and I’m going to go ahead and send results. array and this actually gives me all the errors so it will tell us okay what fields are missing or what fields are invalid okay so just very quickly I’ll show you how this works so notice how if I omit display name it’s going to complain about display name not being there if I omit password it’s going to complain about the password and if I omit username username will not it’ll complain about the username over here so hopefully that makes sense with how this works so now of course if there are no errors at all then we can proceed with the rest of our um our logic but ideally you don’t want to use the actual request body object from the request object itself like we’re doing over here you want to actually use this function so let me first declare a variable I’ll call this data equals and then we’re going to call this matched data function which is imported up top over here from Express validator and then I’m going to pass in the request object and so what this match data function will do is it’ll grab all the validated fields for you so it’ll grab username password and display name for us okay so let me remove this and let me place this with data instead and I’ll also just console log data as well and let’s try this again so this time let’s make a post request uh for the username I’ll do Anon one and that was created and if you look at the console you can see that that object is being logged right over there and of course if we did omit any data at all then it would just return that response right over here let me set the status to uh 400 okay there we go perfect so like I said I just wanted to show you how to perform validation if that was something that you also additionally wanted to do but I also wanted to show you a very easy way just to save records to the database okay and everything is going to be similar to how we just did this okay so we have one user schema if you wanted to save products to your database cuz we have endpoint for product s then you would have to make sure you create a product schema compile that schema into a model by using this model function right over here or this model method on the Mongoose import and then now you can just easily create products in your database that’s literally all you have to do all right so now in the previous parts of the tutorial where we covered authentication with passport I was actually using users that were in an array and what I want to do is I want to go back to the authentication part and I want to show you how we can replace all this stuff with using the actual database itself CU I know many of you want to actually see an example of how to do that and that’s what I’m going to do and then after we finish this I’m going to show you how we can encrypt or hash out our passwords because you obviously never want to save raw passwords raw text passwords like this in your database because if someone hacks into your database they can see everything they can see the username the password and that’s not good you want to actually hash it so I’ll show you that after we just replace all this stuff over here okay so first let’s go ahead and do this I’m going to go ahead and go into my verify function right here so this is where we are searching for the user in a database and then we’re going to compare the passwords okay so I’m going to pretty much just remove this Mock usind and let me just remove this whole let me just remove all this okay move all this so we need to First import the user model from our user MJS file inside the schemas folder and then we need to search for the user so I’ll show you how to do that so conine user equals so first we need to make sure we reference the user model and we’re going to call this find one method and this is where we need to actually specify a filter so you’re going to pass in an object and you’re going to specify what you want to search the user by so in this case we’re searching the user by the username so I’m going to set username like this okay since the username argument is the same as the username field I don’t have to do this like username callon username I can just do username like that now this fin one method is asynchronous so we do need to make sure that we await this call and then we also need to make sure we add the acing keyword in front of our verify function okay and of course if there are any errors at all it will just be it will be thrown by let’s say the fine one method and then we’re catching it so that will be handled accordingly so that’s already set up just fine so now let’s first check to see if fine user is actually defined because this fine one method could return null which means that the user was not found so if there’s no fine user then I’ll throw a new error and I’ll just call I’ll just say uh user not found and then the error will be caught right down over here in this catch block which we’ll call the done function with the error instance now the user is found and we can verify that the user is defined so now we want to check to see if the passwords are valid so if find user. password so I can reference the property directly on this instance that I just searched for if it’s not equal to password then we’re going to throw an error as well and we’ll just say bad credentials literally the same exact thing only difference is that we are replacing the array um with referencing the actual user model and calling the f one method okay same exact thing let me just remove these two console logs and we need to go into our deserialized user method and then we need to make sure we remove this mock us that fine and uh instead let me remove all this instead we’re going to go ahead and call user. find one but this time we’re going to actually search by the ID but the nice thing is though there’s actually this method called find by ID and I think this should return just one user record let me just double check yep finds a single document so it doesn’t return an array just wanted to double check so this is good because remember our mongodb database it autog generates these object IDs right over here so we can use that to search in a database okay so I I’ll just pass in ID like that and let’s just make sure we add the Asing keyword in front of our callback function for der serialized user and the rest of the logic stays the same if the user is not found throw an error if the user is found then it’s going to ignore this part and then we’re going to call the done function okay and I think that should be it um let me just make sure that everything else is good uh we can ignore the other parts of our application that are still using the mock users that’s fine okay so let’s test out our login and log out feature using the actual database to search for the user and see what happens so we have two users we have Anson and we have we have our password set to one 12 hello 123 for that so let’s go into let me see okay let’s go into Postman uh so I’m going to pass in Anson and then I’m going to pass in the password hello 123 um oh whoops I made the post request to the wrong endpoint okay so it’s still processing I wonder what’s going on uh let’s see let me try let me restart my server let’s try again uh okay so for some reason it’s still processing I think I may have forgot may have forgotten something let’s see find by ID uh oh yeah that’s right I forgot to call the done function down here silly me so let’s just pass in null for the error and pass in the user my apology click Send okay so we are logged in let’s verify that we’re logged in by making a call to the status endpoint so we’re making a get request so I am logged in you can see now my actual ID that’s in the database is right there okay and I have my username my display name my password all that stuff that’s from the database okay so we are a ble to log in using records that are in the database so hopefully that makes sense okay so now I’m going to show you how to Hash passwords for your users when you’re creating them before you actually save it to the database because right now if you were to look right over here in the database you can see all of the users and their passwords and that’s obviously not good and that’s obviously a huge red flag for any application that that saves the passwords raw like this because if a hacker gets access to your database they can literally see all your users and all of their passwords and that’s not good so you want to make sure you always hash your passwords before you save it to the database and then once we hash the passwords I’ll show you how when we log in how we can actually compare the hash passwords so that way we can validate that the user is actually passing in the correct password so first let’s go ahead and install bcrypt so let me go into my terminal npmi so I’m going to type npmi bcrypt like this and once we’re done let’s just rerun our server again and now what I’m going to do is let’s go into our utils folder I’ll create a new file called uh because we want to keep this logic separate from the rest of our codebase so inside here I’m going to go ahead and import bcrypt from bcrypt like this and what I want to do is I simply just want to create a function that will take care of hashing the password so I’ll create a function and I’ll export it I’ll call this function hash password and this function is going to take in the actual password itself so password and the way that we actually begin hashing the password in bcrypt is very simple the first thing that we need is obviously the plain text password and then the other thing that we need is a what it’s called a salt round okay and basically the salt round just pretty much means uh you know how much time is needed to calculate the hash for for bcrypt so of course the more rounds you you want that it’s going to increase complexity uh the documentation recommends 10 so I’ll create a variable I’ll call this salt rounds equals 10 like that and then uh what we can do is we first want to actually generate a salt so this is the rounds but we want to still generate the salt so I’m going to go ahead and call bcrypt and then I’m going to go ahead and call this gen salt method like this and then you can just simply pass in the rounds so salt rounds like that and then this is asynchronous but there’s also a gen salt sync function that is synchronous so if you don’t want to use async A8 then you could just use this function so it it really doesn’t matter all that much because we’re going to do we’re going to be doing everything in order anyways so first we want to generate the salt so let me store this in a variable so bcrypt do gen salt sync and then pass inst rounds next what you’re going to do is you’re going to go ahead and call bcrypt and then you’re going to call Hash so again this is asynchronous as well so this will return a promise with the data in this case our password hashed now there’s also hash sync which is the same function it just does it synchronously so it doesn’t return a promise but it will call this function and then it return the string so I’ll just use hash sync since I’m using gen salt sync as well so you call this function and you pass in the text password that you want to hash and then you want to pass in the salt okay so I’ll just pass in this salt right over here just like that and then I’m done and then I can just return this so whenever I call Hash password this will hash the password for me so let me actually console log salt as well cuz I want to actually show you what this value looks like so now what we want to do is before we actually create our user we want to make sure we hash the password so I’m going to go into my users. MJS file in the routes folder so I’m going to go back to my users endpoint where I’m creating an actual user so this one right over here and you can see uh right over here on line 61 I’m creating a new instance of my user and then I’m saving it right inside this Tri catch or inside this Tri block so before I actually pass the data into the user Constructor what I want to do is I want to reference data. password because remember this data is the request body that is being sent to this endpoint and we expect there to be a password field and since we are doing validation after this point the password field will be there so I want to basically reassign a new value or assign new value to the password field to the data object itself okay so when I pass the data object to the Constructor of user it will contain the hashed password not the raw password so what I’m going to do is I’m going to call Hash password and that’s going to be imported up top over here from our helpers file that we just created from the utils folder uh where am I okay right over here now remember the hash password function is synchronous because we’re not using any async A8 in here and we’re not returning any promises we’re just returning the string so we don’t need to use async A8 but if you did use the asynchronous methods like gen Sal and then hash then of course you would need to First await this and then you would need to add async like that and then you would need to add async in front of this hash password call so I just wanted to mention that for those of you who choose to use the asynchronous versions of the functions so I’m going to call hash password and I’ll pass in data. password so this will take the raw password hash it and then store it back to the password field for data so I’ll console log I’m already conso logging data up here but I’ll console log it after we assigned the new value for password so let’s go ahead and see how this all works so let’s go into Thunder client let’s make a post request to API users and we need to send a username password and display name let’s change it let’s do uh John and username will be John because we already have Anson as username already in the database going to click Send uh is our server up and running oh whoops I forgot one more thing I think I yep I forgot to name helpers JS to MJS let me rename that and then inside the users. MJS file we need to make sure we are adding that MJS extension that was the main problem over there I keep forgetting so I apologize for that but let’s test this out again so our server is up and running I go back to thunder client click Send uh let’s see password oh username must be at least five characters let’s do Johnny Okay click Send okay and now you can see that the password is hashed let’s go into my database and you can see Johnny is saved in the database and it has the hash password okay wonderful we now know how to Hash passwords and save it to the database now the next problem that we have since we have authentication is we need to be able to actually compare the hashed password with a value that we’re sending to the server because right now let’s say if I try to log in as Johnny let’s do this with our current logic right now if I try to log in as Johnny and I and I provide my password like this it’s going to throw an error it’s going to say bad credentials okay that’s because we’re trying to compare uh this password hello 123 with the hashed text and obviously hello 123 is not equal to this entire thing so here’s what we need to do we need to go back into our strategy file right over here inside our verify function okay right over here what we need to do right before we compare the password instead of uh just comparing the raw password that is sent from the client side with the hash password now we need to actually hash that password that was sent from the client so what I’m saying is when I send hello123 as a password to the server I need to Hash hello 123 and then we’re going to compare that hash to the hash value that’s in the database hopefully that makes sense okay and actually there’s a built-in function that we can use to compare hash passwords and I’ll show you what that field is so let me go back into helpers MJS so there’s this function called uh bcrypt do compare or compare sync I’ll use compare sync and what you do is you pass in the plain text password and then you pass in the encrypted which is the hash password so this will be the actual hash password that is saved to the user in the database so first let me just actually create a helper function so I’ll do compare password equals password uh let me do this plane hashed like this okay and then uh this bcrypt compare sync function will return a booing so I’ll just return that Boolean only pass in plane and then the second argument for compare sync will be encrypted which is just going to be the hashed password and so this will return a Boolean value so if it if these two values are equal to each other then it will return true if it’s not then it will return false so we don’t actually need to rehash anything because this compare sync function will take care of it for us okay so let’s go over to here and then all I need to do is just simply instead of doing this check like this I can just call compare sync or I’m sorry not compare sync compare password and then just pass in the plain password so that’s password right over here so this is the value sent from the client the raw text password and then we’re going to pass in the hashed password so find user. password like that okay and then of course if this returns uh we want to negate the value because if it returns true that means the passwords do match but if the password uh don’t does not match it would return false so if not false then we’ll throw a new error so let’s go ahead and try and reauthenticate and now you see we’re good to go and notice how if I try to log in as ansen because currently ansen has the raw text password save in the database it should actually error out because now we’re trying to compare uh the plain text to a hashed value which obviously is not going to work so yeah that is how you can save the hashed password instead of the text based password to the database and then you can and that’s how you can compare them as well so I hope this part of hashing passwords and how you can save the hash password to the database and compare it makes sense so in the next section of the tutorial we’re going to go ahead and talk about session stores something that will help us tremendously because right now whenever we keep on restarting our server our sessions keep getting dropped from the memory store because it’s volatile so I’ll show you how we can actually use session stores to save the session data to the database so that way when we drop the server and then restart it our session will be restored and you’ll see that we remain logged in okay so now let’s go ahead and move on to session stores so this is something that you very likely will need especially when you want to persist session data for the user because sometimes your server may go down for unknown reasons and they might restart and when that happens all of your session data will be gone because by default Express session stores it in memory so what you want to do is you want to store this in a database so that way it can be persisted whenever your server Goes Down And if it goes back up the session store will have that session data there and express session will look in that session store in the database to grab the session data and restore it for the user so earlier I actually did show you how the inmemory session store looks like and how it stores data I’ll show you again so inside my API users endpoint is where I have this being uh logged so what this does is it looks for the session ID and uh if there are an errors so just throw in error but then we pretty much just log the session data right over here so right now I’m not logged into the application at all I’m not authenticated so I don’t have a cookie or anything but if I make a request to API users and if I show the logs you can see that right over here uh inside session store get that’s where I’m logging this right over here you can see that the session data is undefined okay that’s fine let me go ahead and log in first cuz we haven’t actually U modified the session data at all we haven’t actually logged in yet so let me go ahead and log in so let’s do this API SLO log in oh whoops did I forget yep sorry about that uh bad credentials uh oh wait you know what it is it’s because I’m still comparing the old the raw based the raw text password in database let me use uh Johnny instead and then the password is I think it was hello 1 123 as well okay so I just successfully logged in let’s verify let’s go to the status endpoint and you can see that I’m logged in obviously you don’t want to return the password but that’s something for a separate part of this tutorial but now watch this when I go to/ API users you can see see that in the console so we’re inside session store get so we’re logging it right over here and then you can see that this is the session data and you see how the session data I have the cookie and then I have the passport and then I have the user okay so every single time we make a request to the server um Express session will take care of looking for the session data in the inmemory store and then it will know who the user is okay and then right over here we have the user ID uh inside passport okay and then passport will take care of calling the serialized user with the ID and then it’ll search for the user in the database and then that’s how it’ll grab that user from the database and attach it to the request object okay so if the server goes down so let’s say right now if I restart the server and if I try to visit uh let’s say if I visit the previous endpoint let’s do au/ status you see how it says unauthorized so we’re not even logged in anymore okay all of our session data is gone if I were to go back to SL API users you can see that now the session store does not have our data it says undefined so obviously that’s a problem so what we can do is we can use a session store to save the session data and it’s actually not that difficult to use because all we really need to do is just have a database connection which we already do already so in earlier parts of the tutorial I showed you how to connect to a mongodb database using so that’s this right over here and then what we can do is we can reuse that connection to connect our session store to that database so we’re going to use this package called connect and pretty much this is just a mongod DB session store for Express now let’s say for example if you’re using some other database there are a bunch of different session stores right over here so this is the express session documentation if you just scroll all the way down and you scroll down to compatible session stores you can see that let’s see there is one for couchbase DB there’s one for uh mcash yep connect right over here there’s one for SQL this is the Microsoft SQL Server neo4j redis Firebase there are a bunch okay so you just have to look for this look in this list and find the one that you want to use we’re just going to use connect mango for now so let’s just first install connect so inside my terminal I’ll type npmi connect and of course you must make sure you have already a database connection so in this case since we’re using I can actually just reuse this database connection so now that we’ve installed connect we can import that and into our index file so I’ll import store from connect just like that and then we need to go down into our session middleware and we need to set this store property so where you’re pretty much calling this session function and then you want to reference store. create and since we are using we can actually reuse that connection so there’s this property called client in the connect options like this and then you can reference which which we have imported up top over here and then you can reference connection and then you can call this gets client method just like that okay and this says Returns the mongodb driver client instance that this connection uses to talk to mongod DB okay so let’s go ahead and start up the server again and let’s just make sure everything is good okay so we’re connected to the database and let’s actually try to authenticate now because that’s what actually modifies the session so let’s go ahead and make an API request to API let’s send the username Johnny and then password l123 so we are logged in successfully no errors in the console okay that’s good now let’s go into our database and let’s see what happens okay so I’m going to refresh and you notice how now there is this sessions collection okay notice how now there’s a sessions collection let me expand this real quick and you can kind of see how we have uh let me see if I can kind of do this so you can see it better okay so you see how we have this sessions collection right of here so now we’re actually storing the session data in mongod DB in our database so then what happens is now I’m logged in okay I just logged in I’m going to make a get request to the o/ status endpoint to verify that I am logged in which I am okay so we’re good now watch this the problem that I mentioned earlier was that if I were to close the server so I’m going to exit the server and if I restart it it would log us out because all of the session data was saved in memory but because now that we actually have a session store that is a database it will use the database to restore the session data so watch this okay so I have my session data stored in the database and notice how if I make a get request to the off/ status endpoint notice how I am still logged in okay if I remove this store completely it’s going to use the memory store by default okay and let’s go ahead and restart the server click send notice how now I am unauthorized because my session data is not found in memory because it’s using the inmemory stored by default so I I really hope this makes sense and I I hope this showcases how important a session store is because now instead of having your session data stored on stored in memory it stores it in a database which is great for persistence okay so you can restart your server how many times as you want want the session data will always be restored so notice how now if I just call this endpoint again after just uncommenting out this part the store options now we see our data so what happens underneath the hood is by configuring that session store it will basically look inside the sessions document or inside the sessions collection and it’ll search for uh this session ID right over here so if you look right over here wrg K if I kind of show you the cookies right over here let me see if I can find it you see how this is my session ID right over here and I can even log it too I think I may be logging already nope let me log it right over let’s see let me go into let me go back to to the status endpoint and let me just log request session ID okay and if I make a request again you’re going see that we have that that’s our session ID right there and notice how that session ID is the same ID that’s in the our document right over here so what happens underneath the hood is when we send the request to the server remember we’re sending the cookie back to the server right our cookie is right over here so that gets pars on the server and then what happens is instead of looking for the session data in the memory store it’ll look in our mongodb database which is persistent and that’s how it will take care of looking for the session data sorry about clicking all this stuff let me click over here and show you the the mongodb compass client so it’ll look for the ID okay and then it looks for the session property and it will basically take this whole string of ified object parse into Json and then attach this object to that request. session object which is what you see right over here okay and notice how we have the password data right over here that’s right over here and those how this is right over here as well the user ID so everything is in the database now which is great so now since we’re on the topic of session stores I want to revisit these two properties save uninitialized and resave for uh the session configuration because I mentioned this and I told you all not to worry about it so much until we got to session stores so right now we have the sets of false okay so what this means is uh only when you modify that session data object then it will actually save this to the session store okay so in our case right now when we authenticate using passport passport will modify the session data object for us which means that it will also save it to the session store which is actually what you see happening right over here okay so when you set save an initialize true it’s going to save every single session object to your session store even if you didn’t modify the session at all so I’ll show you I’ll show you an example okay so right now what I’ll do let me just delete this session from the database so that means I’m no longer authenticated you can see right now if I try to make the get request it’s going to say I’m unauthorized okay CU I don’t have that session data stored on the service side now but what I’m going to do is I’m going to go ahead and set save uninitialized the true and I’ll just visit any random endpoint so I can visit uh let’s see I’ll visit SL API off/ status and let me also clear my cookies as well before I do this just so that we are at a clean state so I’m going to make a request to API status okay and notice how it gives us back a cookie and notice how now in the session store you see how it’s saving this session data to the database to the session store even though we never modified the session data at all and you can tell because uh let me show you the logs okay you can see that we have the session data and we have this cookie so it’s going to send us that cookie back but we don’t have anything related to the user at all so if I try to revisit this endpoint again if I refresh I’m still going to use this but notice how if I clear the cookies now if I click if I send a request again it’s going to create another session uh data in the database and then I can go ahead and just clear the cookie again and it’s going to create one again so even though I’m not doing anything but just trying to visit an endpoint it creates a session record for us okay and this really depends on how you want to implement your application sometimes this might be useful but you can start to see that this is not necessarily a good thing because um it’s it’s just going to save a bunch of unmodified session data to your database and that could use up a lot of storage so it’s better to only save the session data when it’s been modified so in cases where the user logs in passport will actually modify that session data and then it will save the session data to the database so let’s take a look at the resave option now so currently it sets a false uh so I’m going to set it to true and currently I have dropped all of my sessions in the database but what I’ll do is I’ll make a request a get request to this status endpoint okay that’s fine we do get back a cookie though which is which is fine as well if I refresh I can see that my session data is over here so what save really does is it pretty much just forces this cookie to be resaved every single time so you notice how right now let’s pay attention to this date right over here this date string okay notice how every time I make a request it’s going to go ahead and update this time right over here okay so if I keep refreshing it’s basically just going to keep updating that expiration date okay so it Reaves it every single time if I set it back to false and let’s go ahead and let me just refresh real quick so pay attention to this time so 14 43 39 so you’ll notice how if I click Send again and I if I refresh notice how the date does not actually get modified because we’re not forcing that cookie to be updated to be resaved every single time even though there’s no changes happening at all now if I actually try to log in so watch this I’m going to go ahead and try to log in now so I am logged in and I think I am using the same cookie as well uh let’s see maybe not let me refresh oh okay so here’s what happened okay so it actually replaced that session ID that we previously had with this one so notice how when I refreshed we have this session ID and you’ll notice that now everything got updated and it modified the session so typically when you do modify the session it will actually update the cookie as well which is what you see over here you can see that I don’t have the same cookie anymore as before okay um let me see yep that’s fine so yeah hopefully the resave part makes sense now typically ideally you would want this set to false and you would also want save an initialized set to false as well but it also could depend on when it’s useful like for example if you have it set to true that could mean that someone just visited your website they’re performing some kind of uh operations maybe they’re adding products to a cart but then once they log in you want to persist that session data as well so that way it’s not gone so once they log in they have their cart all set up already even though they did that when they were a guest on the application so hopefully that makes sense all right so in this part of the expressjs tutorial I’m going to show you how to set up ooth 2 using passportjs so this will allow you to use third-party providers such as Discord or Facebook to log into your application rather than logging in using just local username and password so I will be using Discord as my third party provider to allow myself to log into my application using Discord but as long as you understand what I am doing throughout this tutorial and I will be explaining everything that is going on you should have no problem following along using whatever third party provider you want so even though I’m using Discord you can use literally any other provider such as GitHub or Facebook the only difference is that you just need to make sure you figure out where to create the actual ooth application and you can easily find that out by just going to the developer documentation they typically provide links where you can read up on how to create an actual oo app but like I said as long as you understand what is going on with setting up our Discord oath application and grabbing the required values then everything should be fine and you should be able to integrate this with any third party provider so the first thing that I am going to do is go to my thirdparty providers website so discord.com so and I’m going to go ahead and scroll down to the developer documentation section so if you’re using Twitter for example you would go to twitter.com and search for the developer section okay I’m going to click on get started now and so now I want to look for the section where it says application so right over here applications you want to make sure you create a new application so I’m going to go ahead and call this let’s do ooth to Discord oh whoops o I guess let’s do Anon oo 2 so I’ve just created my application and whatever provider you’re using will prompt you to do the same so now what I’ll do is I’m going to go to the oath 2 section and there’s a couple of fields that we need to get we need the client ID and then we also need the client secret and let me just enter my tofa code real quick and get back to you all all right so I was just able to get my client secret you want to make sure that you keep this client secret private you do not want anyone to know what this secret is so I’m going to copy that and just for now I’m going to just paste this right over here now just for tutorial purposes it’s okay that you are seeing this client secret cuz I’m going to reset it anyways and let me just go ahead and copy the client ID now this client ID is not something that you need to worry about anyone can have it doesn’t really do anything other than just identify the actual applications ID so it’s okay if someone else sees the client ID now the other thing that we need is we need to add a redirect so this redirect is important because the way that the flow is going to work is we need to make a request to an endpoint that’s going to take care of uh redirecting us to the third party provider that we’re trying to authenticate with in our case we need to set up an endpoint later on that will take care of calling passport to redirect us to the Discord platform and then once the Discord platform shows up that authorization page and it shows us all the different permissions and the Scopes that we want to allow we click authorize and then Discord needs to redirect us to this redirect URL so hopefully that makes sense so that’s why we need this redirect URL cuz we need to tell Discord hey once we’re done authorizing send us back to this URL so I’m going to go ahead and just pass in Local Host 43000 because that’s what my server is running on SL API sloth let’s do Discord and then redirect now keep in mind this endpoint has not been implemented yet but we will implement it later on now you can add another redirect URL if you want this is useful if you want to use the same app in different environments such as let’s say uh right now we’re currently in development mode but let’s say you want to use this for production as well then you can add your production URL which is your domain name and then same endpoint I’m going to go ahead and just click save changes and let me also copy this redirect URL cuz we will need this as well so we just finished setting up up the ooff 2 app for Discord so the next thing that we can do is install our strategy package so since I’m using Discord I want to make sure that I install the correct strategy module for my project so remember that there are plenty of strategies to choose from depending on which third party provider you want to use so if you’re using Facebook there’s a passport Facebook library that you can install if you want to use Twitter there’s passport Twitter there’s a bunch you just have to go on this website passport js. org and just search for these strategies so obviously I’m using Discord so I’m going to install passport Discord so I’m going to go into my windows Powershell and I’ll type npmi passport hyphen Discord now make sure that if you don’t have passport the base passport package you install passport because you need passport itself as well I already have it already because I did a tutorial earlier with this passport itself with the local strategy so I’m not going to reinstall it I’m going to go ahead and hit enter and install passport Discord okay we’re good to go with that now let me just run my server again okay there we go so now what we’re going to do is this so in earlier parts of the tutorial I did set a passport with a local strategy however I don’t want to I don’t want to make this tutorial super complex so what I’m going to do is just temporarily I’m going to kind of like disable the local strategy cuz we really don’t want to have these two conflict
with each other and that’s kind of like something that is for a different video to solve and I don’t want to make this whole section super complicated I’m just going to go ahead and comment out the local strategy the local strategy file import up top here and I’m going to leave the rest of these routes alone for now now so what I mentioned earlier is if you didn’t see the part where we set a passport you need to make sure you first import passport like this from the passport package and then right down over here you want to make sure you initialize passport by calling app.use and then passing in passport. initialize like this and then you also want want to configure passport to work with Express session so we just call app.use and pass and passport. session and that’s literally all you need to do the rest of the things that we’ll do for our Discord strategy will be pretty straightforward and doesn’t depend on anything else okay so now that we got that out of the way let’s go ahead and create our Discord strategy much similar to how we created our local strategy so I’m going to go ahead and create a new file and I’ll call this Discord hyen strategy. MJS and I’m going to import inside this file passport from passport and I’m going to import this strategy class and the strategy class actually comes from passport Discord now of course if you’re using a different passport strategy all the passport strategies have this strategy class so if you’re using passport Facebook you can still import this strategy class it’s going to be in every single strategy module it’s standard so now what we need to do we need to go ahead and call passport. use and pass in an instance of this strategy class like this and now we need to pass in options for strategy and we also need to pass in the verify function so I’ll handle the strategy options first so since we are using oo 2 we need to make sure we configure the oo 2 to have it point to our Discord application that we just created so remember how earlier I grabbed the client Seeker the client ID and the redirect URL well all that is going to be passed into this object right over here for the strategy options so first we’ll set up the client ID so you can see there’s this property that I can assign a value and I’m going to go ahead and assign it the value of my client ID and of course like I said if you’re using Facebook or Twitter or whatever the oath app that you create on those platforms will have a client ID it’s standard across any platform that implements o 2 okay and then it’ll also have the client secret so I’m going to grab my client secret and paste it over here keep in mind that just for tutorial purposes I am hardcoding all this ideally you would want to place these values in an environment variable so I’ll recommend doing that but just for tutorial purposes it’s okay I’m going to go ahead and now copy the redirect URL cuz we will need that and the field name is actually callback URL so when I say callback URL or redirect URL I use those terms synonymously okay so we’re going to paste that URL this is the Callback URL that Discord or whatever provider will make a request too upon success upon authorization success now there’s one more field that we need to configure and that’s the scope field and this is important because we need to actually State what permissions that we want to have what Fields what type of information that we want to access and that’s defined all in the scope so by default if you don’t leave the scope at all then you won’t have really any access at all to the user’s information but if you wanted the users’s let’s say username or their Discord ID then you would need to use this identify scope now the Scopes are defined differently on each platform so for example Discord has this identify scope let me see if I can kind of show you all through the documentation let me see right over here okay you see how over here at o off two Scopes and you can see that we have this identity scope and it tells you that what it allows you to access is allows you to make a request to this uh let me zoom in a little bit it allows you to access this users at me end point so if I click on that it pretty much gives you the user itself okay the user that authenticated so we need the authentify scope to get at least the basic stuff like the username the ID of the user stuff like that now it also does mention that it does not give you the email so in order to grab the email you need to use the email scope so notice how over here there is this me scroll up here there’s an email scope and it tells you right over here in the description it enables the same endpoint at users at me to return an email so if you want an email then you would provide that in the scope over here if you wanted to grab all the users servers all their guilds that they are in then you can use the guild scope okay so I’ll just do identify and I’ll do guilds for now so we’re done with our configuration for the strategy options this verif function is responsible for performing validation on the user that’s trying to to authenticate now since we are using oo 2 and there’s no need to worry about a password because they’re using a third party platform they’re not going to be logging in with a password what you would need to do is actually check to see if the user exists in the database and if they don’t you can save that record to the database okay so the reason why you would want to save a third party uh user account to your database is sometimes you might have certain types of data that you want to relate to that user so sometimes you might have uh like a one: one or one to many relationship that you need to associate with the user on your platform so it’s definitely a good idea to save that user to a database so that way the next time they log in they can see all of their relations with other types of data for example the user can see all of your posts all of their messages all of their um current activity things like that okay so it’s always a good idea to save the user now this verif function takes in four arguments the first two arguments are both tokens so access token and refresh token the third argument is the profile so the profile itself is going to be pretty much the user object and it’s going to also have the email if you have the email scope enabled and it’s also going to have all the guilds the servers that the user in so that’s what the profile is and like I said if you’re using Google or Twitter then the profile would contain Google details of the user same thing with Twitter and that would contain stuff like the username email address ID stuff like that and the last argument is the done function which we’re going to go ahead and call when we’re done performing the logic that we need so that way passport can then move on and then take care of the seriation part serialization part which I will explain how that works so the access token and the refresh token these are just uh tokens that you’re going to be using primarily for making uh requests to the API on behalf of the user so the access token is what you would actually use to make API calls so for example for Discord in order for you to actually even call these endpoints such as uh users at me uh users me guilds you need a an an authentication token so that’s kind of like some type of think of it like an API key but it’s not an API key it’s an access token and you use that access token to be able to access the data that you want to retrieve on behalf of the authenticated user so for example if let’s say you want wanted to fetch I don’t know all of the guilds then you would need that access token in our case passport actually takes care of that for us the passport Discord strategy so we would need to manually do it ourselves but if there comes up time where you do need to do it you need that access token the refresh token is just used for literally refreshing the access token so your access token is actually short-lived usually it lasts for about I think I don’t remember the exact time but it is a lot shorter than the refresh token and the refresh token is usually a lot it lasts a lot longer I think usually about 6 months it really depends but what you would do is you would store these tokens in your database somewhere and then you would pretty much use the access token to make requests on behalf of the user and then when it’s time to get a new token you would use the refresh token to kind of like refresh the access token so that way you would not need to require the user to re log in you just use the refresh token to get a new access token and then that new access token can be used to retrieve data from the API on behalf of the user so hopefully that makes sense we’re not going to be using these two tokens though but I just wanted to mention it just so that if you’re using a whatever third party provider you are and then you need to actually make API calls then you know what value you need to be using which is primarily the access token I’m just going to go ahead right now and console log the profile object because I want you to see what this looks like after we actually get redirected to Discord and click authorize but let’s go ahead and actually export our passport. use call like this export default and I’m going to go ahead into my index. MJS file and I’m going to go ahead and import that strategy like this so import strategies Discord strategy. MJS okay so that will load up the strategy into our entire application and now we need to set up an endpoint that the user is going to be visiting in order for them to get redirected to the Discord platform so they can authorize themselves with our application using Discord so ignore all of this stuff right now don’t worry about any of this we’re just going to go down over here and I’m going to set up a simple app.get request and then we’re going to name this NPO API SL o Discord and then we need to pass in that passport. authenticate call and then we need to specify the strategy name which in this case we’re using Discord so I’m going to pass in Discord like that okay now let me show you what’s going to happen once I go to this endpoint so let me go to my browser move this over here okay so let me go to SL API Discord notice how now when I visit that URL it redirects us to the Discord platform and we can see right over here it tells us okay this is the external application wants to access your Discord account and this is what the application wants to access and again all this is based on the scope so if I go into my strategy you can see that I currently have identify in Guilds and it says okay identify relates to the username Avatar and banner and guilds is know what servers you’re in if I were to add email and let’s kind of like go back and go back here I guess I have to revisit the actual endpoint notice how now it says access your email address okay so hopefully that makes sense for now I’ll just do identify which will just give me the basics but like I said if you wanted to get the guilds or email address just add those in the scope and then you’ll be good so let me go back and let’s go ahead and make a call to the endpoint and now it only asks for the username Avatar and banner and then we’ll click on authorize and now we get this cannot gets and notice how the endpoint is our redirect URL so we don’t have this endpoint set up yet so we need to set that up so I’m going to go back to the index. MJS file and I’ll set it up right here so it’ll also be a get request as well so it’ll be SL API othis Discord redirect SL redirect and then you’re going to call passport. authenticate and and pass in Discord strategy like this and then you can pass in the request Handler at the end so after passport is finished logging the user in it’s going to go ahead and call this next middle function which is the request Handler and then we can just send back a response of a status code of 200 okay now I actually forgot to show you the console real quick so that way you can see what happened when we try to authenticate so let me just reauth Kate again and show you what happens okay so let’s go to the endpoint click authorize and now watch this okay so now you can see that when I make a request so what happened is this okay I made an API request to SL API Discord we invoked the passport to authenticate function the first time when that happens it redirects us to the Discord platform okay when you click on the authorized button on the Discord platform what happens is it actually redirects you back to this redirect URL that we set up just now and you’ll notice how uh I don’t know if you can see this now but before when it tried to redirect us there was actually this query parameter up there let me comment this out and show you again okay so you see right over here how we have this query parameter called code okay and then it has this code over here so we actually use that code to exchange it with the Discord API to get the access token and the refresh token okay that’s what the code is used for in order to actually grab the access token refresh token we must implement this redirect URL so the flow works like this it goes to the first endpoint soapi Discord and then we use password to authenticate pass in that Discord strategy name that’ll redirect us to the third party platform once we click click on authorized it’s going to redirect us back to the Callback URL which which is this redirect or over here when you do this when you call passport. authenticate the second time so it’s calling this passport. authenticate middleware the second time it’s going to take that code query parameter and it’s going to exchange it for an access token and a refresh token and then what happens in the end is it goes ahead and calls verify function after it calls this passport. authenticate function the second time now the reason why I didn’t return a response back was simply because we need to continue implementing the rest of this verify function so here’s what we’re going to do I’m going to go ahead and create a Discord user schema for our mongodb database and we’re going to go ahead and save the user to our database so I’ll create a new file inside the schemas folder and I’ll call this file Discord user. MJS and I’m pretty much just going to do the same thing that I’m doing here I’ll just copy this and paste it here here and I’m just going to rename this to Discord user schema and we’re going to have of course we’re going to have a username we don’t need display name we don’t need password uh I’ll also just store the Discord ID I guess so that’ll be a string and then we want it to be required and also unique and then what I’ll do is I’ll take this Discord user schema I’ll pass into this mango. model call as a second argument and I’ll change this from user to Discord user and same thing for this model name right here so this is my Discord user schema and this is my Discord user model and now I’m going to go ahead and inside the verifi function in our Discord strategy this is where I am going to search for the user in the database so we want to search by a unique value that will never change the Discord ID will never change at all so we can use the Discord ID to search for the user safely because of course if you search by the username that could potentially change so not a good idea but better to search with the those ID so let’s go ahead and create a variable let’s call this find user and then we need to use async and A8 so I’m going to add async in front of this callback function inside this or in front of this verify function and inside the verify function I’m going to use the awake keyword and then I’m going to import the Discord user model let me do that real quick I’m going to import that from mongus schemas Discord user like that MJS so we’re going to go ahead and do await Discord user find find one and then for the filter I’m just going to pass in the field that I want to search by so I want to search by the Discord ID like that and then I need to pass in the actual Discord ID as a value so to grab the Discord ID from the profile object you just reference profile. ID like this that’ll give you the Discord ID or if you’re using a different platform like Twitter or Google it’ll give you their respective IDs okay so what we’ll do is if the user is not found we’ll create it so if no find user we’ll create the user and save it to the database so this is a two-step process we first need to create an instance of the new user so cons new user and all we need to do is use the new keyword to create an instance of Discord user like this and you just want to pass in an object that contains the fields that you want to set for this new user that’s going to be saved to database so we only have two fields to worry about that’s username and the Discord ID so I’ll do this username profile. username Discord ID profile so this is the first step with creating the actual user instance and then we have to save it to the database so I’m going to go ahead and call this variable new saved user equals await and then new user so reference that instance and call the save method and the save method is asynchronous it returns to promise so we need to await it and once we are done with this we’re going to go ahead and call the done function and pass a null for the error and then pass in the new saved user so once you call this done function it’s then going to need to call the serialize user function for passport which I’ll show you how to do that as well so don’t worry so I definitely want to add some error handling inside this logic because our fine one method could throw an error and so can this do save method and we want to make sure we’re also handling these method calls and their errors separate because if I just wrap everything inside a TR catch block like this and then I catch the arrow down here it would kind of be like difficult to figure out which method CES the problem is it to find one or to save so here’s what I recommend is first we can declare a variable called Fine user like this and then let me just remove this const find user declaration let me copy this whole line over here where we’re calling a wait Discord user. find1 and I’ll try catch and wrap this method called the find one method called inside the try and then I’m going to sign the return value to find user and if this F web method called errors out for whatever reason then we’ll catch that error down inside this catch block and so here what I’ll do is I’ll return done passing the error and then null for the user however if there is no error then it’ll just go down to here and then I’ll have another try catch so try catch and then right down over here we are still checking to see if user find user is under so if it’s not undefined then we will go ahead and create an instance of the user and then we’re going to go ahead and call this save method which could throw an error and we want to make sure we’re handling it so that error will be caught inside this will be caught by this catch block right here and then now we have handled errors for both possible methods that could throw an error okay so I wanted to just mention that real quick because it’s not good to just write code that doesn’t have any error handling so let me go ahead and return done if there is an error we’ll pass error and then null for the user okay and if everything is successful then we will just call done right over here so we’re not done yet we s it to handle the case where fine user is defined so that means the user already exists in the database so that means they’ve already logged in at least once first let me just add this return keyword in front of this done function call and then right outside over here if the user if F user is in fact defined then we’ll just return done and then pass a n for the error and then pass in that find user object as a second argument so let’s go ahead and try to hit the API so let me just go into my database right now you can see I have this Discord users collection there’s no data in here currently when I go to this Discord endpoint it’s going to go ahead and prompt me to click authorize don’t worry about this error the reason why this error is out right now is because we don’t have the serialized user and deserialized user methods implemented yet but what I want to do is I want to show you in the database if I refresh you can see that my Discord user was created right over here in the database and you can see I have the username and the Discord ID right over here all right so now let’s go ahead and fix this fail to serialize user intercession issue so as I mentioned earlier already uh we went over a lot of these basic stuff such as serialized user and deserialized user with the local strategy I highly recommend you rewatch that section or watch it if you missed that part but what I’ll do is I’ll copy all this stuff from the local strategy file and don’t worry I’ll explain what I’m doing and I’ll explain everything that’s going on so I’m going to copy all of this and I’m going to paste this inside my Discord strategy file so let me explain one by one what’s going on and you know what let me remove this Des serialized user and let’s just focus on serialized user first so inside this verify function whenever we call the done function and assume that there’s no errors so we pass in null for the error and then we pass in this user object okay so what really happen happens when we call this done function is we’re passing in this user object and we’re telling passport that we want to serialize this user object into the session data okay remember passport works well with Express session so this user object right over here is going to be passed into this callback function as an argument right here so whenever we first log in and once that done function is called in the verif function it will call this callback function that is passed to serialize user so whatever you pass in right over here as the second argument to the done function while error is set to null will be passed over to this user argument over here okay so watch this I’m going to leave the console logs alone and I’m going to reauthenticate and you’re going to see what’s going to happen Okay so let’s go ahead and click authorize okay now you see how the error goes away the fail to serialize user inter session error goes away that’s because we were able to successfully serialize user into to the session object because we implemented this function right over here and all you really need to do is just call the done function that is the second argument to this call back when you call the done function you pass in null as the error and then you pass in some unique ID that can be used to identify the user so you can use either an ID or if you want to use the username though even though that is unique it can be changed so you would have to just be responsible for updating the session data cuz the session data could go stale but what we’re doing is we are saying okay I want want to serialize this ID of the user into the session object now remember when we went over sessions I explained how all that stuff works so I’ll show you right now what will happen if right over uh let’s see right over here inside the redirect endpoint I’m going to go inside this request handle and I will log console.log request. session and then you’ll also see that we now have this request. user object so let me go ahead and show you what happens okay so let’s reauthenticate uh whoops okay this is this is the reason why we’re having this errors because we are already logged in and it’s trying to deserialize user because we already have a cookie so what I can do is very quickly I’ll go ahead and just clear the cookie and Let me refresh click authorize now I want to show you the logs you see how now the session object so this session object is being logged right over here inside the request Handler for our redirect endpoint so when Discord redirects us to the endpoint it’s going to go ahead and eventually call this request Handler function and you can see now the session object has that passport property which is an object and notice how we have this user property inside this password object and that is the users’s ID okay and then we also have the request. user object being logged and then you can see that this is the actual user object ID okay that’s the object ID of the user document we have the username and then we have the Discord ID this is the user object itself so that’s the responsibility of the serialize user function it pretty much allows us to say okay how do we want to serialize our user data into the session if I pass in something else let’s just say if I pass the in just the entire user object then what you’ll see is this user property will map to the entire user object okay so let me just go ahead and clear my cookies once again because it’ll throw an error because we are passing a valid cookie but when we do that we actually need the Der serialize user function and I’ll explain a little bit a little bit about that in just a second but let me try to reauthenticate now and now if you look at the logs you’ll see how that user object is is now in the session data like I said all this stuff I’ve went over in early parts of the tutorial when we over passport and session so if you need a recap with a full in-depth coverage of everything of how it works I definitely recommend you to revisit that section okay and it’ll clear up a lot of confusion but let’s go ahead and change this back to passing the user ID and this is the uh the actual document object ID not the Discord ID okay so now let’s go ahead and implement the Der serialized user method so we’re going to go ahead and call passport. deserialize user pass in a callback function as well now this function is important because when we first log in we call serialized user because we’re basically taking the user object we are storing it in the session store and then we’re setting a cookie and sending it to the browser when the browser has that cookie stored it’s then going to send the cookie upon subsequent requests now that cookie is sent to the server and our middle Wares such as Express session passport will take care of everything for us so what it does underne the hood is it’ll grab that session ID from the cookie and it’ll look inside the session store for that session ID and the data that it maps to okay so I actually already have the session store implemented so if I go into sessions you can see that we have a bunch of session data right over here so what happens is it goes inside the session store looks for the session ID so for example these are session IDs and then it references this session property right over here and currently this is a string but what it does is it parses this into a Json object and then it attaches it to the request. session property okay hence why when I showed you when I logged request. session you saw how we had that cookie property and then you also saw that we had that password property and we had the user property all that kind of stuff what these serial user takes care of is it pretty much takes that serialized data so in our case it’s just the session data that’s all uh pars into a string and then it kind of like un undoes it it converts it back from a string to ajason object and restores it by attaching it to the request object so we can access it very easily so we know who the user is and we can get the user session data okay so the first argument for deserialized user is going to be the ID which is really whatever it is that you passed in right over here so if it’s user ID right over here then this argument is going to be that user ID if you passed in user. username like this then this argument is going to be the username if you passed in the user object itself then this argument would be the user itself okay let’s keep it as user ID and the second argument for this callback function is done similar to serialized users call function now inside the serialized user we actually need to to search for the user by the ID so the first thing that we’re going to do is I’m going to use a TR catch always handle your errors and what I’ll do is I’ll search for the user so const find user equals and since we’re searching for the Discord user I’m going to import the Discord user model I think I already had that up top over yep I had it up top over here so Discord user. find one and we’re going to actually search not by the Discord ID but by the object ID so the object ID the object ID are the this is this ID right over here not the Discord ID it’s the autogenerated ID that mongodb generates for each document in the collection so I can actually just use this find one or is finded by ID method and pass in that object ID so this will search for that user by the ID and I need to make sure I await this call because it is a synchronous so let me add the Asing keyword in front of our call call function okay so now if the user is found so I’m I’m going to use a turn operator so if the user is found I’m going to call done pass null for the error and pass find user however if the user is whoops sorry about this find user Mark okay so if find user is defined it’s going to go ahead and call done and then if find user is undefined we’ll call done but pass in uh null for the error and null for the user okay so there’s no error but there’s also no user so now inside the catch we will just simply call done passing the error and null for the user okay so now you’ll see that the Der serialized user function error will go away now to test everything out we’re going to go ahead and make that request to the o/ Discord endpoint which will eventually redirect us back to this endpoint over here and then what I’ll do is I’ll I’ll visit this API off/ status endpoint that I had implemented already from previous parts of the tutorial but it still works just fine because the responsibility of this endpoint is just return the user object that’s on the request object itself and we already configured passport to do that for us okay specifically for the Discord user so let’s go ahead and go back to the browser let’s go ahead and try to let me clear my cookies first because we’re still technically logged in so I want to do a completely new login so let’s do that okay so I’m going to click authorize so I’ve have successfully logged in and now notice how if I go to the console you can see that all of my session data is right over here and then if I go to API status you see how now it returns to me the Discord user that I am logged in as if I were logging in as a different Discord user it would go through that verifi fun function logic and then it would end up ser realizing that other user into the session and then when we visit this endpoint we can see our record that’s saved in the database so I hope all this makes sense all right everyone so in this part of our expressjs tutorial I’m going to show you how to set up just and use just to write unit tests and run them for your express application so just is a testing framework for JavaScript it’s very popular it’s made by Facebook or now known as meta and it’s been around for a very long time and you can use just to write tests and run them for really any JavaScript application many people use it to test no JS server side apps you can use it also to test react apps or angular apps it’s very versatile so let’s go ahead and get started so inside my project one thing that I do want to mention is that remember that we are using ES modules so if you recall inside our package.json file you can see that I have the type set to module and all of my my file extensions are ending with MJS now there’s nothing wrong with using ES modules and it is the way to go in the future with developing surver side with no. JS however as of right now just they currently do support es modules however it requires experimental Flags so you need to enable an environment variable and while that might work out of the box there are some things that don’t necessarily work and after doing some research on stack Overflow and some of the GitHub issues I’ve came to the conclusion that some of the things that I was trying to get to work just wasn’t simply working to say the least so the options that we have are we can either revert our entire project to Common JS so what that means is we remove this type let’s everything back to commonjs because that’s what the default system is and then we would have to remove all of our import statements and replace them with require statements so instead of import Express from Express we would have to do const Express equals require Express like this and then we would have to change all of our export stat stat as well so instead of export cons mock users I would have to do module. export and then pass and mock users like this and obviously that’s not something that is possible for many projects because you might have already written so much code and you can’t just go through every single file and change all those lines just doesn’t really make sense so I figured out a solution where we can actually configure Babble which is a transpiler and we can use Babel to actually take all of our MJS files and kind of like transform them from es modules into commonjs so that we just can actually execute them correctly so we’re going to leave our type set to module we’re going to leave all of our code the way it is we’re not going to change anything at all we’re not going to modify the import statements nothing and I’m going to show you how this is going to work now if you’re someone that is just trying to learn how to write unit tests and you might already have Babble or typescript set up then just actually has documentation on how to configure just with the right environment if you go to the their docs they actually show you right over here if you’re using Babel webpack typescript all this stuff so for example if you’re using typescript you can use tsj right over here even mentions over here and it’s basically just a pre-processor so you can actually use just to test your project right in the typescript so to get started we need to install a couple of dependencies so I’m going to type npmi hyphen capital D CU I’m going to install these as Dev dependencies so the packages are at Babel slore Babel code at Babel slpre EnV so that’s it for Babel we then need to install just as well and then let’s go ahead and hit enter so while this is happening I’m going to go ahead and go into my project folder and I’m going to go ahead and just set up the Babel RC configuration file so you’re going to go ahead and create a new file I’m going to call it Babble RC like this and then I’m going to go ahead and pass an object like that and then we need this presets field and this is going to be an array and inside this array we’re actually going to pass an array and then inside this inner array we’re going to pass a string and we’re going to type at Babel SL preset hyphen EnV and then we’re going to pass a second argument or second element inside this inner array so we have this object right over here and this object is going to have this targets proper property which is going to map to an object and in that object we’re going to have node set to current okay so we’re just configuring the preset EnV for Babel okay so that’s pretty much it for the Babel stuff now let’s go ahead and close that so our packages have finish installing and let’s go ahead and type npm init just at latest so we want to configure just and what this will do is set up a just config file for us so I’m going to hit enter and then it’s going to ask ask us some questions so it’s going to say would you like to use just when running test so this will just create a test script for us so I’m going to hit yes would you like to use typescript if you’re using typescript then press yes but I’m going to press no uh choose the test environment so we are testing a server sided noj application so we’re going to hit enter for node but if you’re testing like a frontend application for react and You’ want to hit jsom do you want just add coverage reports we’ll hit no for that we’ll just select it as V8 and then for this one you want to hit yes automatically clear mock calls instances context and result before every test this will ensure that whenever you run your next test there won’t be any leftover uh mock calls or mock data from the previous test and it’s actually very important so you can see that it modifi the package Json file and then we create this just. config.js file okay so we’re not done yet because there’s one more thing that we need to do inside our just .c config.js file so right over here we need to go to this transform property currently it is commented out but we want to uncomment this part and we want to set this to be an object and now what this transform property will take care of is it will look for those source files that match a regular expression and transform the source code into something that Jess can actually run which is pretty much plain JavaScript so what I’m going to do inside this object is I’m going to use this regular expression right over here I’m going to copy it and you all can just copy this as well so this will just look for our MJS files inside our directory and what I’m going to do is map this value to babble justest so this is going to be the tool that it’s going to use to deal with a transformation and now we actually didn’t install Babel justest but when you install just it actually does install Babble justest for you as of right now if you look at your node modules you can see that there should be this dable just package right over here so that’s how we can verify that that package was installed for us okay so we’re done with this part and let’s just also go into uh right [Music] over let me go over here uh module file extensions so we’ll just uncomment that and we’ll just you can remove the ones that you don’t need so I’m not going to be using TSX or jsx or TS uh so I’m just going to move all that and I’m just going to close this out so we should be done with our setup uh we do need to actually go into our package Json file and for some reason uh when we ran the just configuration it did not override this test script so let’s go ahead and do that real quick whoops let’s go ahead and do that so all we have to do is just have this test script and then have execute this just binary so this will look inside your node modules inside this bin folder and it will look for this just binary right over here and it’ll just run that command and that’s what will actually run your test for you when you are ready so let’s go ahead and write a very very simple test and kind of like explore the just API so what we’re going to do inside our source folder we’re going to create a new folder and I’m going to name it uncore testscore and this is industry standard and this is where you’re going to place all of your tests so you need to create a file and then you want to name the file of your test ideally something that resembles the actual file name so for example if I were testing let’s say something inside my users. MJS file inside the routes folder then I would want to name the test file something like users Dot and then the extension here is where you want to name it either dopc or test and then end it with JS like this so if you were using typescript it would be dope. TS or test.ts since we’re just using JavaScript I’m going to name it dope. JS or. test.js doesn’t matter which extension either test or spec that you want to use I personally like to use spec so I’m just going to go ahead and do that and now it’s going to go ahead and create this file for me okay let’s just explore the just API very quickly and then I’ll get to actually testing some of our express route handlers so we have this described function and now you’ll notice that right now it isn’t going to be imported from anywhere by default just actually so the very first function that you’re going to be using that comes from the just API is this describe function right over here now one thing that I do want to mention is that you could actually import this describe function from @jg globals like this and then you can just use it accordingly like this the thing is though just typically is configured globally but you can see right now for some reason it is not configured globally so I’ll show you very quickly how we can actually configure just to have this describe function and other functions like it test before all for each which are hooks these two are hook functions I’m going to show you how to configure this so that it it’s actually Global so we don’t have to manually import it in our files so what you need to do is you need to First create a new file inside your root directory called JSC config.js and then you’re going to set this object and have this type acquisition property which is an object and then you’re going to add this include property which is an array and then you’re going to want to add just okay now we don’t actually have any any types installed I believe let me just double check yep we don’t have types for just installed is what I meant to say so we need to actually we need to actually install those types in order for us to get it to work so what I’ll do and you can kind of see that now it actually recognizes uh just. describe globally but just to be safe make sure you install the at types slj package like that okay even though we’re not using typescript you can still use this package to have types set up globally like this okay so now you can see that the whoops right over here we have the just types over here and it should recognize them globally without any issues so going back to our users. spc. JS file I’m going to call this just describe function like this and again no no need to import it and this describe function is used used to create test Suites and basically all that means is it allows you to group together your tests into collections so you can better organize and understand what’s going on so typically you want to give your test Suite a generic name that represents what you’re trying to actually test for so for example if I want to let’s see if I wanted to test for a basic I’m trying to look for something that we can actually test uh let’s try let’s do this endpoint so let’s say for example if I wanted to test this endpoint where I wanted to get a user by ID then I would just first name the test Suite something like uh get users and then pass in this callback function so inside this callback function is where you will actually create your test closures and those are basically just going to be what’s actually going to run your test and you’re going to implement the test logic in there so to create a test closure you can use either the it function or the test function they both work the exact same way so I’m just going to use it and then you want to give the test name so I’ll just say something like should get user by ID and then you want to pass in a callback function and inside the Callback function of your test closure so the second argument for this it function this is where you’re actually going to to invoke the function that you want to test and then you want to actually write assertions and verify that certain things occurred okay so here’s the next part though we need to actually write a test for some of our functions so for example let’s say I wanted to test this router. getet API users ID endpoint so this is getting a user by ID and this is actually one common confusion that many developers begin to have when it comes to running tests they look at this and they’re like well how do I actually test this whole endpoint because there’s so many things that are going on do I need to actually make an HTTP post request or get request to the actual endpoint that I’m trying to test so first of all when it comes to unit testing you want to actually test only a single piece of your code look for individual functions that might be calling other functions maybe they are calling a database maybe they are calling an external API whatever it is you want to test that single function and you want to make sure that the function does what it’s supposed to do so ideally you want to verify that the function is hitting the right IFL statements the conditions correctly and then based on those conditions that are being executed you want to make sure that it is returning the correct response so to give you a very simple example let’s take a look at uh this function right of here okay so you can see that this function is our request Handler and it first takes this F user index property from from request and this comes from our resolve index by user ID middleware so don’t worry so much about that right now but we grab this property from the request object and then we try to reference mock us array and Index this user so we can grab the user with its index so if the user is not found in this mock users array it’s going to go ahead and return a response and send a status of 404 if the user is in fact found then it’s going to go ahead and call response. send find user so what you need to understand is this function is pretty simple it doesn’t really do too much stuff but the point is is that we want to make sure that we understand what are the possible outcomes of our function in this situation there are two possible outcomes only only two either the user is not found and we return a status of 404 or the user is found and then we just send back the user that was found there’s only two outcomes sometimes your functions might have many different outcomes it might output many different types of results based on the condition and there are some general principles when it comes to writing your code in a way that makes it easily testable because writing tests also depends on the code quality as well if you have a bunch of spaghetti code you’re making it really difficult to actually write tests okay the purpose is not to actually write the most complex code but to separate concerns and make sure that you have each function doing the main responsibility and anything else you turn it into a dependency function is what we like to call it and that basically just means that you’re invoking another function and letting that function take care of the work and then once that function is done it’ll return back the result and then you can proceed so we’ll start off with a very easy example we’ll use this call function over here but now here’s the other problem though okay when we actually want to write tests we want to be able to import the function or class or whatever it is that we’re try trying to test into our test file so how do we import this Anonymous function there’s no way so what we need to do is we need to copy this function and we need to move it into uh we we need to turn it into a named function so what I’ll do is I’m going I’m going to actually create a new folder called handlers and then I’m going to create a new file and I’m going to call this users. MJS and then what I’m going to do is I’m going to paste this function right here and then right before the parenthesis I’m going to do export con and since this request handler was trying to get the user by ID I’m going to go ahead and call the function get user by ID Handler and let’s make sure that we are importing the correct value so we need mock users so I’m going to import that up here and and I think that’s all we need so let’s go ahead and copy this function and we want to make sure that we pass it as an argument to our router. getet method call so at the end like this and then we’re going to make sure we import that up top over there as well and then now we have our function being passed as an argument it’s still going to work the same exact way the only difference now is that we can actually import it wherever we want so I’m going to go into my users. spc. Js and what I’m going to do is first I’m going to import that function so get user by ID Handler and so this is going to be our system under test or function under test and now we want to actually call this function okay but we need to also remember that this function does take in two arguments it takes in a request and a response so this is where you start to learn how to actually create fake data or mocks so that way you can use them for your test subjects in this case are get user by ID handle function so when it comes to creating mocks there are ways to be smart with it so what we’ll do is we’ll create two simple objects let’s call this mock request and then mock response and remember this the request that response object resembles the actual request type in expressjs okay so if you were to actually look at let me go over to here because we’re using JavaScript okay so if I were to actually rightclick the type definition of this request you can see that we have this interface and you can see that there are a lot of properties on the request object itself okay you can see that we have uh host cookies method prams these were similar methods or properties that we looked at earlier signed cookies as well now you’re probably wondering well when I create my mock object like my mock my mock request do I need to also include all of those fields and the answer to that question is actually no so what you can do is you can only Define the fields that you need okay and again this works because we’re using JavaScript if you’re using typescript then you can use uh casting for example you can type annotate the request and force it to be an actual request type even though it is missing all of its Fields but since we’re using JavaScript we can do literally whatever we want so for our mock request we want to include the necessary properties that our code is actually referencing on the request object so this is where you need to actually look at your code look look at the function that’s being tested and you need to see okay what is actually being referenced on the request object so I can see right over here one property is being destructured from the request object so we need to make sure that this whatever this fine user index is we know that it’s a number but whatever it is we need to make sure we Define that in the mock request object um and it seems like that’s the only property that we are referencing so I know that this is a number because in case of you didn’t watch the early parts of the tutorial this resolve index by user ID middleware function what it does is it will go ahead and grab the ID from the route parameter and it’ll take care of parsing it to an actual integer and then it’ll attach it to the request object so what I’ll do is inside my mock request I’m going to go ahead and Define find or what was it called again uh find user index yep find user index and then you can give it literally any number you want you can give it 1 2 3 100 literally anything you want but here’s the thing though we want to give it an actual meaningful value that is going to correlate with our code so if you look at the rest of your code you can see that fine user index is being used to retrieve an element from this mock users array and this is our mock users array right over here here and if I were so for example if I were to just give like just some bizarre number like 100 it’s pretty obvious that that number would not actually give us back anything inside mock users because there is no element at subscript 100 that would give us back a user okay so let’s just do something simple for now let’s just do one so that way I know that it’ll give me back the user Jack okay all right so we’re done with the mock request object now let’s go into the mock response so this is going to be our response object and now we have again we have to do the same thing we have to look at our code and look at what response uh is and we have to also see what is being referenced on response so right over here I can see that response is being referenced right over here and the send status this is a method on the response object is being called okay so I know that send status is method so that means that inside the mock response object we should set this send status property and have it mapped to a function so you might think that it would look something like this right well no so it is going to be a function but it’s not going to be a regular function it’s going to be a mock function so what we can do in just is we can use this just namespace and I can reference just. FN like this and what this will do is it’ll create a mock function for me so this is where we actually want to call a mocked function of send status on the response object and not the actual send status method itself okay so we use just. FN to apply this mock function to S status and then we’ll do the same thing for the send method as well so let’s do send and then this will be just. FN okay all right so now what we want to do is we want to actually take both of our objects mock request and mock response and pass them as arguments to get user by ID Handler so let’s do that so mock request and mock response okay so now if I run my test right now the test actually should just pass because we’re not actually testing for anything so in our terminal we’ll run npm run test and this will execute that just binary and you can see that our test runs and it passes and just very quickly I want to show you what would happen if I were to go over here and just kind of like remove this part entirely and you’ll see that it’s going to go ahead and complain about all the stuff so that’s the reason why we needed this transform part okay and again we can also run our application completely separate from our tests like this and it still would work just fine okay so hopefully the setup with Babel and everything else wasn’t too complex and we can still proceed to use es modules and write tests okay you can see it’s currently running without any issues well awesome so let’s go ahead and go back to our test and let’s actually write our first assertion so again let’s look at our code again okay and what we can see is there’s two outputs there or two things that could happen either we send a status of 404 or we send the user back so this is where we need to understand okay well what should happen inside this test is whatever it is that we wanted to happen Okay so we have to figure out what it is that we’re trying to test for so in my situation let’s say I want to test to ensure that a user was actually sent back okay and and so we already set up our mock request to have F user index to be a value of one so when the function is called it’s going to use one as the index and search for that mock users so let’s actually write our first assertion so again we need to understand what it is that we’re trying to test in my situation right now I want to test to make sure that the user was actually found and sent back with the response if I look at the code okay how can I verify that the user was sent back well what I can do is I can write an assertion that verifies that this response. send method was called and it was passed it passed this find user object as an argument and I can also write another assertion to verify that send status was not called because send status would only be called if fine user is undefined and since we are setting fine user index to be one it’s going to use that as the index to reference the user at that position and mock users is just this constant array that we have over here so we can just reuse this data because it’s not like it’s coming from a database or some external API so we can use this as mock data so let’s go back into our test and here’s what we’ll do we’re going to use this expect function like this and we use the expect function to actually test a value so for example I want to test that mock response. send like this I want to test this specific function and then at the end of expect at the end of the uh parenthesis we can use these just matchers and the one that I want to use is to have been called so what this means is we are expecting mock response. send we’re expecting this function to have been called okay so that asserts that the function was called when we called this get user by ID Handler so let’s actually test this out and see what happens so let’s run npm run test okay and you see that it passes okay so again this it takes some time to really you know get used to some of these matchers and knowing how to use uh expect but as long as you just keep practicing it’s going to come in it’s going to come in handy and you’re going to develop an intuition behind it so you can see that we definitely wrote an assertion on this send function and we asserted that this function was called and you’ll notice that right now if I were to try to negate this matcher so if I actually use doot do to have been called that basically just asserts the opposite so it’s going to assert that mock response.end was not called so if I run the test it should fail because the function itself was actually called okay hopefully that makes sense and then it’s sometimes good to do that because it it helps you assure that you’re not having your test pass falsely if that makes sense so you don’t have any false positives cuz sometimes your tests may pass when they actually shouldn’t so let’s actually be more specific with our test so what I’ll do is I’ll duplicate this line and I’m going to use the matcher to have whoops to have been called with and this is what what I want to use whenever I want to verify that a function was called with specific parameters so the send function is called with only one argument and this argument is a user itself now again since we are using a mock array I can very easily just reference the array at the subscript of whatever fine user index is which is one so I can just go ahead and import this mock users right over here so let’s import that and that gets import up top here and then I’m just going to access it like this okay or if you wanted to you just literally copy this whole thing and paste it in like this either one will work the same way cuz they’re both going to be the same object and the contents are the same let’s go ahead and run our test now and you can see that it still passes and you’ll notice that if I tried to let’s say if I tried to pass in this direct object and let’s just say say if I tried to change some property values right of here let’s change it let’s change the username you’re going to see that the test actually fails because the value that was actually passed as an argument to the send function is not the same as what we were asserting it to be so you can see that the expected value we expected uh username of Jack without the K so jaac but then the actual received value was username of Jack so again this is good to make sure that your tests are actually passing correctly okay so let’s run the test again and it should just pass just like that all right so hopefully this makes sense and there’s also one more assertion that I want to show you so we can also check to see the amount of times this send function was called so I can do to have been called times and I can specify the expected amount so if I want to verify that this send function was called once then I can just pass one and it should only be called once especially in Express because if you try to call it twice that will actually throw an error so let’s run the test again and of course if I try to pass in like two it’ll throw an error or the test will fail you can see over here the actual received number of calls was one okay so hopefully that makes sense and one more thing as well that I forgot to mention is that with this two have been called with matcher you can actually pass in the number of arguments that the function is called with so we only have one over here but if you had a function that was called with like multiple arguments you can pass in the exact amount okay so let’s go ahead and move on let’s write another test to handle the second scenario of our function so the other scenario would be where fine user is not found and it sends back a status code of 404 so I’m going to write another test using the it function and I’m going to goe and say it should uh call send status with 44 when user not found okay you want to keep your test names short and simple and we’re going to go ahead and write our test so now here’s the thing though okay if I were to call get user by ID Handler again and then if I were to pass in the same mock objects it’s going to actually give us this same response that we have up over here but the problem is now we want to actually get it so that we can set up our code to ensure that the send status function is called instead of the send function okay if I were to just leave mock request alone you can see that it’s still using the same value for fine user index and in the code it’ll actually look for a user and return that user so it would never hit this part at all line six so we need to actually modify the mock request object so what we need to do is there there are a couple ways that you can do this if you prefer to not modify the object directly like this and set it to a value like this you can always just create like a copy of it so you can do something like const and then you can do mock request or let’s just do copy mock request equals and then you can do something like find user index is equal to 100 and then of course you can also destructure mock request because there might be some properties that you want to uh copy over to the copy of the mock request so you can do something like this and then passing copy mock request to here for mock response we don’t really have anything that we need to change because we still have the same functions so it doesn’t really matter so we can leave that alone okay so we’re going to call get user by ID Handler with a new request object but we’re going to set the find user index property to a value that I know that will not give us back a user in this case we’ll set it to 100 okay so when we call this function we now want to write some assertions so what I can do is I can write an assertion to verify that this send status function was called so let’s do expect mock response send status to have been called and then let’s run the test and you can see our second test passes without any issues let’s write a few more assertions so let’s do expect mock response send status to have been called with 404 let’s run the test again pass passes and I can just throw in a value that I know is actually not going to pass you can see that it fails so that’s good because it shouldn’t be sending a 400 it should be sending a 404 and I can also do to let’s do to have been called times let’s do one let’s TR the test again and let’s also write an assertion where we verify that mock response not send was not called so expect mock response send not to have been called let’s run the test wonderful so all of our assertions are good now one more thing that I do want to do though is if you go inside your just config file and if you look for Clear mock you want to make sure this is set true early ear when we were configuring just we had pressed yes when it asked us if we wanted to configure um our test to clear all mock calls instances and context and results before every test because what happens is if this is false the next test will actually carry over data from the previous test so if I actually try to run my test now you’re going to see now our second test actually fails and it’s actually failing because right over here on line 32 where I have this assertion expect mock response. send not to have been called you can see that it’s failing because it says receive number of calls one so it in fact was called but if you think about it your code itself says otherwise because I know for a fact that in my code response. send should not be called because we are returning response. send status so this code doesn’t get executed when F user is uh not defined Okay the reason why it’s failing this test right over here and it’s treating it as if sen was actually called is because in the previous test the sen function was called and it was called one time okay so since it was called one time and we didn’t clear the mock it carried over to the next test right over here inside this second test over here so there’s several ways they can do this the first thing that you can do is obviously what we already had was having clear MOX set to true instead of false the other thing that you can do is you can use this before each hook and this takes in a callback function and basically you can execute some logic that happens before each one of your tests so you can initialize a variable you can connect to a database whatever is that you want so you can actually use this just. clear all MOX function call and now if I run my test it passes okay so this is manually clearing all the mod before each test sometimes you might not want to clear all the mocks because you might want to depend on previous function calls from the previous test so you might want to turn off clear Mock and set it to false sometimes you just want to manually clear the mock so you can use this before each it’s up to you but I just wanted to mention that as well so I’m just going to remove this before each and I’m going to set clear MOX back to true so hopefully these two tests that we wrote makes sense now I have one more example where we can write a unit test for another one of our endpoints but this one’s this one’s going to be a little bit longer so I just wanted to warn you all but I’ll try my best to keep it as concise as possible and I want to do this one because there’s a lot of stuff going on inside this function and I think it would be really great for you all to learn how to test different scenarios okay so what I’m going to do is for my post endpoint for API users this request Handler creates the user and saves it to a database so you’re going to learn how to mock functions that come from modules you’re going to learn how to to mock uh classes es6 classes you’re going to learn how to mock the database call so that way we don’t actually hit the actual database because when it comes to unit tests you don’t want to actually invoke your database or call an external API so you’re going to learn how to do a lot of stuff with this next test so we need to make sure we get this function um out of this uh out of this format we don’t want it to be an anonymous function so I’m going to just copy that and I’m going to go inside uh let’s see not here but inside my handlers file or the users. MJS file inside handlers and I’m going to go ahead and paste this here and I’ll name this function create user Handler like this and uh before I import all of the necessary functions into this file let me just take this and let me just paste it here and import it up top over here okay and now let’s go ahead and go back to our users. MJS file inside the handlist folder and we need to make sure we import all of the necessary functions that we imported that were in the other files so validation result comes from Express validator that’s a validation library that can validate post requests um request bodies query parameters all that kind of stuff we need to also import match data that’s also a function from Express validator hash password is a function that we wrote Our elves let’s import that right over here uh user is the model so this is what actually allows us to interact with our database but we’re not actually going to call the database we’re going to mock out this as well um and I think that should be it okay so now let’s go ahead and go into our users. spc. JS file and then now I’m going to create a new test Suite so outside of this describe get users I’m going to go ahead and create another describe and I’m going to call this create users so you can think of these individual it functions these individual tests as your scenarios okay so inside the create users test Suite I’m going to go ahead and create a simple test and I’ll just say it should let’s see let’s go back into our function okay so this is a pretty big function it does a lot so I take this step by step so that way you all don’t get confused first let me just remove these console logs cuz we’re not going to need them whoops so we want to take this step by step because there are a lot of things that are going on so let’s hand let’s take a look at our code and understand what’s going on so when we call this create user Handler um when Express calls this function to handle the uh create user endpoint it’s going to go ahead and call validation result so when you’re looking at the code the important part is not to really worry about what your what these functions these external functions cuz we don’t know what these functions let’s just pretend we don’t know what it does you don’t have to care about what this function does you have to care about what it returns because we’re going to mock the function anyways we’re going to mock the implementation we’re going to mock the return value of the function so in the end it doesn’t really matter okay what I care about is what it returns so result you might not know what it is you might think it’s an object it’s a number it’s a string you might not know but you can very easily tell if you just look at the rest of the code and look at where result is being referenced so you can see right over here that result has this is empty method that’s being called on it and I immediately know that this is an object okay uh there’s also this array method on result as well so what I can do is I can go ahead and actually mock out validation result because this is known as a dependency it’s a function that that can perform some kind of side effect and we don’t want to actually have any side effects in our unit test we want to make sure that we mock them all out and we only want to test the function itself we only care about the possible paths our function that we’re trying to test and take so again you can see right over here this is our first if condition if result uh dot is empty if it is uh let’s say if this results to false and then we negate that value so if it is not empty then we’re going to return this response status of 400 and then send back whatever this value is again I know it’s an array cuz we wrote this out ourselves but we’re just pretending that we don’t know okay so this is the first thing that it could do the second thing that could happen is right down over here so you can see that we have this new user. saave being called and then it sends back a status of 2011 and it sends the user okay so this is the second scenario the third scenario is that an error could be thrown inside this Tri block so then the save method could have been could have thrown an error and then we catch it down over here and then we send back a status of 400 okay now there actually should be another scenario where the hashing password uh failed and we actually should have added this inside the try catch but we’re just going to leave it the way it is right now okay so hopefully all of this makes sense so now if I were to go back up top over here again the validation result is one dependency Okay so what we want to do right now is we want to test our function to handle this first scenario first because instead of just having to do everything all at once we’re going to take it step by step okay so what I’m going to do is I’m going to write a test that is going to mock out this validation result function call we’re going to have it return uh literally whatever object we want but that object specifically needs to have this is empty method as well as this result uh as well as this array method on the result object cuz they are both going to be call okay so we need to make sure that whatever is empty is going to return it returns false for this case because I can see that we negate the value of result. is empty so for example if there are no errors that’s what this isempty method means if there are no errors you can see right of here it returns true if there are no errors so if this is true the negation of this would uh not execute this line and it would just go down over here which means that there are no errors however is however if is empty is false then result that is empty would return false which means that we negate that which means it would return this part over here so for our first scenario we want is empty to return false just so that we can Target this line over here so what I’m going to do inside my users. spc. Js file is this so I actually already have some mock data defined up there um just to keep things simple I’m actually just going to Define it inside test Suite so const mock request and then const mock response and then it’ll be within the closure of this callback function so we don’t have to really worry about the ones defined up there so what I’ll do is for the test scenario I will say it should return a status of 400 when there are errors and we’ll pass on our callback function okay so now we need to go ahead and set up our mocks our our mock request and mock response to actually get this to work so again we have to look at our request object and we want to see Within These two lines where is our request object being referenced you can see that it’s being passed as an argument to validation result however it’s not going to really matter because we’re going to mock validation result so we actually aren’t really going to need to do anything with the mock request for this specific scenario okay so let’s look at response I can see that response is referencing this status method right over here so right over here we’re going to go ahead and do status just. FN and you know what I actually could just reuse mock response up top over here because we’re going to be using some of these similar methods anyways so you know what what I’ll do is I’m just going to remove this and I’ll just reuse the mock response up here and it shouldn’t matter because we are clearing all of the mocks uh anyways before every test so we won’t have any leftover data from the previous test okay so let’s go ahead and implement the status method and this is also going to be a mock function so we’ll use just. FN okay now one more thing that I do want to point out is that after we call the status method we actually are calling the send method as well because when you call this status method it actually Returns the instance of the response itself and you can actually call the stat status method on it as many times you want because it just Returns the response instance itself so in order for us to actually detect calls on the send function inside uh status over here inside just. FN for status we actually want to pass a callback function and we want to actually return mock response so basically returning itself so that way by returning itself mock response would then have access to all these other methods as well and if we don’t do this we wouldn’t be able to actually test to see if send was called after status and I’ll show you that when we actually write the test okay so we’re not done yet we’re done with setting up our mock request and our mock response we need to now mock this validation result function and you’re probably wondering well how do I do that this is a function that comes from a thirdparty module Express validator well I’ll show you so you can mock modules and what that basically means is you can override the implementation and the functionality that that module that module’s API provides so for example inside the express validator module we have a bunch of functions we have a bunch of different things that we can import that we can use in our application however we want now for our case we only are using validation result currently so we want to mock validation results specifically so all the way up top over here what I can do is I can reference jmck and then I want to specify the name of the module so I’m going to go ahead and say Express validator
like this so This Will Mock that mpm module you can also mock your own modules that you create as well so for example uh later on when we need to mock uh the hash password function we’re also going to mock this helpers module as well okay and that’s our local module so as a second argument after we pass Express validator for the first one the second argument whoops the second argument is going to be a factory so this is where you’re going to return an object because if you think about it your modules are kind of like objects and those objects have um the named exports okay if it assuming it does so what we want to do is we want to return this object like this so notice how I have the parenthesis wrapped around the curly brace so that just allows me to do it shorthand instead of having to do something like this okay so what I’ll do is inside the object I want to mock the validation result function so I’m going to type validation result like that and I’m going to do just. FN like that so now I have successfully mocked the validation result function for the express validator module and now this mock function we want it to actually return something so that way we can actually uh have this result value be something that is defined with the correct is empty and array methods so we can do that inside our Justa FN function we can pass in a call back that also returns an object as well and I can go ahead and Define the is empty method so is empty is going to be a mock function as well but this mock function remember we’re going to have it return uh false okay so passing that call back return false like this and then we also want to implement this array method on the return value of validation result so this is a method and uh it does return an array so we will have it return an array like this and then what you can do is you can add some random object with random Fields so you can just say message invalid username just like an example you can literally put whatever you want like invalid field whatever it is okay because we can always actually modify uh we can always override the return value of validation result and I’ll show you how to do that as well okay so I think we’re good to go let’s actually go ahead and test everything out okay so what I’m going to do is I’m going to go ahead and call create user Handler so let’s go ahead and import that up top over here oh whoops I can just import that from right over here wonderful cuz we’re in it’s from it’s coming from the same file okay so let’s go ahead and call create user Handler let’s pass in the mock request and notice how we’re referencing this local mock request cuz this is the closure we’re inside this closure over here and then we’re going to reference the mock response which is all the way up there so we are reusing that same mock resp responds object from earlier okay and remember that this function is asynchronous so we should also await the call and we need to make sure we add the Asing keyword in front of this callback function for the it function okay all right so let’s just make sure everything is okay so if I run npm run test the test does pass but we aren’t writing any assertion so that’s okay and you’ll notice how now if I actually try to kind of like remove all this all the mocks that we just did you’ll start to notice that a lot of stuff uh starts to error out and you can see that um it’s actually trying to go to line seems like like line8 over here inside the helpers MJS so it’s actually without mocking anything it actually tries to call the actual uh Express validator uh Library so it’s actually calling the functions okay and then it’s going to try to execute everything the way it is but you can see over here it tries to throw this error right over here because we don’t have a value for password but we’ll get to that because right now our request body has uh nothing okay and we also aren’t mocking match data yet so don’t worry step by step just wanted to show you what would happen if we removed the mock stuff okay so let’s add that back in and you can see that everything will work the same way all right so now let’s actually write an assertion so the first thing that I want to do is this so when it comes to testing there are different ways that you can approach testing there is there’s implementation testing and that’s where you’re actually testing the actual implementation so you’re trying to verify that certain functions are called certain functions are called with certain parameters that’s known as implementation testing there’s also behavioral testing where you just give it some input you don’t care what it does as long as it gives you an output so there’s different ways on how you can test this with backend you can’t really go wrong with either either one usually on the front end like if you’re testing apps and react you would want to use behavioral driven testing because you want to test based on output and you don’t care about what actually happens underneath the hood with all of the state and all of the uh you know form fields and whatever is being called to the API stuff like that so I just wanted to point that out okay but since we’re just getting started I’m just going to show you very basic how to write assertions so what I want to do is I want to verify that validation result was called with the request object okay so the question is how do I actually write the assertion for validation result because in my whole test file I don’t have any access to validation result well I’ll show you so the first thing that we can do and I’ll import this over here on line one is I’m going to import the entire Express validated library but I’m going to import it as like a default import like this so import validator from Express validator like this and then now down over here in our test after I call the create user Handler function I can write an assertion and I can reference validator do validation result to have been called times one and let’s run our test and you can see that it passes and if I were to set this to zero to see if it actually fails and it should fail you can see that it was actually called once so that verifies that it was actually called and if I were to actually remove uh if I were to actually just kind of like remove this whole thing right over here you can see that our test begins to fail and it’s not recognizing validation result as a function if I remove this whole just. Mock and if I try to run the test again you’re going to see that other stuff starts to fail as well okay so hopefully this helps you understand the importance of mocking out your modules and hopefully this helps understand how to how to mock out uh these functions that come from the Express validator package or just any package in general okay let’s go ahead and continue so I’ll do validator dot validation results so I’m going to write an assertion to say that to have been called with mock request because if you look right over here we are passing whatever request object this is to validation result so we’ll write the assertion there it passes and let me just change this to two have been called instead of two I’ve been called times one okay that’s a lot more better because this basically implies it’s going to be called once or two have been called at least once okay so now uh we want to also write an assertion that response. status was called with a status code of 400 so let’s do that so expect response dot I think it was status and it’s mock response to have been called with a 400 mock response okay let’s run our test okay it passes good and let’s go ahead and write a search to verify that the do send method was was called so we can do expect mock response and this will be mock response. send not mock response. status. send because remember that when we call the send method we’re still calling it on the instance of the response method so we would have to reference mock response so to have been called with and then we want to verify that it was called with this array and that’s whatever we had mocked over here so I’m just going to take that copy and paste it down over here let’s run the test again and it passes and again I can go ahead and just change everything up and make sure that our test is passing correctly and you can see it throws an error when I pass in the invalid expected argument okay so that’s pretty good let’s go ahead and move on now because we’ve covered this whole part over here so now we have to cover the next few lines over here everything up until down over here so we are calling this match data function but we aren’t mocking it okay so it’s going to actually call the actual match data function which comes from Express validator so we want to mock it because what I want to do is I want to mock this function to return uh some object which is going to be the actual user data so again to give you context uh what this function does is it takes the request body and it gets you it gives you the validation result okay so if there are no errors then what happens over here with match data is match data will extract all of the valid fields in the request body and store inside this data object so all we really need to do is just mock match data to return a user a valid user object so let’s do this okay so going back up over here I’m going to do match data just. FN and we’re going to have it return an object and keep in mind that whatever the return value of matched data is is actually just going to be an object so there’s no methods on it that we would need to worry about because we’re not referencing anything except for just the password field so let’s just do uh let’s see username let’s do test password uh password and then I think the other field was uh I think it was display name if I remember correctly let me check if I go inside my validation schema so we have username display name and password yep so display name just do test name now some of you might be asking well what’s the point of doing all this mocking because doesn’t that kind of defeat the whole purpose of test testing well no not for unit testing because remember our goal is not to actually test to make sure that you know Express validat Works our goal is to test create user handle Works our own function this is a unit test okay when you want to actually test the entire application that is where you want to actually set up an integration test or an end to end test which you will learn about it later okay so hopefully that kind of clarifies the confusion between uh mocking and actually testing the entire thing with without mocking it okay all right so now that we’ve mocked match data this function to return a mocked result so we can safely uh run the rest of our code and then we want to make sure that this match data function is going to be called but we also want to make sure that we don’t hit this if condition and make this true so we need to actually make is empty return true this time which means that there are no errors but the thing is though I mocked it up top over here to return false so what if I changed it to true but then that would break my first test over here so we can’t do that so I’ll show you what we can do to actually change the return value for our specific tests okay because we want this is empty function to return uh true for whenever we call it validation result so that way this if condition results to false and then it’ll go down over here and call match data okay so let me just make sure that we have our match data function mocked properly okay this is good let’s go down over here and let’s rate our next test and I’m going to go ahead and call this test uh let’s see so I guess the overall thing that we are trying to test for is making sure that the response. status is sending back a 2011 and it’s sending back the user that was created so essentially we’re we’re testing for success for creating user so I’ll just say it should return status of to1 and the user created okay and let me actually go up here and let me fix this should return status of 400 okay so let’s add the Asing keyword in front of our callback function for this test and now we’re going to go ahead and call create user Handler so after we call our function we want to actually mock out the is empty method to return true so that way goes to the match data function call so inside our test here’s what we’re going to do we’re going to use just. spyon and I’m going to go and reference um this import up here validator so that’s the entire Express validator package and then we’re going to spy on on uh this function right over here it’s validation result like this okay and then what I can do is I can use this mock implementation once and then in here this is where I can actually mock the actual implementation of the function and I can have a return an object so the same result object but this time that object will have this is empty function so this is also going to be a mock function and it will return true like that okay so hopefully that makes sense so this is how I can override the mocked value of validation result into something else so now what will happen is create user Handler will be called it’s going to go ahead and call validation result and then result that is empty will be called and we can see that’s going to a result to true and then negating that will cause this whole if condition to be false and then it’ll go down over here so what I can do is I can write an assertion to verify that matched data is called so let’s do expect so remember match data is a function that comes from the Express validator package so I’m going to reference validator do matched data to have been called and let’s save and let’s run our test and let’s make sure that it passes okay so it actually is um let’s see okay yeah don’t worry about this so it is actually supposed to pass but the reason why it’s failing is because right now it’s actually trying to uh call the next few functions it’s trying to call Hash password and then it’s also trying to call the database by Saving this new user to the database so don’t worry uh it is working it’s just that um we’re it’s trying to connect to the database and you can see that it actually timed out because we don’t actually have a database connection so don’t worry we actually did the right thing we just need to mock the rest of our function okay so we know that match data is being called and you know what let me just comment all this out and run the test again because I just want to show you all that it passes great so now let’s go ahead and mock hash password because again we don’t want to actually call these functions because remember these functions these dependencies produce side effects okay so we’re going to go up top over here and now I want to mock this hash password function that comes from my helpers module so what I’m going to do is I’m going to call just. Mock and I want to pass the path to that module so we’re in the test folder so we need to go out one folder into utils helpers MJS like this okay and what I want to do is I want to have hash password um I want to I want to mock the implementation so let me pass in the factory and return an object and just overwrite hash password and so this will be a mock function but I I actually want to have it return some custom logic and all I want to make it do is takeing an argument so I’ll just do password so inside this callback function I can pass in this argument password and all I’m going to do is just concatenate um hashed with password like this I’m just going to literally prefix the password with hash so that way it at least does something okay all right so we just mocked hash password or hash password so now let’s go ahead and import up top over here we’re going to import helpers from utils helpers okay and this would allow me to reference helpers like an object and I should be able to reference hash password or maybe I need to do import as helpers yeah there we go okay I think I may have need to do that as well for validator I’m not too sure let me just run everything and make sure it’s good let me go over here and just come this out real quick okay there we go perfect okay just wanted to make sure that didn’t break okay so now we’re going to go down over here and we have wrote an assertion for for the Matched data function okay to have been called uh let me also change this to have been called with mock request to be more specific and then we’re going to go ahead and write an assertion for hash password so what I’m going to do is I’m going to expect helpers do password to have been called and I want to verify that it was called with data. password so data. password password is going to be whatever matched data returned so up top over here matched data returned password so I’m going to say to have been called with password like that you know what for the rest of this test let me just comment out all this stuff over here because I do want to actually see our assertions passing okay good so to have been called with password and then I also want to make sure that hash password so helpers hash password returns with the correct value so to return to have returned returned with hashed password and I know I’m just hardcoding these values but ideally for you you would probably not want to hardcode these values so that way you can make it more Dynamic but I’m just doing this for testing purposes okay just to show you an example so if I run the test you can see that it will in fact return hashed password and that’s just our mock implementation right over here nothing special but at least it is returning with something so we can verify that data. password is uh storing the correct return value okay so now the next part we want to um test this part over here you see how we are creating a new user so this is where we are invoking the Constructor of class so now you’re probably wondering well how do we test that so what we can do is we can actually mock these es6 classes it’s actually not that difficult and I’ll show you how to do it so what we can do is right over in our test file up top over here I can go here just. Mock and I can just pass the path to our our user right over here this this user. MJS file inside schemas so I need to go out One Directory to schemas user. MJS okay and then up top over here you know let me remove this mock users import let me import user from the uh mongu schemas user. MJS file okay so I just mocked that whole module right over here and now what we can do is is so I uncommented this line over here where we call the new user Constructor and I can write an assertion and I can say expect user so I’m referencing the entire model which is a class and that’s coming from this input right over here okay this is our model right over here and then what I’m going to do is I’m going to use the two have been called assertion and I’m going to run the test and it’s going to pass so this verifies that the Constructor was actually invoked if I comment this out you’re going to see that it’s going to fail because it it actually was called or it actually wasn’t called but we wrote the assertion to see that it was called so let me uncomment that and let’s just change this to to have been called with the correct arguments so we want to make sure that it was called with the correct username display name and the hashed password okay so in our test let’s go back up over here so notice how this is the return value of matched data because we are passing uh matched data whatever this return value is into the user Constructor only with the password being hashed so what I can do is I can pass in that object and just change this to Hash Hash password and remember this value comes from our mock function over here we just prefixed hashed uncore with whatever the password is so let’s go ahead and run the test and you can see that now it passes so that’s good and now one more thing that I also want to show you is if you wanted to access the instance that was created so the user instance you can do that by referencing user and it’s going to attach this mock property onto that user and then you can reference instances at subscript zero because we only created one instance and then let’s run the test again and you can see right over here we have the instance and this instance has this save method as well and you could of course also reference the properties on it so let’s go ahead and continue testing the rest of our code so I’m going to comment this out and since we’ve already mocked out the user model or mongus model I can actually just run my test and we shouldn’t get the same errors that we had before because all that is mocked out already okay this save method is mocked everything so what I want to do is I want to verify that the save method was called on the instance this new user instance so what I can do is this I can actually create another spy on this save method so I can keep track of its calls because there’s no way for me to directly ask this unless if I get the instance so for example if I wanted to I could do user. mo. instances zero do saave to have been called like that and this should work without any problem yep and then if I try to negate this call to verify that it’s it’s not passing incorrectly you can see that it actually was called so this is one way that you can do this the other way that you can do this is you can use a spy and I’ll show you how to do that so I’ll create a variable I’ll call this save method equals just. spy on and I can reference user. prototype like that and then what I can do is I can specify the actual method itself on the instance so save is one of the methods and then leave it like that and what I can do is I can go ahead and replace this part to be expect save method to have been called okay and if I run test again the test will pass and if I try to add the not operator in front of it you can see that by adding not operator the test fails because it actually was called so what I want to do specifically is I want to actually mock the return value of save so what I’m going to do is at the end of just. spyon I’m going to call mock resolved value once and I want save to just return the user that should be saved to the database but I’m just going to attach an ID you don’t have to do this but I’m just going to do it anyways and then I’m going to copy that so that way like the reason why I’m attaching the ID is that way it makes it feel like it’s being saved to the database even though it’s not because mongodb generates an ID for us so now what I’ll do is I’m going to go down over here and what I’m going to do is I’m going to let’s see so we are asserting that save was called so now let’s write an assertion on response. status we’ll verify that it was called with the status code of 2011 and then we’ll verify that the response object was called with the send method or called it called the send method with the saved user which means that it includes that user over here that we are mocking the resolved value so let’s do expect mock response. status to have been called with 2011 and then let me just go down here let me change this to mock resp response. send and let me just copy this object paste it here and we should be good so let’s test this out let me run my test and you can see that our test passes so that’s good all right so we’ve covered two cases so far for our crate user Handler let’s go ahead and cover the last case this one’s going to be pretty easy we just need to get it to actually throw this error so here’s what we’re going to do we’re going to go ahead and create a new test so I’ll go ahead and call this test let’s see um it should throw error when save or let’s see it should send a status code of 400 when save uh errors out okay so everything else is good except for when uh the save method is called maybe something failed the database and then it throws us th throws this error and it sends a status of 400 so let’s do should send status of 400 when database fails to save user so I think that’s good enough and let’s make this an async method so we’re going to uh let’s see we’re going to copy this create user Handler right here so everything is going to be roughly the same as the previous test so I do also want to copy this just spyon because we do want to make sure that we are going past this part we’re going all the way down but then it we just want it to fail when it calls the save method okay so the thing is though we don’t need to rewrite all of these uh assertions because we already did before so let me do this um con save method yep so let me copy this save method equals just. spyon let me copy this part and now what we are going to do is we’re going to go ahead and for the save method for this spy we’re going to mock the implementation one time and remember this save method throws it it could throw an error but we’re just going to mock the implementation so when it does throw an error then it’s going to handle this catch block over here but since this save method uh is asynchronous it returns a promise so we have to do promise do reject and we’ll just say failed to save user okay so now we’re basically overriding the save method to actually error out return um return an error so everything in our code should be good and then once it gets to this save method it’s going to go ahead and error out and then we’re going to go ahead and write an assertion on response and Status okay so let’s go ahead and do this let’s do expect save method to have been called and then what we’ll do is we’ll do expect mock response that’s send or I’m sorry send status right over here to have been called with 400 and let’s go ahead and run our test let’s make sure that it works and there we go we have covered all three cases if you want you can go ahead and write some assertions for some of these functions to verify that they were called but you don’t really have to is it would just kind of be redundant with what we have up here CU at this point in this test we know that all these functions are being called it’s just that we’re trying to get to the point right down over here to make sure that we are testing for uh this send status being called with a status code of 400 and if I were to pass 401 that test would fail because it is supposed to be 400 and there you go so hopefully all this makes sense I know this this part of the tutorial was pretty long but that’s because there’s a lot of stuff that I wanted to cover and I felt like with this specific test you learn so much with how to mock modules how to mock classes how to mock your own modules that you create yourself on your uh on your in in your source code so your local modules um and just a lot of stuff about unit testing so hopefully this tutorial made sense and I would highly encourage you to practice writing more tests more unit tests for your other functions as well so for example one thing that I can encourage you to do is maybe for the local strategy if this is something that you have you can go ahead and take let’s see you can probably take this part out you can take this Anonymous function out put it in a separate file and import it in here and then that way you can actually import that function into a test file and test the logic in here and using the logic that I showed you with how to Mock and how to override values of functions by mocking them out you can write those unit tests so hopefully all of this makes sense in this part of the expressjs tutorial I’m going to teach you how to write integration and end2end tests for your Express server so integration tests and unit tests basically involve testing your entire application at least with integration tests you typically are testing certain scenarios and flows in your application like for example create a user and then expect that user to uh return as a response and then try logging in as that user after you’ve created that’s an example of writing an into and test okay you have different scenarios it’s a lot different that unit tests where unit tests you are only testing one piece of your entire code base like one single function and many of you who have seen the previous section where I showed you how to write unit tests may actually find writing integration tests to be a lot more easier because you don’t have to worry about setting up a bunch of mocks okay some people do get confused with how to Mock and what to actually mock but with integration and ENT test you just call your API and then you write assertions so the first thing that I’m going to do is I’m going to actually disable the OA 2 configuration with the Discord strategy right over here I’m going to comment it out and I’m going to uncomment out the local strategy because I want to actually use local authentication we’re not going to be testing oath 2 we’re going to be testing actual local authentication where we create a user and then we can log in with that user and then we will verify that the user was created and that we’ve logged in so let me just do that so just uncomment this file everything else is set up the way that it should be and then we should have our both serialized these serialized user functions okay so we’re done with this part just want to do that very quickly now let’s go ahead and install super test so you’re going to type npmi hyphen D super test and we’re going to use super test with just they both work very well with each other and we already have just set up already so if you missed a previous section of this tutorial where we configure just and wrote some unit test check out at least at least the first 10 minutes of the video where or maybe like the first 5 to 6 minutes where we set up just okay then come back to this video but all the code is going to be in a GitHub Link in the description so check that out so you don’t have to like you know watch the whole thing you just copy the code and get the setup and then come back to this video so I installed super test now let’s go ahead and go back to our code what we’re going to do is we’re going to create a folder inside the source folder and I’m going to call it e2e like this cuz I want to keep all of my unit tests separate from my end to end tests because it’s good practice to do that and it’s also industry standard as well and I’m going to create a new file and I’m going to call this index. spc. JS or you can call it index. test.ts if you prefer okay and I’m not going to I’m going to leave this blank for now I’m not going to write anything just yet inside this new file what we need to do is we’re going to go into our package.json file and we’re going to add a a new test script but I’m going to call it test colon e2e so that way I can run either only unit tests or only endtoend tests for the test E2 script the way it’s going to look like is we’re still going to be using the just binary so again make sure you have just installed and configured and then we’re going to use this test path pattern flag and I have it point to the source The Source SL folder so that way when I run test colon e2e it’s going to go ahead and only run the tests inside this folder over here okay so we can run just the end to end tests and not the unit tests with it okay so we’re done with this now we’re going to go ahead into our index. spc. JS file and what I’m going to do is I’m going to import Super Test from Super Test like this and then I’m just going to show you a very very easy example right now I’m going to import Express and I’ll set up a very simple Express server with literally nothing no middleware nothing okay whoops didn’t mean to do that so I’m going to call the Express function and I’m going to register a simple test routes so I’ll call that route hello and we’re just going to send back a status code of 200 okay and then now to actually use super test the first thing that I’m going to do is I’m going to use the describe function again this comes from just so make sure you have just configured and I’m going to go ahead and call this hello endpoint just something simple and then I’m going to passing that callback function and inside the Callback function for describe this is where we’re going to have all of our tests so I’m going to use the it function that’s part of just to write my actual test so I’m going to go ahe and just say get hello end point well actually let me do get hello and expect 200 okay so I have one test inside my describe callback function over here and I can add more test if I want to so this is where we’re going to actually call our API so we’re going to use this function actually actually I’m sorry it’s not super test from super test it’s import request from Super test or that’s how you should name it import request from Super test because this is actually a function so let me just I just fix that real quick sorry about that so let me just invoke this request function which is this super test module over here again this is the top level function that we’re importing and then we’re just going to pass our app instance like that and then what we’re going to do is we’re going to go ahead and call the get method so whatever endpoint point that we want to make a request to and whatever method type you would use that one so for a get request I would use get for post I would do post so I’ll do get and then the URL so hello and then you want to pass in a callback function if you need one but I don’t need one right now so after the do getet I can go ahead and use uh this expect method at the end so I’m chaining this expect expect method on the return value of get and then what I can do is I can expect a status code like this I can do expect 200 and now let’s go ahead and run the test so we’re going to run the test by using this test e2e command that I just set up earlier so npm run test colon e2e like that and our test should pass there we go okay perfect awesome not sure why it took forever it might be because we did not end the request but I can do at the end of the expect call I can do end and then error res and and do if error throw error like this and that should fix that error in in the last part yep there we go perfect so you can see that the test passes and of course if I were to change the status code inside this app.get inside this request Handler I change the 2011 to kind of like throw off this test over here and show you what happens so let’s do npm run test e so the test should fail you’ll see that the error actually uh is thrown right over here the problem here though is that even though we are expecting 200 over here and keep in mind this is the expect method that is on Super Test not from just okay you can see that right now over here it still treats the test as passing even though the test shouldn’t pass and um even if I were to write an assertion inside this call back function for the end method call so we to do expect and then we have this res argument which is the response so res. status code to be 200 and if I run the test again the test actually will still be considered passing let me remove this expect as well okay you can see that the test actually is still considered passing right over here even though it actually is supposed to fail now to fix this instead of having to do uh do end like right over here I’m going to go ahead and remove that and so instead of that we’re going to go ahead and actually await this doget call because this actually returns a promise if you look at the end over here you can use then or catch like that so I’m going to add the ASN keyword in front of the call function for the it function or test and I’m going to go ahead and do const res equals await so this is the response object right over here you can see that the return value the resolved value is a response let me name it response okay and now what I can do is I can write an assertion on the response the status code and I’ll say response. status let go 2 B 200 so this should fail because the end point actually returns a 2011 and now the test actually fails so this is exactly what we want of course if you wanted to write an assertion on the response body there is this body property on the response object and then you can use assertions such as to b or to equal or to strict equal or to contain whichever mat you feel like you need so for example I can do Tob an empty object and let’s see what happens uh let me first fix this back to 200 and of course you can see the test fails because we’re not returning a response body so let’s fix that let me go ahead and set the status to 200 and also send some Json and empty response body and let’s run the test again and let’s see uh I think let’s do two equal since it’s an object okay there we go now it passes okay it does suggest to use two strict equal as well right up top over here that’s why it was erroring out okay and if I tried to pass in the wrong object like this let’s run the test and you can see that the assertion fails so hopefully this makes sense now I just want to show you this quick example we’re now going to go ahead and actually set up our end to end tests for our application so this will actually require us to grab our app instance right over here because what we need to do is similar to um what we’re doing in here we need to pass that app instance into the request function as an argument as you can see over here okay so inside our application right over here inside index. MJS this is where we actually have our Express app created and we have all of our middleware set up so the thing is though we need to make sure that we can export our app and import it into our test files our endtoend test files so that way all of the routes and all of the uh middlewares and anything else is actually going to be registered the other issue is that because in our file we’re not only just registering middleware but you can see right over here I am trying to also invoke the database as well so there are actually a few things that we need to do just to get this to work and so the good thing is it’s not going to be a big deal to do this so what I’ll do is I’ll create a new file and I’ll call this uh let’s see create app. MJS and all I’m going to do is just export this function create app like that and I’m just going to literally take let’s see I’m going to take all this stuff right over here and I’m going to paste that in here and then what I’m going to do is this I’m going to go ahead and pass an instance of app like that so then I can reference app right over here and I also need to make sure I’m registering all of my middleware which I am and I also need to import all of the middleware as well all the Imports right over here as well as right here okay and um let me see uh Additionally you know what actually I’m going to create the app inside the function instead and let me import Express up over here so let me delete all of these Imports in the index files because we won’t need them anymore okay so what I can do now is I can call create app and I want to actually return the app instance so when I call create app it’ll run through all of these it it’ll call all of these functions it’s going to register all of the middlewares right over here all of the routes and it’s going to uh return app so once all of the middlewares and all the rout or registered it’s going to return this app instance to wherever we called it so now what I can do is inside the index. MJS file I can go ahead and first let me import create app like that and then I’m going to go ahead and do const app equals create app and we don’t have any asynchronous a logic going on here so that’s good so we can just call create app and now the next thing is is we need to also make it so that when we run our end to end tests or integration tests that we’re also able to connect to the database as well so this alone is just fine for our development application like if I were to just run my code right now for just development everything would still work the same way you can see that still going to uh reference the app and then call app. listen to actually start up the server is not defined I think oh I think let me see where where was that over here um did I reference that in here oh yeah let me import Mongoose in here as well inside the create app MJS method because we do reference it down over here forgot about that and then cannot in a client please provide correct options okay so the other problem here is that it does require the connection so what I can do is I can move the connection top over here and now it works okay so it’s just an it’s just a matter of ordering things so first I’m connecting to the mongodb database I’m calling mango. connect then I am initializing the app because the application does require the connection to exist first so now what I can do is let me remove uh this app.get let me remove all of this for now and instead of just calling Express I’m going to remove that let me remove this import of Express I’m going to go ahead and import the create app like this okay so now we actually have our Express app in this variable like our actual app not the fake one that we just created just now but we still need a connection to the database and that’s okay because what I can do is I can actually just copy all this stuff over here and I can just paste it right in here and I can just import mongus from mongus and I can change the database that it is connecting to so I can change it from Express tutorial to express tutorial test like that and I can say connected to test database and now let’s go ahead and try to test a very simple endpoint so I have let’s see do I have any simple end points that I can set up um let’s do this one let’s do the API off/ status endpoint let me remove all these logs so what this should do is we’re going to write an assertion to return a 401 because we’re not authenticated currently so inside our test file let’s go ahead and do describe API off and then what I’ll do is say it should return 401 when not logged in and let me add the Asing keyword in front of the call function for our test and I’m going to do const response equals await so I’m going to call the request function that’s super test right over here we going to pass in our app and then we need to go ahead and call get and then go ahead and pass in the URL that we want to visit so/ API SL status just like that and then now I can write an assertion on the response do status code to be 401 so let’s actually run our test and see what happens so npm run test or I’m sorry npm run test e2e okay and you can see uh let’s see right over here you can see that it is logging in the console right over here it says connected to test database and our tests are passing so that’s good so it is actually calling the endpoint um and it passes because we are expecting the status code of 401 which it is actually giving it to us and of course we get this issue where um the test did not exit after the test completed so I think it’s likely because of our database connection right over here mongus doc connect let me actually do this I’m going to copy this and I’m going to go inside the describe block and then right before the test I’m going to go ahead and use this before all function this is a life cycle hook so basically this function takes on callback function and before all of your tests that’s why it’s called before all it will run whatever is inside this logic over here you can see before all of our test it’s going to connect to the database so there’s before all there’s also before each before each will run before every test and we don’t want that because we only want to connect to the database one time and then let me just make sure this still works as expected uh let’s see um okay so I think the problem is oh wait whoops let me do this uh it does require a little bit of tinkering but what I need to do is because we’re trying to create the app first before the database connection so let me actually do this let me declare variable up here called app like that using the let keyword and I’m going to reassign uh the value of what whatever create app returns to app and so that way I can reference it inside here okay there’s a bunch of different ways you can set this up so this is not only one way this is not the only way to do it there are different ways of how you can configure this but this should work okay perfect and now to fix this part we’re going to go at the end of our test I’m going to go ahead and use this after all hook okay so it’s pretty much the opposite of before all so after all your tests what we want to do and this is the part where I mentioned earlier or maybe in the previous section of this tutorial where you want to actually drop the database as well as close the connection to the database so you can do that by referencing doc connection drop database um and then you can see it says helper for drop database deletes the given database including all collections documents and indexes so that will drop the database that we are connected to which is the test database and this returns a promise so we will need to await that so let’s add the Asing keyword and await this and after we drop the database let’s go ahead and close the connection yeah I think it’s yep drop not drop sorry close and then this will close the connection right over here and then this should fix that uh warning that we have over here okay there you go you see how now the tests actually gracefully exit and this is important because if you have your end to endend test or really any test running in a pipeline it’s going to block your pipeline from proceeding to the next job so it’s very important that you resolve these situations okay but we have a pretty good setup right now so let’s go ahead and actually continue so what I’m going to do is I’m going to go ahead and write an end to end test I’m going to I’m going to write a scenario okay so what I’m going to do is I’m going to go ahead and create a user first verify that the user is created and then we’re going to try to log in and then verify that we’re logged in I know it’s a lot but don’t worry we’ll take it step by step ideally you always want to make sure you are separating your tests you don’t want to like have them all together so what I can do is I will go ahead and create a new file I’ll call this user dope. JS or really whatever ever it is that you want to describe it as and we can just literally copy this whole thing and paste it here so I’ll just call this uh create user and login and just have the same exact setup like this um let’s see yep everything else is good and then let’s just delete that because we’re our test is going to be different okay so the first thing that I want to do is I want to actually create the user so let me go ahead and do this it should create the user and keep in mind that we’re not going to be testing everything in one single test block we’re going to be doing everything in sequential order so first thing is we’re going to test that the user is created so it should create the user and we’re going to go ahead and make a request so let’s call the request function pass in our app instance and then we’re going to go ahead and call a post request this time and the endpoint is going to be/ API SLO SL user and let me just verify that route right over here yep router. poost API users or I’m sorry it’s I don’t know why off it’s API users with an S and then it’s going to go ahead and call this middle word function this is the express validator so this is where we can actually also make sure that the validation is working working as well uh we have create user Handler is called which is our request Handler and it’s going to basically run through all this logic so again in the previous section of this tutorial where we went over unit testing I showed you how to unit test this whole function this time we don’t have to worry about mocking anything it’s going to call this function and it’s going to run the actual logic it’s going to call the actual functions from Express validator it’s going to call our own hash password function it’s going to create the user and going to actually save it to the database using okay so let’s go ahead and go back to our test file oops sorry about that all right so we’re going to make a post request and let’s go ahead and send a request body so uh to send the request body you can use this send method like that whoops not sure why that is send yep and then you can pass in an object so so we need to send the username so for the username I’ll do Adam 123 password let’s do password and then display name just do Adam the developer okay so when we send this request it’s going to handle it on the server side we don’t obviously care about what’s going on on the server side with this because we’re trying to just care about what the response is okay so what I’m going to do is after this whole thing is done we also want to await this call because remember this do send method also returns a promise as well so let’s await that and now let’s write an assertion let’s do response. status code to be 2011 okay so let’s run our test so let’s do npm run test e2e so this should run all of our tests for us and you can see both tests pass and you can see in the cont conso that that’s I think that’s the salt from the hash password function that’s being logged if I am correct yep it’s the salt let me remove this console log but you can see that both tests are passing so that’s good and you can see that they don’t conflict with each other and one more thing that I also want to show you is if I open up my mongodb compass tool okay and if I were to actually let me see not this one but it shouldn’t be connecting yeah it should not connect to this Express tutorial database it should connect to the test database so you know what let me remove this line over here and show you what happens when I run the test okay so now watch this if I refresh the page or refresh this application uh what is this new version available let me click X you can see that now this Express tutorial test comes up and you can see that our collection our users collection is inside the express tutorial test database and so is our sessions okay so hopefully this makes sense but the reason why we didn’t see it before is because we dropped the database and the reason why we dropped the database is because we don’t want the test data from previous test Suites to conflict with other tests okay I’ll explain more about that later on because right now you might wonder okay well we do need the data with this user in the next test but yes that’s within the same test Suite in other test sues like in other scenarios you don’t want to have leftover data in the database conflicting with that scenario because you might have a scenario where you’re only expecting one user but there might be three users because you didn’t clear the database okay all of those tests that you ran kept creating a new user and because you didn’t drop the database the users kept adding on into the database collection and your assertions are going to fail so let’s go ahead and continue Contin so after we create the user let’s actually log in so what we’ll do is this I’m going to first manually drop my database let me just do that because it will error out if it creates a duplicate okay so we dropped the database good let’s go ahead and go back to our code so now we’ll do this it should log the user in and we’re going to make a request a post request this time to SL API SLO yep I think it’s just slpi SLO and then we’re going to send our whoops I don’t know why it keeps doing set encoding send username so the same username that we configured up top over here so Adam 123 and then the same password and then let’s go ahead and get the response in a variable okay so let’s just go back to our off I think I put that right over here yep so it should send back a status of 200 on success okay uh I think with passport let me just double check everything yep I think everything here is good so let’s continue so expect response status code to be 200 now let’s go ahead and run our test make sure that it passes okay so now it says uh let’s see now it failed and let’s see what’s going on over here it says received 500 so it seems like the backend uh there might be something wrong with the back end for it to send back a 500 so I’ll actually just console log the response body and see what that message says because it sent back a status code of 500 so that’s obviously not good let’s see okay so it says um maybe not response. body but maybe let’s just do response okay so it says right over here that unknown authentication strategy okay so I know what the problem is the problem is that it doesn’t recognize our local strategy and I think it’s likely because of the way that we moved everything into here so I’m trying to think what would be the easiest way to do this because if I were to actually remove this create app and then move everything back into the index file I would need to export the app and that would require me to import the index file which would also call this mongus doc connect code and I don’t want that to happen so the only other option is I would have to essentially move this to a separate file and then it would also call this app I listen which I don’t want so we don’t want to import this index file at all so I think the other thing that I might need to do is I might need to import this strategy into the create app probably maybe like right over here and I think maybe that might fix that so let’s try to run the test again and see if that same issue occurs okay so you can see that the error goes away now so it it seemed like this import did fix that I guess because we had it over here uh was what was causing the problem let me move this as well over over to here okay um I guess it has to be inside the scope since I guess this is where we are creating the app and we are initializing passport here so maybe that’s the reason why I’m not too sure but at least we fixed that part so now we can go back over here and let me remove this console log and let me just rerun the test we know that it’s passing though okay and you can even see in the console log from the actual source code right over here it is logging the user over here and if we go to where is the local strategy right here yep you can see that it should be logged I think yeah it’s being logged right over here inside the serialized user function and it says inside serialized user and it logs the user itself and then after successful authentication the endpoint right over here sends back a status code of 200 okay so we verified that we were able to successfully log in now additionally what you can do is you can write some more assertions on the response object they have this property called I think it’s headers yep headers and what you can do is you can check to see if the headers actually has the cookie that you expect because this response that headers object is actually just an object that has the cookies property so let me show you real quick what that looks like right over here yep you can see that we have this set cookie property which seems to be an array so I guess what you could do is you can look to see if the array contains this uh cookie name right over here so that’s one thing that you could do but I’ll let you all take care of that so now inside this second test we are trying to log the user in so now once we’ve logged the user in then we should have a session and we should be able to visit the o/ status endpoint and get a response back with our user record cuz that’s who we are logged in as so let’s go ahead and try that out so I’ll sa for the test it’s should visit API status and return logged in user let me just call this authenticate authenticated user and I want to show you what happens when we try to do this so we’re going to make a get request this time to / API o status and we’re going to assert that the status code returned is 200 and let’s see if this passes and you’ll notice now that it actually fails okay it gives gives us back a 41 and so I think the reason why this happens I don’t know the exact reason but I will tell you what I think because I ran into this issue myself so when we run our test they are running in order okay they are running this one first this one first and this one first but when we run this test right over here it doesn’t actually uh persist the cookies for the next request so for example we do receive cookies inside this inside this API call right over here okay we do have cookies inside this second test and those cookies are being sent from the server however in this third test when I when we try to make a get request to this protected endpoint we need to obviously send the cookies but in the context right over here we don’t have the cookies sent so I think because of that reason uh it is giving us back that 401 because it’s treating us as if we never logged in so the way around this is to actually implement this logic inside just one test so I’ll go into this second test over here and I’ll say for the for the title should log the user in and visit API status and return off user okay and so what we’ll do is after we call this send method I can actually use the then method and then I’ll get the response of the post request because remember I’m using the then method to resolve the promise for this request. post method and then that would resolve the value of whatever that post was going to return okay whatever the promise was going to resolve so inside this then I’m going to pass in a callback function which gives me access to that response for that post request to the API off endpoint so inside here what I can do is I can actually return request. apppp so I can make another request right after this post request is finished and I can make a get request and I’m going to paste that URL over here and then what I can do is I can also set the cookies so I can use this set function and then I want to set the cookie and then we need to just pass in this array of cookies which we can easily grab if we reference res. headers and I think the property was called set hyphen cookie I think or set cookies let me actually just double check real quick let me do this let me console lock this okay but then what will happen is we send the cookies along with this request and so this response so after we await this whole thing this response up top over here is the response respon for the actual get request okay so then right over here we can write assertions on the status code on the response body so let me go ahead and remove this third test because we won’t need that anymore and let me go ahead and run the test again and let’s see invalid value and defined um let’s see headers it may have been set cookie instead of set cookies maybe that’s why it’s giving us back undefined yep it’s set cookie okay yep that’s fine so let’s go ahead and change this to set cookie so this will pass all the cookies send it to the server and let’s go ahead and run the test again and now you can see that our tests pass and specifically this second test pass with all of our API calls and you can even see on the server side it goes through the serialized user function and then it goes through the Der serialize user function so this is invoked whenever we make a next request after we first log in okay so everything is working as expected and if I want I can write some more assertions on the response body so I can do response. body. username to be atom 123 for the display name let’s do that as well to be adam. developer and let’s run our tests and see what happens and you can see all of our tests pass so I hope that this shows you how to write integration tests as well as endtoend tests I hope that you better understand how to do it and how to set it up in a way that makes it effective and and this will be the last tutorial for the entire expressjs series I’m still going to make more expressjs tutorials it’s just not going to be part of this specific uh long series that I designed so I hope that you all enjoyed watching this series if you watch the whole entire thing like I said before the code will be on GitHub I’m going to leave a link in the description as well so you all can access it you’re more than welcome to ask questions Down Below in the comment section I check my comments every single day and I spond whenever I get a chance to if you need additional help visit the Discord server the link is in the description as well you can go onto the Discord server and get help with your programming issues uh talk to other developers um just you know just just hang out and whatever so yeah like I said I hope you all enjoyed this whole Express Chas tutorial and that is going to be it for this one so I will see you all in my next episode peace out

By Amjad Izhar
Contact: amjad.izhar@gmail.com
https://amjadizhar.blog
Affiliate Disclosure: This blog may contain affiliate links, which means I may earn a small commission if you click on the link and make a purchase. This comes at no additional cost to you. I only recommend products or services that I believe will add value to my readers. Your support helps keep this blog running and allows me to continue providing you with quality content. Thank you for your support!








