Home Blog Page 9

Creating a Simple Web Application with Express.js

0
full stack development
full stack development

While Node.js provides the core functionality to create HTTP servers, Express.js is a minimalist and flexible web framework built on top of Node.js that makes it easier to build robust and scalable web applications. In this module, we’ll explore how to use Express.js to create a simple web application with routing, middleware, and dynamic content.


Table of Contents

  1. Introduction to Express.js
  2. Setting Up an Express.js Project
  3. Creating Routes in Express.js
  4. Using Middleware in Express.js
  5. Handling Form Data in Express.js
  6. Sending JSON Responses
  7. Dynamic Content with Templates (Using EJS)
  8. Error Handling in Express.js
  9. Conclusion

1. Introduction to Express.js

Express.js is one of the most popular web frameworks for Node.js. It simplifies the process of handling HTTP requests, managing routes, and rendering views. Express is lightweight, fast, and can be easily integrated with other Node.js libraries and tools.

To use Express, you must first install it in your project using npm:

bashCopyEditnpm install express

2. Setting Up an Express.js Project

Start by creating a basic Express app. First, create a new directory for your project, then initialize a Node.js project:

mkdir express-app
cd express-app
npm init -y

Next, install Express:

npm install express

Now, create an app.js file and add the following code to create your first Express server:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
res.send('Hello from Express!');
});

app.listen(port, () => {
console.log(`Server running at http://localhost:${port}`);
});

To start the server, run:

node app.js

Visit http://localhost:3000 in your browser to see the response.


3. Creating Routes in Express.js

Routes define how your application handles incoming requests to different endpoints. In Express, you can create routes for different HTTP methods like GET, POST, PUT, and DELETE.

app.get('/about', (req, res) => {
res.send('This is the About page');
});

app.post('/submit', (req, res) => {
res.send('Form submitted');
});

You can also capture URL parameters using :parameter_name:

app.get('/user/:id', (req, res) => {
const userId = req.params.id;
res.send(`User ID: ${userId}`);
});

4. Using Middleware in Express.js

Middleware functions are functions that have access to the request (req), response (res), and the next middleware function in the application’s request-response cycle. Express.js provides built-in middleware for tasks like logging, parsing request bodies, and handling errors.

// Built-in middleware to serve static files
app.use(express.static('public'));

// Custom middleware to log request details
app.use((req, res, next) => {
console.log(`Request made to: ${req.url}`);
next();
});

5. Handling Form Data in Express.js

Express makes it easy to handle form submissions. You can use express.urlencoded() to parse data sent from HTML forms with application/x-www-form-urlencoded encoding.

app.use(express.urlencoded({ extended: true }));

app.post('/submit', (req, res) => {
const { name, age } = req.body;
res.send(`Received name: ${name}, age: ${age}`);
});

This setup allows your application to handle form submissions easily.


6. Sending JSON Responses

One of the common tasks in API development is sending JSON responses. Express makes this simple with the res.json() method:

app.get('/data', (req, res) => {
const responseData = { message: 'This is some data', status: 'success' };
res.json(responseData);
});

This sends the data as a JSON object, making it suitable for API responses.


7. Dynamic Content with Templates (Using EJS)

For dynamic HTML content, you can use template engines like EJS, Pug, or Handlebars. In this example, we’ll use EJS.

Install EJS:

npm install ejs

Set up Express to use EJS as the template engine:

app.set('view engine', 'ejs');
app.set('views', './views'); // Path for views

Now, create an index.ejs file inside the views folder:

<!DOCTYPE html>
<html>
<head>
<title>Dynamic Content</title>
</head>
<body>
<h1>Hello, <%= name %>!</h1>
</body>
</html>

Then, render the EJS template in your route:

app.get('/greet/:name', (req, res) => {
res.render('index', { name: req.params.name });
});

Now, visiting http://localhost:3000/greet/John will render Hello, John!.


8. Error Handling in Express.js

Error handling is essential for a robust web application. Express allows you to define custom error-handling middleware.

app.use((req, res, next) => {
const err = new Error('Page not found');
err.status = 404;
next(err);
});

app.use((err, req, res, next) => {
res.status(err.status || 500);
res.json({ message: err.message });
});

This handles any errors that occur in the application and sends an appropriate response to the client.


9. Conclusion

Express.js simplifies building web applications by providing a set of powerful features, including routing, middleware, and support for templates. With Express, you can easily manage HTTP requests, handle form submissions, send JSON responses, and much more.

By mastering Express, you’re on your way to building robust web applications that scale. Stay tuned for the next module:
“Connecting a Node.js Application to a Database (Using MongoDB)”

Building a Simple HTTP Server with the Node.js http Module

0
full stack development
full stack development

One of the fundamental tasks of web development is creating HTTP servers. In Node.js, the built-in http module allows you to easily create a web server that listens for incoming requests and responds to them. In this module, we will explore how to build a simple HTTP server in Node.js, understanding its core components and the basic flow of an HTTP request/response cycle.


Table of Contents

  1. Introduction to the http Module
  2. Creating a Simple HTTP Server
  3. Handling Different HTTP Methods
  4. Parsing URL and Query Parameters
  5. Setting HTTP Headers
  6. Sending Responses
  7. Handling Errors
  8. Real-World Use Cases
  9. Conclusion

1. Introduction to the http Module

The http module in Node.js provides the functionality to create HTTP servers and clients. It allows Node.js applications to interact with HTTP requests and send HTTP responses. The http module is built-in and requires no installation.

To use it, simply require it in your code:

const http = require('http');

2. Creating a Simple HTTP Server

The basic structure of a Node.js HTTP server involves using http.createServer() to define how to handle incoming requests. The server listens for requests on a specified port.

const http = require('http');

const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello, World!\n');
});

server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});

When you run this, the server listens on port 3000 and responds with “Hello, World!” when accessed via a web browser or API client.


3. Handling Different HTTP Methods

An HTTP request can be of various methods, such as GET, POST, PUT, DELETE, etc. You can handle these methods differently based on the type of request.

const server = http.createServer((req, res) => {
if (req.method === 'GET') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('GET request received\n');
} else if (req.method === 'POST') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('POST request received\n');
}
});

server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});

This example differentiates the response based on the HTTP method used in the request.


4. Parsing URL and Query Parameters

You can parse the URL and query parameters in the incoming request using req.url and the url module.

const url = require('url');

const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const name = parsedUrl.query.name || 'Guest';

res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(`Hello, ${name}!\n`);
});

server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});

If you visit http://localhost:3000/?name=Alice, the server will respond with Hello, Alice!.


5. Setting HTTP Headers

HTTP headers provide additional information about the request or response. You can set headers using the setHeader() method.

const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Cache-Control', 'no-store');
res.end('Response with headers\n');
});

server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});

Here, the Cache-Control header is used to prevent the caching of the response.


6. Sending Responses

The res.end() method is used to send the response body. You can send plain text, HTML, JSON, or any other content type.

const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
const responseData = { message: 'Hello, JSON!' };
res.end(JSON.stringify(responseData));
});

server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});

This sends a JSON response to the client.


7. Handling Errors

You should handle errors properly to avoid crashes and ensure the server runs smoothly.

const server = http.createServer((req, res) => {
try {
if (req.url === '/error') {
throw new Error('Something went wrong!');
}
res.statusCode = 200;
res.end('Everything is fine');
} catch (err) {
res.statusCode = 500;
res.end(`Error: ${err.message}`);
}
});

server.listen(3000, () => {
console.log('Server running at http://localhost:3000/');
});

This example demonstrates how to catch and handle errors gracefully.


8. Real-World Use Cases

  • APIs: Node.js HTTP servers are commonly used to build RESTful APIs.
  • Web Servers: A basic HTTP server serves as the foundation for building complex web applications.
  • Real-Time Applications: Use cases such as chat applications, live notifications, etc., rely on WebSockets, but the HTTP server still plays a vital role in initial communication.

9. Conclusion

Building an HTTP server in Node.js is simple yet powerful, giving you the flexibility to handle different HTTP methods, parse request URLs, and send dynamic responses. This serves as the foundation for creating APIs, websites, and real-time applications in Node.js.

Asynchronous Programming in Node.js – Callbacks, Promises & async/await

0
full stack development
full stack development

Node.js is built on asynchronous programming. This allows it to handle I/O-heavy operations efficiently, even with a single-threaded architecture. In this module, we’ll dive deep into the core asynchronous patterns in Node.js — Callbacks, Promises, and async/await — and how they work under the hood.


Table of Contents

  1. Why Asynchronous Programming?
  2. The Callback Pattern
  3. Problems with Callbacks (Callback Hell)
  4. Introducing Promises
  5. Chaining Promises
  6. Using async/await
  7. Error Handling in async/await
  8. Comparison Between Callbacks, Promises, and async/await
  9. Real-World Use Cases
  10. Conclusion

1. Why Asynchronous Programming?

In a blocking environment, long-running tasks like reading files or accessing databases halt execution until they complete. In contrast, asynchronous programming lets the program continue running while waiting for these tasks to finish.

This is why Node.js is ideal for real-time applications, streaming services, and APIs — it handles thousands of operations without getting blocked.


2. The Callback Pattern

A callback is a function passed as an argument that gets executed after an asynchronous operation completes.

const fs = require('fs');

fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) return console.error(err);
console.log(data);
});

3. Problems with Callbacks (Callback Hell)

While callbacks work, they can quickly become messy and hard to manage:

getUser(userId, (err, user) => {
getPosts(user.id, (err, posts) => {
getComments(posts[0].id, (err, comments) => {
console.log(comments);
});
});
});

This nested structure is often referred to as callback hell and is difficult to read, maintain, and debug.


4. Introducing Promises

A Promise represents a value that may be available now, in the future, or never.

const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('Data received!'), 1000);
});
};

fetchData()
.then(data => console.log(data))
.catch(err => console.error(err));

5. Chaining Promises

You can avoid nesting by chaining .then() calls:

getUser(userId)
.then(user => getPosts(user.id))
.then(posts => getComments(posts[0].id))
.then(comments => console.log(comments))
.catch(error => console.error(error));

6. Using async/await

async/await is syntactic sugar over Promises that makes asynchronous code look synchronous and cleaner:

async function showComments() {
try {
const user = await getUser(userId);
const posts = await getPosts(user.id);
const comments = await getComments(posts[0].id);
console.log(comments);
} catch (err) {
console.error(err);
}
}

7. Error Handling in async/await

Use try/catch blocks to handle errors with async/await:

async function fetchData() {
try {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
console.log(data);
} catch (err) {
console.error('Error fetching data:', err);
}
}

8. Comparison Between Callbacks, Promises, and async/await

FeatureCallbackPromiseasync/await
ReadabilityLow (nested structure)Better (chaining)Best (sequential flow)
Error HandlingManual per call.catch() methodtry/catch block
ReusabilityLimitedGoodGood
DebuggingHardEasierEasiest

9. Real-World Use Cases

  • API calls to fetch or update data.
  • Reading/writing to a file or database.
  • Timers (setTimeout, setInterval) and user input in CLI tools.
  • Handling events in an Express.js app.

10. Conclusion

Asynchronous programming is at the heart of Node.js. Whether you start with callbacks, move to promises, or settle with async/await, understanding these concepts is crucial for writing modern, scalable Node.js applications.

The Node.js Event Loop and EventEmitter Explained

0
full stack development
full stack development

Understanding the event loop and the EventEmitter class is essential to mastering asynchronous programming in Node.js. These two concepts form the backbone of Node.js’s non-blocking, event-driven architecture.

This module explains how the event loop works, what the EventEmitter class does, and how you can use them to write efficient, scalable applications.


Table of Contents

  1. What Is the Event Loop?
  2. How Node.js Handles Concurrency
  3. Phases of the Event Loop
  4. The Role of setTimeout, setImmediate, and process.nextTick
  5. What Is the EventEmitter Class?
  6. Creating and Listening to Events
  7. Using once(), off(), and removeListener()
  8. Real-World Use Cases
  9. Conclusion

1. What Is the Event Loop?

The event loop is a mechanism that handles asynchronous callbacks in Node.js. It allows Node.js to perform non-blocking I/O operations — despite being single-threaded — by offloading operations like file system access and network communication to the system kernel whenever possible.


2. How Node.js Handles Concurrency

Instead of using multiple threads, Node.js uses the event loop and callbacks to manage concurrency. Time-consuming operations are offloaded and their callbacks are pushed onto a queue once completed.

The event loop processes these callbacks one at a time, creating the illusion of multitasking in a single-threaded environment.


3. Phases of the Event Loop

The Node.js event loop has several distinct phases:

  1. Timers – Executes callbacks scheduled by setTimeout() and setInterval().
  2. Pending Callbacks – Executes I/O callbacks deferred to the next loop.
  3. Idle/Prepare – Internal use only.
  4. Poll – Retrieves new I/O events; executes their callbacks.
  5. Check – Executes setImmediate() callbacks.
  6. Close Callbacks – Executes callbacks for closed resources.

Each phase has a queue of callbacks to process before moving to the next phase.


4. The Role of setTimeout, setImmediate, and process.nextTick

Understanding the differences between these is key:

setTimeout(() => {
console.log('Timeout');
}, 0);

setImmediate(() => {
console.log('Immediate');
});

process.nextTick(() => {
console.log('Next Tick');
});

Output order:

Next Tick
Timeout
Immediate
  • process.nextTick() runs before the next event loop iteration.
  • setTimeout() executes in the “timers” phase.
  • setImmediate() executes in the “check” phase.

5. What Is the EventEmitter Class?

Node.js comes with the events module, which allows you to create and listen for custom events using the EventEmitter class.

const EventEmitter = require('events');
const emitter = new EventEmitter();

6. Creating and Listening to Events

You can register event listeners and emit events like this:

const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.on('greet', (name) => {
console.log(`Hello, ${name}!`);
});

emitter.emit('greet', 'Alice');

Output:

Hello, Alice!

7. Using once(), off(), and removeListener()

  • once() listens for a single occurrence: emitter.once('init', () => console.log('Initialized'));
  • off() or removeListener() removes an existing listener: const handler = () => console.log('Running...'); emitter.on('run', handler); emitter.off('run', handler);

8. Real-World Use Cases

  • HTTP servers use events like request and close.
  • Streams emit data, end, and error events.
  • Custom event-driven architectures in large applications.
  • Logging and analytics where you want to emit custom events across modules.

9. Conclusion

The event loop and EventEmitter enable Node.js to handle high-performance, asynchronous applications without blocking execution. By understanding how these features work, you can build scalable applications that handle I/O operations efficiently and react to custom or system events in real time.

Understanding Node.js Modules and require()

0
full stack development
full stack development

Modules are the building blocks of any Node.js application. They help you organize your code into reusable, maintainable, and encapsulated components. In this article, we’ll explore how the Node.js module system works, how to create your own modules, and how to use the require() function to import them.


Table of Contents

  1. What Are Modules in Node.js?
  2. Types of Modules in Node.js
  3. Using the require() Function
  4. Creating Custom Modules
  5. Exporting Multiple Values
  6. Caching Behavior of Modules
  7. The module and exports Objects
  8. ES Modules vs CommonJS
  9. Real-World Use Cases
  10. Conclusion

1. What Are Modules in Node.js?

In Node.js, every file is treated as a separate module. This means you can encapsulate functions, variables, and logic into files and reuse them elsewhere. The Node.js module system is based on CommonJS, which uses require() and module.exports to manage modules.


2. Types of Modules in Node.js

Node.js supports three types of modules:

  • Core Modules: Built-in modules like fs, http, path, etc.
  • Local Modules: Custom modules you create in your application.
  • Third-party Modules: External libraries installed via npm (e.g., express, lodash).

3. Using the require() Function

You use require() to import modules:

const fs = require('fs'); // core module
const math = require('./math'); // local module
const express = require('express'); // npm module

4. Creating Custom Modules

Let’s say you create a math.js file:

// math.js
function add(a, b) {
return a + b;
}

function subtract(a, b) {
return a - b;
}

module.exports = {
add,
subtract
};

Now you can import and use it in another file:

// app.js
const math = require('./math');

console.log(math.add(2, 3)); // Output: 5
console.log(math.subtract(7, 4)); // Output: 3

5. Exporting Multiple Values

You can export functions, objects, or variables individually:

// logger.js
exports.info = (msg) => console.log(`INFO: ${msg}`);
exports.warn = (msg) => console.log(`WARNING: ${msg}`);

Or as a single object:

// logger.js
const logger = {
info: (msg) => console.log(`INFO: ${msg}`),
warn: (msg) => console.log(`WARNING: ${msg}`)
};

module.exports = logger;

6. Caching Behavior of Modules

Node.js caches required modules, meaning it loads them only once:

const a = require('./moduleA');
const b = require('./moduleA');

console.log(a === b); // true — same object due to caching

To reload a module, you’d have to delete it from the cache manually (not recommended in most use cases).


7. The module and exports Objects

Every module in Node.js has a module object and an exports object. They work together like this:

console.log(module.exports === exports); // true initially

You can assign to module.exports to change what gets exported, or add properties to exports.

Avoid assigning directly to exports = ... because it breaks the reference.

8. ES Modules vs CommonJS

Modern Node.js supports ES modules using import/export. To use them:

  • Use .mjs file extension or set "type": "module" in package.json.

Example:

// add.mjs
export function add(a, b) {
return a + b;
}
// main.mjs
import { add } from './add.mjs';
console.log(add(1, 2)); // Output: 3

ES Modules are preferred in modern JavaScript projects, but CommonJS is still widely used.


9. Real-World Use Cases

  • Organizing utility functions into separate files
  • Grouping API routes into modular files in Express apps
  • Wrapping third-party libraries for internal use
  • Managing services like database connections, logging, etc.

10. Conclusion

Node.js modules help structure your application cleanly and effectively. Whether you’re using CommonJS with require() or moving toward ES Modules with import/export, mastering modules is essential for building scalable Node.js applications.