- Our registries are built in React on the front-end, but I'm hoping this tutorial gives me more insight into NodeJS as a whole, so that I have a greater understanding of how our code works
- This has also given me insight into how other frameworks we plan to use, namely Django, work as well
- Also provides more hands-on experience working with routing and middleware for web servers
- Code repo for reference is on GitHub with videos on The Net Ninja YouTube channel
- What is Node.js Actually?
- A platform which allows us to run JS on a computer/server
- This means that to run a JS app on a server, there is no longer a need for an additional server-side language like PHP, everything can be done in JS
- Node.js allows us to read, delete, and update files, in addition to being able to easily communicate with databases, among other things
- A platform which allows us to run JS on a computer/server
- Pros of Node.js:
- Uses JS
- Very fast (runs on the V8 engine & uses non-blocking code)
- Huge ecosystem of open-source packages (npm)
- Great for real-time services (like chats)
- Set up dev environment (new Atom package for in IDE terminal)
- Computers do not inherently understand JS code
- A JS engine is needed to compile source code to machine-readable code, and for that code to then be executed
- levels of abstraction: JS > C++ > Assembly Language > Machine Code
- Node JS is written in C++ because it uses the V8 JS engine developed by Google in C++
- The V8 engine is the heart of Node.js, and it is what converts JS into machine code
- For more on V8, check out their website
- V8 can be run standalone, or be embedded into any C++ application
- So Node.js is a C++ application in which V8 is embedded to convert JS code to machine code
- JS was always intended to run in the browser, and not to deal with lower-level operations like what C++ is suited for
- So the C++ code of Node.js hooks into the V8 engine and extends to JS some additional functionality, like being able to read a write files or connect to databases
- JS was always intended to run in the browser, and not to deal with lower-level operations like what C++ is suited for
- The global object is one which is available globally i.e. in any module of JS
- The global object when we write JS in the browser is the
window
object, defining the global scope, on which we can access properties and methods likealert()
- In Node.js, the global object is no longer the
window
, but is an object calledglobal
, and it is the global namespace object, defining the highest-level scope- an example is
console
, which can be used in the global namespace without having to first be required or imported
- an example is
- Looking under the hood a bit at functions and function expressions, where anonymous functions are assigned to variables
- Recall, we can also nest our functions
- Modules are logical blocks of code that provide some separation and reusability in our applications
require()
is a globally accessible function- modules, or specific functions and properties within a module, must be explicitly exported in order to access them outside of
- Often times we want to export and import (require) more than just a single function as a part of a module
- the
events
module is a built-in Node.js module - the event emitter allows us to generate custom events and then handle them accordingly
- the same way there are
click
orkeyup
events emitted due to certain keyboard and mouse actions, we can define and emit our own custom events
- the same way there are
- As an aside, "JavaScript is an object-based language based on prototypes, rather than being class-based" (MDN Documentation)
- "A prototype-based language, such as JavaScript, does not make this distinction [between classes and instances]: it simply has objects. A prototype-based language has the notion of a prototypical object, an object used as a template from which to get the initial properties for a new object. Any object can specify its own properties, either when you create it or at run time. In addition, any object can be associated as the prototype for another object, allowing the second object to share the first object's properties." (MDN Documentation)
- This is why object constructors exist
- "JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript." (MDN Documentation)
- Think about the "classes" we see in React, and how they can be generated without the ES6 syntax
fs.readFileSync()
provides us with a synchronous method for reading files (fs.readFile()
is the async version)- using this generates "blocking code" i.e. code after it will not be executed until the file is read
- Similarly,
fs.writeFileSync()
provides us with a synchronous method for writing files (fs.writeFile()
is the async version) - Use
fs.unlink()
to delete files
- There are both synchronous and asynchronous methods for creating directories (
fs.mkdirSync()
andfs.mkdir()
) and deleting directories (fs.rmdirSync()
andfs.rmdir()
)
- In most cases, our client will be our browser, which makes requests of a server, which will in turn return a response to the client
- This will happen after a protocol (rules for communication) is agreed upon for structuring the data sent between the client and server (HTTPS or FTP for example)
- The different protocols are for different types of data (HTTP/S vs FTP) or level of security in transmitting that data (HTTPS vs HTTP)
- Each client and server is identifiable buy their unique IP addresses, and the connection between then is created via a socket
- TCP is the protocol for the sending of data down the socket, while a protocol like HTTP defines the structure of the data to be transmitted (HTTP is at the application level, TCP at the transport layer according to Quora)
- Data is transmitted across the socket in packets
- Node.js gives us the ability to open a connection between two computers, and send information between them
- A program running on a computer can listen for requests sent to a particular port number
- Need to know what port Node.js is listening on in order to send it requests it can respond to
- The
http
module is a core module shipped with Node.js that allows you to create a server - Both requests from and client and responses from a server come with data and headers (metadata about the request or response)
- There are two types of reponse headers:
- Content-Type: clients (usually browsers) handle different types of data differently (JSON vs HTML)
- Status: indicating the level of success or failure of a request
- Analogy: There is a large crystal candy mountain you want to take home to feed your family, but it's too big to move all at once, and it would take forever to do so. Instead, you set up a conveyor belt between the mountain and you house. You then chip away at it until you have a box full, and send that box on the conveyor belt to your house. This way, you family can start eating ASAP and you eventually transport all of the candy home.
- A buffer (box in analogy) is a temporary storage spot for a chunk of data that is being transferred from one place to another
- the buffer is filled with data, then passed along
- transfer of small chunks of data at a time
- A stream is the flow of/ pathway for data, from the large conglomerate to the buffers to the final destination
- Think about streaming and buffering for watching videos online, you can begin consuming content before all data is transferred
- In Node.js we can create streams to transfer data (read and write files for example), and improve the performance of our applications
- Types of streams in Node.js:
- Writable stream: allow Node.js to write data to a stream
- Readable stream: allow Node.js to read data from a stream
- Duplex stream: can read and write to and from a stream
- Typically, we want to be able to write data to a stream so that it can be sent back to the client (browser) efficiently
- Using streams over reading and writing data in-full provides improved performance, and allows you to make use of parts of the data more immediately
- Because reading and writing streams of data is such a common practice, Node.js provides up with pipes to direct read stream outputs to write streams as inputs
- Don't need to manually listen on a read stream or write to a write stream
- Rather than serving plain text, we may want to instead serve HTML pages
- JSON data must first be serialized to either a string or buffer stream before being served (more on data serialization here)
- You may wish to return JSON data for a front-end JS script to make use of
- This makes the server, at a very low level, an API endpoint
- you could handle routing s.t. different URL paths return different JSON data
- Want to be able to specify specific URLs to gain access to different resources (webpages, JSON data, etc.) that our server can provide, while using the same IP address and port
- To do this, we can make use of the
req.url
, the attribute of the request object (calledreq
) that contains the URL the requested by the client - Note: without a default route, your client will be left hanging with no response, so it is best to have a default
404
page option
npm
comes installed with Node.js, and is a collection of command line tools for installing and managing third-party packages (modules)npm
can also be used to publish your own packages- doesn't seem to work without
package.json
- The
package.json
is for keeping track of all installed packages and dependencies for your project - You can either create it manually, or use the Node.js command
npm init
and fill-in the requested information - Typically you only share source code, and not dependent modules, with other developers
- So to run you application they must know what packages and versions you have installed, and install and update their own packages accordingly
- Prior to version 5.0.0., you had to include the
-save
flag to indicate that the package should bee saved to thepackage.json
file- This is now done automatically
- Given a pre-existing
package.json
file, you need only runnpm install
to install all of the dependencies listed in that file
- From
npm
:nodemon
is a tool that helps develop node.js based applications by automatically restarting the node application when file changes in the directory are detected.nodemon
wraps your application, so you can pass all the arguments you would normally pass to your app
- This way, if you have a server running and a browser open to see served resources, any changes to application files are reflected in the browser when you hit refresh
- Install locally using the command
npm install nodemon
- To run, you need to use
npx
(more on that here)- This is because: With a local installation,
nodemon
will not be available in your system path. Instead, the local installation ofnodemon
can be run by calling it from within annpm
script (such asnpm start
) or usingnpx nodemon
. (fromnpm
documentation onnodemon
)
- This is because: With a local installation,
- Now, to run your application use
npx nodemon app.js
or whatever the main script is according to yourpackage.json
file
Express
is a routing and middleware web framework that has minimal functionality of its own: AnExpress
application is essentially a series of middleware function calls. (docs)Express
is a popular framework because:- It provides an easy and flexible routing system
- It integrates with many templating engines
- It contains a middleware framework
- Routing refers to determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on) (from Express docs)
- In
Express
, the route definition has the structureapp.METHOD(PATH, HANDLER)
where:app
is an instance of expressMETHOD
is an HTTP request method, in lowercasePATH
is a path on the serverHANDLER
is the function executed when the route is matched
- In
- Middleware functions 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 middleware function is commonly denoted by a variable namednext
. (docs) - Middleware functions can perform the following tasks:
- Execute any code
- Make changes to the request and the response objects
- End the request-response cycle
- Call the next middleware function in the stack
- If the current middleware function does not end the request-response cycle, it must call
next()
to pass control to the next middleware function. Otherwise, the request will be left hanging.
Express
can handle both static (ex./contact
) and dynamic (ex./
) requests with the use of route parameters
- A template engine (also called a view engine) enables you to use static template files in your application. (docs)
- At runtime, the template engine replaces variables in a template file with actual values, and transforms the template into an HTML file sent to the client.
- This approach makes it easier to design an HTML page.
- For this project, we will be making use of the EJS template engine
- In addition to adding in dynamic data, you can also put JS control structures, like for loops, in view templates
- Partial views (templates) allow you to extract the elements common to many templates into their own file, and then include it in multiple templates
- for example, the navigation bar and footer available on every page of your application
- For static files in you application (ex. CSS files), you need to handle requests for these files just as you would any other (otherwise client will get 404 error because the resource cannot be found)
- Middleware (in server-side web application frameworks) can be thought of more broadly of any code that runs between the request and the response (see above for details related to
Express
)- Note: this is just one type of middleware
Express
provides us with a lot of in-built middleware, including middleware for handling requests for our static resources
- On the World Wide Web, a query string is a part of a uniform resource locator (URL) that assigns values to specified parameters (Wikipedia)
- the parameters and values often make up a kind of key-value pair
- ex. in
mysite.com/blog/new?page=2
, the website and path aremysite.com/blog/new
onto which we add a?
to denote the beginning of our query, and the the key-value pairpage=2
- If there is more than one condition, they are separated by an
&
- Given a query string, you must be able to parse the request and pull out the data it contains
- The
POST
method is used to submit an entity to the specified resource (in our case our server), often causing a change in state or side effects on the server.([MDB web docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods- often used for submitting forms
- As
Express
doesn't have built-in form handling, you need to install some middleware packages for that (this tutorial usesbody-parser
)