WE Notes Unit - III, IV Complete (R-18)
WE Notes Unit - III, IV Complete (R-18)
Q1. Build a REST API using Node.js and Consume it in react with CRUD
Operations
A.) A REST (Representational State Transfer) API is an architectural style for designing networked applications. It relies on
a stateless, client-server, cacheable communications protocol, typically HTTP. REST APIs allow different systems to
communicate with each other over the internet in a standardized way. Here’s an overview of what a REST API is and how it
works:
2. Client-Server Architecture:
The client and server are separate entities, allowing them to evolve independently. The client is responsible for the user
interface and user state, while the server manages application state and resources.
3. Cacheable:
Responses from the server must define themselves as cacheable or non-cacheable, allowing clients to cache responses to
improve performance.
4. Uniform Interface:
REST APIs use standard methods and conventions for interacting with resources, which simplifies and decouples the
architecture. The uniform interface typically involves the use of standard HTTP methods.
2. POST:
Create a new resource on the server.
3. PUT:
Update an existing resource on the server. If the resource does not exist, it can create a new one (though this is less
common).
4. PATCH:
Partially update an existing resource on the server.
5. DELETE:
Remove a resource from the server.
Resource Identification
Resources in a REST API are identified by URLs (Uniform Resource Locators). Each URL represents a specific resource or
collection of resources. For example:
GET /users:
Retrieves a list of users.
[
{ "id": 1, "name": "John Doe" },
{ "id": 2, "name": "Jane Smith" }
]
POST /users:
Creates a new user.
{
"name": "New User"
}
GET /users/1:
Retrieves the user with ID
1.
{
"id": 1, "name": "John Doe"
}
PUT /users/1:
Updates the user with ID
1 .
{
"name": "Updated User"
}
DELETE /users/1:
Deletes the user with ID
1.
let users = [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Smith' }
];
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
React Application
App.js:
function App() {
const [users, setUsers] = useState([]);
useEffect(() => {
axios.get('http://localhost:5000/users')
.then(response => setUsers(response.data))
.catch(error => console.error(error));
}, []);
return (
<div className="App">
<h1>User Management</h1>
<ul>
{users.map(user => (
<li key={user.id}>
{user.name}
<button onClick={() => updateUser(user.id, 'Updated Name')}>Update</
button>
<button onClick={() => deleteUser(user.id)}>Delete</button>
</li>
))}
</ul>
<button onClick={() => addUser('New User')}>Add User</button>
</div>
);
}
Introduction to Express
Express is a minimal and flexible Node.js web application framework that provides a robust set of features to build web and
mobile applications. It facilitates the rapid development of Node-based web applications. With Express, you can manage
different HTTP requests at different URLs and create routes for your web application.
Middleware support: Provides a series of middleware functions that can be used to handle requests.
Installation of Express
Before installing Express, ensure you have Node.js and npm (Node Package Manager) installed on your machine. You can
download them from nodejs.org.
mkdir express-app
cd express-app
npm init -y
3. Install Express:
The --save flag adds Express to the dependencies in the package.json file.
touch app.js
node app.js
Define a Route:
This line sets up a route for the root URL ( / ). When a GET request is made to this URL, the server responds with
"Hello, World!".
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
This line starts the server and makes it listen on port 3000. When the server is ready, it logs a message to the console.
Creating an Application:
Defining Routes:
You can define various routes using the
app object:
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
Sending a Response:
Middleware
Middleware functions are functions that have access to the request and response objects and can modify them. Middleware
can execute code, make changes to the request and response objects, end the request-response cycle, and call the next
middleware function in the stack.
Using Middleware:
// Custom middleware
app.use((req, res, next) => {
console.log('Request URL:', req.originalUrl);
next();
});
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
Body Parsing
To handle incoming request bodies, especially for POST and PUT requests, you need to use body-parsing middleware like
body-parser (though in recent versions of Express, body-parser is included in Express).
Using Body-Parser:
app.use(bodyParser.json());
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
5. Render Views:
Use the
res.render() method to render a view and send the resulting HTML to the client.
mkdir express-view-app
cd express-view-app
npm init -y
express-view-app/
├── views/
│ └── index.ejs
├── server.js
└── package.json
views/index.ejs:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %></title>
</head>
<body>
<h1><%= message %></h1>
</body>
</html>
node server.js
Navigate to http://localhost:3000 in your browser. You should see a web page with the title "Welcome" and the
message "Hello, World!".
Explanation
Setting the View Engine:
app.set('views', './views');
This line sets the directory where your view templates are located.
Rendering a View:
The res.render() method renders the index.ejs template, passing in an object with the data to be used in the
template. The keys in the object ( title and message ) correspond to the placeholders in the EJS template ( <%=
title %> and <%= message %> ).
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
<ul>
<% items.forEach(item => { %>
<li><%= item %></li>
<% }) %>
</ul>
</body>
</html>
In this example, an array of items is passed to the index.ejs template and rendered as an unordered list.
Conclusion
Rendering views in Express using a template engine like EJS allows you to dynamically generate HTML content based
on data from your application. This approach is beneficial for creating dynamic web pages and separating the logic of
your application from the presentation.
Authentication
Authentication is the process of verifying the identity of a user or system. It ensures that the entity trying to access a resource
or perform an action is who or what it claims to be. In web applications, authentication typically involves users providing
credentials (such as username and password) to prove their identity.
Authorization
Authorization, on the other hand, is the process of determining whether an authenticated user has the necessary permissions
to access a particular resource or perform a specific action. Once a user's identity has been verified through authentication,
authorization ensures that the user only has access to the resources and functionalities that they are allowed to use.
1. Authentication:
When a user successfully logs in, generate a JWT token containing the user's ID and any additional relevant
information.
2. Authorization:
For protected endpoints, require clients to include the JWT token in the request headers.
On the server side, verify the JWT token's signature using the secret key.
If the token is valid, extract the user's ID and any other relevant information from the token.
Use the extracted information to determine whether the user is authorized to access the requested resource or
perform the requested action.
3. Middleware:
Implement middleware in your Express application to handle JWT verification and user authentication.
Verify the JWT token in the request headers using the secret key.
If the token is valid, extract the user's information and attach it to the request object.
4. Example Implementation:
if (!token) {
return res.status(401).json({ message: 'Unauthorized' });
}
req.user = decoded;
next();
});
}
// Login route
app.post('/login', (req, res) => {
// Check user credentials
const user = { id: 1, username: 'user1' };
const token = jwt.sign(user, SECRET_KEY);
res.json({ token });
});
In this example, the /login route generates a JWT token upon successful authentication. The /protected route is protected
using the verifyToken middleware, which verifies the JWT token included in the request headers.
Conclusion
Authentication and authorization are essential for ensuring the security of web applications. By using JWT tokens, you can
securely authenticate users and authorize access to protected endpoints in your Express application. This helps prevent
unauthorized access to sensitive resources and functionalities.
Q6 . What is Type Script? Explain its compiler Options, Classes and Interfaces.
A.) TypeScript is an open-source programming language developed and maintained by Microsoft. It is a superset of
JavaScript, meaning that any valid JavaScript code is also valid TypeScript code. TypeScript extends JavaScript by adding
static typing, which allows developers to specify types for variables, function parameters, return values, and more.
2. Enhanced Tooling: TypeScript provides better tooling support compared to JavaScript. Integrated development
environments (IDEs) and code editors can leverage TypeScript's type information for features like autocompletion,
refactoring, and code navigation.
3. Modern ECMAScript Features: TypeScript supports the latest ECMAScript features, allowing developers to write
code using modern JavaScript syntax (e.g., arrow functions, async/await) while maintaining compatibility with older
JavaScript environments through transpilation.
4. Interfaces and Classes: TypeScript supports object-oriented programming features such as interfaces and classes,
providing a way to define contracts and blueprints for objects. Interfaces enable structural typing, while classes enable
classical inheritance and encapsulation.
5. Enums and Generics: TypeScript includes support for enumerations (enums) and generics. Enums allow developers to
define a set of named constants, while generics enable the creation of reusable components that can work with a variety
of data types.
6. Type Inference: TypeScript's type inference system automatically infers the types of variables based on their usage. This
reduces the need for explicit type annotations, making code cleaner and more concise.
7. Union Types and Intersection Types: TypeScript allows the creation of union types and intersection types, providing
flexibility in defining complex type relationships. Union types allow a value to have multiple possible types, while
intersection types combine multiple types into a single type.
Enhanced Developer Productivity: Features like autocompletion and type checking in IDEs improve developer
productivity and reduce debugging time.
Maintainability: TypeScript's type system facilitates better code organization and documentation, making codebases
easier to understand and maintain.
Scalability: TypeScript is well-suited for large-scale applications due to its support for modules, interfaces, and classes,
which promote code reuse and modularity.
target: Specifies the ECMAScript target version for the compiled JavaScript code (e.g., ES5, ES6).
module: Specifies the module code generation (e.g., CommonJS, AMD, ES6 modules).
{
"compilerOptions": {
"target": "ES6",
"module": "CommonJS",
"outDir": "./dist",
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true}
}
2. Classes in TypeScript
Classes in TypeScript allow you to define blueprints for objects with properties and methods. They enable you to implement
object-oriented programming concepts such as inheritance, encapsulation, and abstraction.
Syntax:
class ClassName {
// Properties
property1: type;
property2: type;
// Methods
method1(): returnType {
// Method body
}
method2(): returnType {
// Method body
}
}
Example:
class Person {
firstName: string;
lastName: string;
getFullName(): string {
return `${this.firstName} ${this.lastName}`;
}
}
3. Interfaces in TypeScript
Interfaces in TypeScript define contracts for objects, specifying the structure and types of their properties and methods. They
allow you to enforce consistency and provide type-checking capabilities.
Syntax:
interface InterfaceName {
property1: type;
property2: type;
method1(): returnType;
method2(): returnType;
}
Example:
area(): number {
return Math.PI * this.radius ** 2;
}
}
Interfaces can also be used to define contracts for function types, arrays, and more complex structures.
Conclusion
TypeScript compiler options allow you to configure the behavior of the TypeScript compiler. Classes enable you to define
blueprints for objects with properties and methods, while interfaces define contracts for objects, specifying their structure
and types. These features help you write maintainable, scalable, and type-safe code in TypeScript.
Q6. Explain about TypeScript Generic and Decorators along with example?
A.)
TypeScript Generics
TypeScript generics provide a way to create reusable components that can work with a variety of data types while
maintaining type safety. Generics allow you to define functions, classes, and interfaces that can operate on any type, rather
than a specific one.
Syntax:
class ClassName<T> {
// Class body
}
interface InterfaceName<T> {
Example:
// Using generics
let result1 = identity<string>('Hello');
let result2 = identity<number>(123);
In this example, the identity function is a generic function that takes an argument of type T and returns the same type. The
type T is specified when calling the function.
TypeScript Decorators
Decorators are a feature of TypeScript that allow you to attach metadata and modify the behavior of classes, methods,
properties, or at design time. They provide a way to add functionality to existing code without modifying its underlying
structure.
Syntax:
@decoratorName
class ClassName {
@decoratorName
propertyName: type;
@decoratorName
methodName() {
// Method body
}
}
Example:
class Example {
@log
greet() {
console.log('Hello, world!');
}
In this example, the log decorator is applied to the greet method of the Example class. When the greet method is called,
the decorator logs a message to the console.
Conclusion
TypeScript generics and decorators are powerful features that enhance the flexibility and expressiveness of the language.
Generics enable you to create reusable components that work with different data types, while decorators provide a way to
add metadata and behavior to classes and their members at design time. These features are widely used in TypeScript
libraries and frameworks to build scalable and maintainable codebases.
Unit - IV (Angular 2)
Introduction to Angular:
1. Component-Based Architecture:
Angular adopts a component-based architecture, where applications are built using reusable and composable
components. Components encapsulate HTML templates, CSS styles, and behavior logic, making it easier to manage and
maintain complex user interfaces.
2. Typescript Language:
Angular is written in TypeScript, a superset of JavaScript that adds static typing, classes, interfaces, and other features to
JavaScript. TypeScript enhances developer productivity, improves code maintainability, and provides better tooling
support.
3. Modular Development:
Angular applications are organized into modules, which are collections of related components, directives, pipes, and
services. Modular development promotes code reusability, separation of concerns, and scalability.
5. Dependency Injection:
Angular's dependency injection system facilitates the creation and management of application dependencies. It promotes
loosely coupled and highly testable code by allowing components and services to declare their dependencies rather than
creating them directly.
7. HTTP Client:
Angular provides an HTTP client module for making HTTP requests to backend servers. It offers features such as
request and response interception, error handling, and support for RxJS Observables.
Angular Architecture:
1. Modules:
Angular applications are organized into modules, which are logical containers for components, directives, pipes, and
services. Modules help in organizing the application's features and dependencies.
2. Components:
Components are the building blocks of Angular applications. Each component encapsulates a part of the user interface,
consisting of an HTML template, CSS styles, and TypeScript code that defines its behavior.
3. Templates:
Templates define the HTML structure of Angular components and include bindings, directives, and event handlers that
connect the component's data and behavior with the view.
4. Directives:
Directives are custom HTML attributes, elements, or structural markers that extend the behavior of HTML elements.
Angular provides built-in directives like ngIf, ngFor, and ngModel, as well as the ability to create custom directives.
5. Services:
Services are reusable business logic units that perform specific tasks, such as fetching data from a server, performing
calculations, or managing application state. Services promote code reusability and maintainability.
8. HTTP Client:
Angular's HTTP client module provides a way to communicate with backend servers using HTTP requests. It supports
features such as request and response interception, error handling, and asynchronous data handling with RxJS
Observables.
Angular Routing:
Angular's router is a powerful feature that allows you to navigate between different views or components within a single-
page application (SPA). It enables you to define routes, load components dynamically, and handle navigation events.
1. Setting Up Routing:
To use Angular's router, you need to import the RouterModule and define routes in your application module. Each route is
associated with a component and a path.
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule
2. Router Outlet:
In your main application component template, use the <router-outlet></router-outlet> directive to specify where Angular
should render the component associated with the current route.
<router-outlet></router-outlet>
<a routerLink="/">Home</a>
<a routerLink="/about">About</a>
1. Parent Component:
Define a property in the parent component and bind it to an input property in the child component.
@Component({
selector: 'app-parent',
template: `
<app-child [message]="parentMessage"></app-child>
`
})
export class ParentComponent {
parentMessage = 'Message from parent';
}
2. Child Component:
Declare an input property in the child component to receive data from the parent component.
@Component({
selector: 'app-child',
template: `
<p>{{ message }}</p>
`
})
export class ChildComponent {
@Input() message: string;
}
@Injectable()
export class DataService {
sharedData: string;
setData(data: string) {
this.sharedData = data;
}
getData() {
return this.sharedData;
@Component({
selector: 'app-parent',
template: `
<app-sibling1 [data]="sharedData"></app-sibling1>
<app-sibling2 [data]="sharedData"></app-sibling2>
`
})
export class ParentComponent {
sharedData = 'Shared data';
}
Conclusion:
Angular routing allows you to navigate between different views or components within a single-page application. You can
pass data between parent and child components using input properties, and between sibling components using a shared
service or a parent component as an intermediary. These techniques enable you to create more dynamic and interactive
Angular applications.
1. Directives:
Directives are markers on a DOM element that tell Angular to do something with that element or its children. They are
classified into three types:
i. Component Directives:
Component directives are directives with a template. They represent a UI component and encapsulate its behavior,
presentation, and structure in a single reusable unit. Components are the most commonly used directive type in Angular
applications.
@Component({
selector: 'app-example',
template: '<h1>Hello, World!</h1>'
})
export class ExampleComponent {}
2. Modules:
Modules in Angular are containers for a group of related components, directives, pipes, and services. They help organize and
manage the application's components and services into cohesive blocks with well-defined boundaries.
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
@NgModule({
declarations: [FeatureComponent],
imports: [CommonModule],
exports: [FeatureComponent]
3. Components:
Components are the basic building blocks of Angular applications. They encapsulate the UI (HTML template), the
application logic (Typescript class), and the styling (CSS) into reusable and modular units.
i. Creating a Component:
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent {}
// example.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent {
title = 'Example Component';
onClick(): void {
console.log('Button clicked');
}
}
typescriptCopy code
import { Component, OnInit, OnDestroy } from '@angular/core';
ngOnDestroy(): void {
// Called just before Angular destroys the component
}
}
Conclusion:
In Angular, directives, modules, and components are essential concepts that enable you to create dynamic, modular, and
maintainable applications. Directives allow you to extend HTML functionality, modules provide a way to organize and
manage application functionality, and components encapsulate UI elements and application logic into reusable units.
Understanding these concepts is crucial for building effective Angular applications.
Creating a Service:
1. Generate a Service:
You can use the Angular CLI to generate a service.
@Injectable({
providedIn: 'root'
})
export class MyService {
constructor(private http: HttpClient) {}
fetchData(): Observable<any> {
return this.http.get('https://api.example.com/data');
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent implements OnInit {
data: any;
ngOnInit(): void {
this.myService.fetchData().subscribe(data => {
this.data = data;
});
}
}
<div *ngIf="data">
<p>Data: {{ data | json }}</p>
</div>
Error Handling:
Always handle errors when consuming APIs. You can use the subscribe method's second argument to define an error
handler.
this.myService.fetchData().subscribe(
data => {
// Handle data
},
error => {
console.error('Error fetching data:', error);
Conclusion:
Angular services are powerful tools for organizing and sharing code in your application. They allow you to encapsulate
functionality in a reusable way, making your application more modular and maintainable. When consuming APIs, services
play a crucial role in making HTTP requests and handling data, ensuring that your application interacts effectively with
external data sources.
Angular Observables:
Observables are a core part of Angular's reactive programming paradigm. They represent a sequence of asynchronous data or
events over time. Observables can emit multiple values asynchronously, and they provide a wide range of operators to
transform, combine, and manipulate these data streams.
Creating Observables:
You can create observables using the Observable class from the rxjs library. There are various ways to create observables,
such as:
3. From an Event:
Subscribing to Observables:
You subscribe to observables to listen for values emitted by the observable. The subscribe() method allows you to define
callbacks for handling emitted values, errors, and completion notifications.
observable.subscribe(
value => console.log(value), // onNext
error => console.error(error), // onError
Operators:
Observables provide a rich set of operators for transforming, filtering, and combining data streams. Some commonly used
operators include map , filter , mergeMap , switchMap , and debounceTime .
typescriptCopy code
import { from } from 'rxjs';
import { filter, map } from 'rxjs/operators';
from([1, 2, 3, 4, 5])
.pipe(
filter(value => value % 2 === 0),
map(value => value * 2)
)
.subscribe(value => console.log(value));
Interpolation:
Interpolation allows you to embed expressions into the HTML template. It is denoted by double curly braces {{ }} .
Property Binding:
Property binding allows you to set an element's property to a value of a component's property. It is denoted by square
brackets [ ] .
<img [src]="imageUrl">
Event Binding:
Event binding allows you to listen for and respond to DOM events. It is denoted by parentheses ( ) .
<input [(ngModel)]="username">
Conclusion:
1. Template-Driven Forms:
Template-driven forms are simpler to implement and are suitable for scenarios where forms are relatively straightforward and
the data binding is primarily one-way (from the component class to the template).
Features:
Form logic is defined directly in the HTML template.
Example:
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent {
user = {
username: '',
email: ''
};
onSubmit(form: any) {
console.log('Form submitted!', form.value);
}
}
2. Reactive Forms:
Features:
Form logic is defined programmatically in the component class.
Example:
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponent implements OnInit {
myForm: FormGroup;
ngOnInit(): void {
this.myForm = this.formBuilder.group({
username: ['', Validators.required],
email: ['', [Validators.required, Validators.email]]
});
}
onSubmit() {
console.log('Form submitted!', this.myForm.value);
}
}
Comparison:
Feature Template-Driven Forms Reactive Forms
Conclusion:
Both template-driven forms and reactive forms have their place in Angular development, and the choice between them
depends on the specific requirements of your application. Template-driven forms are simpler and more suitable for basic
forms with minimal validation requirements, while reactive forms provide more control and flexibility for complex forms
with dynamic behavior and extensive validation. Understanding the differences between these two types of forms allows you
to choose the appropriate approach for your Angular applications.
Built-in Pipes:
Angular comes with a variety of built-in pipes that you can use out of the box. Some of the commonly used built-in pipes
include:
<p>{{ today | date }}</p> <!-- Outputs: Mar 15, 2022 -->
<p>{{ 'Hello World' | uppercase }}</p> <!-- Outputs: HELLO WORLD -->
<p>{{ 'Hello World' | lowercase }}</p> <!-- Outputs: hello world -->
Chaining Pipes:
You can chain multiple pipes together to perform complex data transformations.
<p>{{ birthday | date | uppercase }}</p> <!-- Outputs: MARCH 15, 2022 -->
You can then use the custom pipe in your templates just like built-in pipes.
@Pipe({
name: 'myPipe',
pure: false
})
export class MyPipe implements PipeTransform {
// Pipe implementation
}
Conclusion:
Pipes are a powerful feature in Angular for transforming data in your templates. Whether you need to format dates, convert
strings to uppercase, or perform custom data transformations, Angular pipes provide a clean and declarative way to achieve
it. By leveraging built-in pipes and creating custom pipes, you can effectively format and manipulate data to meet the
requirements of your application's UI.
2. Injection: When an object (such as a component or service) needs a dependency, Angular's DI system provides it by
injecting the dependency into the object's constructor or method.
Example:
Consider a simple service and a component in an Angular application:
// Service
import { Injectable } from '@angular/core';
@Injectable()
export class DataService {
getData(): string {
return 'Hello from DataService';
}
}
// Component
import { Component } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-my-component',
template: '<p>{{ message }}</p>',
providers: [DataService]
})
export class MyComponent {
message: string;
In this example:
Angular's DI system injects an instance of DataService into the MyComponent component's constructor.
The MyComponent component uses the injected DataService instance to retrieve data and display it.
Conclusion:
Dependency Injection is a fundamental concept in Angular that allows components, services, and other objects to receive
their dependencies from external sources. By using DI, Angular promotes modularity, testability, and reusability in your
application code. While there is no specific concept called "Angular dependency function," understanding how Dependency
Injection works is crucial for building Angular applications effectively.