Creating a Web server
http
module
- Gives us networking capability -> such as building a http server.
1const http = require("http");
http
requires a cb fn which gets fired off whenever a new request comesCB gets access to 2 very imp variables (req and res)
Create a server
start the server -> by listening on incoming reqs
Create a server:
1http.createServer(
2 //whenever a new req comes to server, this callback is called
3 (req, res) => {
4 res.end("Hello from the server!"); // the response we send back
5 }
6);
listening on incoming reqs :
store result of server in a new variable to listen on incoming requests.
Args: PORT(sub address on a certain host), HOST-ADDRESS(where to go next (by default it is localhost)), CALLBACK(Optional)
CB runs right after server is started
1const server = http.createServer((req, res) => {
2 res.end("Hello from the server!");
3});
4//listen to incoming requests from client
5server.listen(8000, "127.0.0.1", () => {
6 console.log("listening to reqs on port: 8000");
7});
8//enter 127.0.0.1 :8000 in browser
Note : Node cannot simply exit the process this time -> coz of event loop . It keeps on listening to incoming request on given port.
Routing
Routing: Implementing different actions for different URLS
Routing in
http
becomes complicated as the application grows, so useexpress
then.First Step : Analyze the URL. Lets use
url
module for that
1const url = require("url");
- url module parses urls like
/overview/id=23&abc=4d
into a nicely formatted object.
1const server = http.createServer((req, res) => {
2 console.log(req.url); // we get 2 reqs by default (`/ ` & `/favicon.ico`) -> cb is executed twice
3 res.end("Hello from the server");
4 }
5});
Routing…
res.writeHead()
: Sends a response header to the request.- Args: statusCode (3 didgit HTTP code like
404
), status-msg(optional, for human readabilty), headers(response headers -> [info about response we are sending back])- Note : We can also specify custom header
- This method must only be called once on a message and it must be called before
response.end()
is called. - Returns a reference to the ServerResponse, so that calls can be chained.
- Args: statusCode (3 didgit HTTP code like
1const server = http.createServer((req, res) => {
2 const pathName = req.url;
3 if (pathName === "/" || pathName === "/overview") {
4 res.end("This is overview page");
5 } else if (pathName === "/product") {
6 res.end("This is product page");
7 } else {
8 // throws a 404 error in browser console. You can also check in network tab
9 res.writeHead(404);
10 //there are many header types one of them is content-type
11 //note all these status codes and headers need to be sent before sending response
12 res.writeHead(404, {
13 "Content-type": "text/html", //browser now expects an html to come in
14 // our own made up header
15 "my-own-header": "hello-world",
16 });
17 res.end("Page not found!");
18 //what we can do now is embed a html in response
19 res.end("<h1>Page not found</h1>"); //output : response in <h1>
20 }
21});
Build a simple API
API : A service from which we can request data.
First Way:
- Read data from json file and parse data to JS
- Send result back to client
1if (pathName === "/api") {
2 //__dirname translates directory in which script that we're currently executing is located
3 fs.readFile(`${__dirname}/dev-data/data.json`, "utf-8", (err, data) => {
4 const productData = JSON.parse(data); //Turns JSON string to JS object
5 console.log(productData);
6 res.writeHead(200, { "Content-Type": "application/json" });
7 res.end(data);
8 });
9}
This is not 100% efficient, because each time a user hits /api
file have to be read and then sent back. Instead we can read the file once in the beginning and then each time someone hits this route, simply send back the data without having to read it each time that a user requested
- Efficient way:
- Use sync version of readFile (But sync version blocks code right?)
- In this case, its not a problem at all coz top level code gets executed only once in the beginning.
- The code outside callback(so called top-level code) gets executed only once.
- Use sync version of readFile (But sync version blocks code right?)
1//top-level code
2const data = fs.readFileSync(`${__dirname}/dev-data/data.json`, "utf-8");
3
4//inside callback
5if (pathName === "/api") {
6 res.writeHead(200, { "Content-Type": "application/json" });
7 res.end(data);
8}
Parse variables from URL
- lets say from this url : ‘https://localhost:8080/api&id=0’ we want to extract query string ie., ‘id=0’ and pathname = ‘/product’
1const url = require("url");
2//pass true here to actually parse the url
3const { query, pathname } = url.parse(req.url, true);
Create your own modules:
If you want to use a function or class in multiple files, Make it as a module. Export it from that file and import it in another.
Note: In Node every single file is a module.
One of the many ways…
Steps to create a module:
- Extract the piece of code which you want to make it as a module.
- Export it using
export.modules
- Import it in the file in which you want to use this module using
require
1//sum.js
2module.exports = (x, y) => {
3 return x + y;
4};
5//index.js
6const sum = require("./modules/sum");