Body Parsing in Express.js Explained
Body Parsing in Express.js Explained
In [Link], body parsing refers to the process of interpreting the data sent in the body of
HTTP requests (usually in POST or PUT requests) so that it can be easily accessed and used
within the application. This is crucial because the body of an HTTP request is often used to send
data (like form submissions, JSON, or files) from the client to the server.
By default, Express does not automatically parse the request body. You need to use middleware
to parse the body, depending on the content type of the request (e.g., JSON, URL-encoded, or
multipart).
1. JSON Parsing: This is used when the request body contains JSON data. Express
provides middleware ([Link]()) to handle this.
Example:
javascript
Copy code
const express = require('express');
const app = express();
[Link](3000);
2. URL-encoded Form Parsing: When the request body contains data sent from an HTML
form with the application/x-www-form-urlencoded content type (common in simple
web forms), Express uses [Link]() middleware to parse it.
Example:
javascript
Copy code
const express = require('express');
const app = express();
[Link](3000);
3. Multipart/Form-Data Parsing: This type of body parsing is used for file uploads. To
parse multipart/form-data (which is used for file uploads), you typically use an
external library like multer.
javascript
Copy code
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const app = express();
[Link](3000);
Access to Data: It helps access the raw data that the client sends in the request body,
such as JSON objects, strings, or files.
Structured Data: Without body parsing, data would be unreadable or in raw byte form,
making it hard to handle and process.
Flexibility: Different types of requests (JSON, form data, file uploads) require different
parsing techniques.
In summary, body parsing in [Link] is the middleware mechanism to process the incoming
data in the body of HTTP requests so it can be easily accessed and used in your application.
Express provides built-in middleware for JSON and URL-encoded data, and for more advanced
use cases like file uploads, external libraries like Multer are commonly used.
In [Link], sending a JSON response is straightforward using the [Link]() method. This
method sends a response with a Content-Type of application/json and serializes the
JavaScript object or value you provide into a JSON string.
Syntax
javascript
Copy code
[Link](data);
data:The JavaScript object (or any value) that you want to send as a JSON response.
Express automatically converts the object into a JSON string.
Example Usage
Here’s an example of how you can send a JSON response in an Express route:
javascript
Copy code
const express = require('express');
const app = express();
[Link](3000, () => {
[Link]('Server is running on port 3000');
});
Key Points:
1. JSON Response: The [Link]() method automatically sets the Content-Type header
to application/json and converts the object into JSON format.
2. Automatic Serialization: You do not need to manually call [Link](). Express
handles the serialization for you.
javascript
Copy code
[Link]('/error', (req, res) => {
const errorResponse = {
error: 'Something went wrong',
status: 'fail'
};
In this case, the status code 400 is set, and the response body is the JSON object provided.
Response Example
When you visit /data, the response would look like this:
json
Copy code
{
"message": "Hello, world!",
"status": "success",
"timestamp": "2024-12-11T12:00:00.000Z"
}
This is how you send a JSON response from an Express server, making it easy to return
structured data to clients (like web browsers or APIs).
RxJS is a library for reactive programming using Observables, which allows developers to work
with asynchronous data streams more efficiently. It provides a powerful and flexible way to
manage asynchronous events and data flows, making it particularly useful for scenarios like
handling user input, HTTP requests, WebSocket communication, or any event-driven
architecture.
javascript
Copy code
import { Observable } from 'rxjs';
javascript
Copy code
const observer = {
next: value => [Link]('Received:', value),
error: err => [Link]('Error:', err),
complete: () => [Link]('Completed!')
};
[Link](observer);
3. Operators: RxJS provides a rich set of operators to transform, filter, combine, and
manipulate streams of data. These operators are used to manage the flow of data and add
reactive behavior.
o Map: Transforms the data.
o Filter: Filters the stream of data based on a condition.
o MergeMap: Flattens multiple Observables into one.
o ConcatMap: Similar to mergeMap, but processes Observables in sequence.
javascript
Copy code
import { map } from 'rxjs';
[Link](
map(x => x * 2) // Multiply each value by 2
).subscribe([Link]);
4. Subjects: A Subject is a special type of Observable that allows you to multicast values to
many Observers. It acts as both an Observer and an Observable, meaning you can both
subscribe to it and emit values into it.
javascript
Copy code
import { Subject } from 'rxjs';
5. Schedulers: Schedulers control the timing of the emissions from an Observable. They
allow you to control when and how the values are emitted, making it possible to schedule
tasks and manage concurrency in reactive streams.
Advantages of RxJS
1. Asynchronous Programming Made Simple: RxJS abstracts away complex async logic
such as callbacks, promises, and event handlers into an elegant and declarative approach,
allowing developers to manage async streams more naturally.
2. Composability: Operators allow you to compose complex asynchronous flows and
transformations in a clean and readable manner. You can chain operators to handle
events, transform data, and handle errors without deeply nested callbacks.
3. Declarative Code: RxJS promotes a declarative style of programming where you
describe the sequence of operations (such as mapping, filtering, merging, etc.) rather than
manually managing the flow of events.
4. Efficient Memory Management: RxJS provides mechanisms like unsubscribe() that
allow you to handle resources more efficiently, avoiding memory leaks. Operators like
takeUntil and takeWhile help with automatically managing subscriptions.
5. Stream Handling: RxJS makes it easy to handle streams of data such as user inputs,
WebSocket messages, or even events from multiple sources, all in one unified manner.
1. Handling User Input: RxJS is excellent for managing complex user interactions like
form inputs, mouse events, key presses, and more. For instance, you can debounce user
input, filter values, and react to events in a cleaner way than with traditional methods.
2. HTTP Requests: RxJS can be used with HTTP requests, where the response is an
Observable, allowing chaining of operators to handle request flow, retries, and errors.
javascript
Copy code
import { fromFetch } from 'rxjs';
data$.subscribe({
next: response => [Link](response),
error: err => [Link]('Request failed', err),
complete: () => [Link]('Request complete')
});
3. Real-Time Applications: In applications like chat apps or live data streams, RxJS can
simplify the management of real-time data streams, like WebSocket or Server-Sent
Events (SSE).
4. Event-driven Programming: For event-based architectures or applications, RxJS makes
it easy to manage multiple events, their transformations, and actions in response to those
events.
Conclusion
RxJS is a powerful library that offers a reactive, declarative approach to handling asynchronous
data streams. By using Observables and operators, developers can create complex and efficient
reactive applications while keeping the code clean and maintainable. Its usage has become
especially popular in modern frameworks like Angular, where it is often used to manage HTTP
requests, forms, and other event-driven programming tasks.
NgRx is a popular library for managing state in Angular applications. It is inspired by the Redux
pattern from the React ecosystem but is specifically built for Angular. NgRx uses a reactive
approach to manage the application's state by leveraging RxJS Observables. It provides a way to
handle application state in a predictable, centralized manner, making it easier to track changes
and debug applications.
In essence, NgRx follows the Redux principles but integrates well with Angular’s component-
driven architecture and the reactive programming model.
1. Store: The store in NgRx is the central entity where the application's state is held. The
store provides a single source of truth for the entire application state. Instead of each
component managing its own state, components in an NgRx-powered application
communicate with the store to access and update the state.
2. Actions: Actions are events or commands that describe something that has happened in
the application. Actions are dispatched to trigger state changes. They are the only way to
interact with the store.
o Actions are plain objects with at least a type property that describes the action.
o Actions can also carry payloads of additional data that are needed for processing.
Example:
typescript
Copy code
export const loadData = createAction('[Data] Load Data');
export const loadDataSuccess = createAction('[Data] Load Data Success',
props<{ data: any[] }>());
export const loadDataFailure = createAction('[Data] Load Data Failure',
props<{ error: any }>());
3. Reducers: A reducer is a function that takes the current state and an action as inputs,
and returns a new state based on the action's type and payload. Reducers are pure
functions, meaning they should not mutate the state directly but instead return a new state
object.
Example:
typescript
Copy code
export const dataReducer = createReducer(
initialState,
on(loadData, state => ({ ...state, loading: true })),
on(loadDataSuccess, (state, { data }) => ({ ...state, loading: false,
data })),
on(loadDataFailure, (state, { error }) => ({ ...state, loading:
false, error }))
);
4. Selectors: Selectors are functions that allow you to select or retrieve specific parts of the
store’s state. They can be used to compute derived state or access nested data. Selectors
are often memoized, meaning they will return the cached result unless the selected state
changes, improving performance.
Example:
typescript
Copy code
export const selectData = createSelector(
selectFeatureState,
(state: State) => [Link]
);
5. Effects: Effects handle side effects like asynchronous operations (e.g., HTTP requests),
external interactions, and logging. They listen for specific actions and can dispatch new
actions in response, typically after completing asynchronous operations.
Example:
typescript
Copy code
@Injectable()
export class DataEffects {
loadData$ = createEffect(() =>
[Link]$.pipe(
ofType(loadData),
switchMap(() =>
[Link]().pipe(
map(data => loadDataSuccess({ data })),
catchError(error => of(loadDataFailure({ error })))
)
)
)
);
6. State Management Flow: The typical flow of state management in NgRx can be
outlined as:
1. Action is Dispatched: A component or service dispatches an action (e.g.,
loadData).
2. Reducer Processes Action: The reducer receives the action and updates the state
based on the action's type.
3. State is Updated: The store is updated with the new state.
4. Effects Handle Side Effects: If the action triggers an asynchronous operation
(e.g., fetching data), an effect will listen to the action and perform the necessary
side effects, dispatching success or failure actions.
5. Selectors Retrieve State: Components or services select the state using selectors
to display or interact with the updated state.
typescript
Copy code
export const loadData = createAction('[Data] Load Data');
export const loadDataSuccess = createAction('[Data] Load Data Success',
props<{ data: any[] }>());
export const loadDataFailure = createAction('[Data] Load Data Failure',
props<{ error: any }>());
2. Reducer: A reducer handles these actions and updates the store:
typescript
Copy code
export const initialState: State = {
loading: false,
data: [],
error: null
};
3. Effect: An effect listens for the loadData action and fetches data from a service:
typescript
Copy code
@Injectable()
export class DataEffects {
loadData$ = createEffect(() =>
[Link]$.pipe(
ofType(loadData),
switchMap(() =>
[Link]().pipe(
map(data => loadDataSuccess({ data })),
catchError(error => of(loadDataFailure({ error })))
)
)
)
);
4. Component: A component dispatches the action and selects the data from the store:
typescript
Copy code
@Component({
selector: 'app-data',
templateUrl: './[Link]'
})
export class DataComponent implements OnInit {
data$ = [Link](selectData);
loading$ = [Link](selectLoading);
1. Centralized State: All application state is managed in a single store, making it easier to
track and debug.
2. Predictable State: State transitions are handled in a predictable way using actions and
reducers, reducing complexity and improving maintainability.
3. Separation of Concerns: NgRx promotes a clear separation of concerns between
components, state management, and side effects (via effects).
4. Asynchronous Handling: Effects provide a clean way to manage side effects such as
HTTP requests and other asynchronous operations.
5. Testability: The use of pure functions for reducers and actions makes it easier to write
unit tests for the application state and logic.
Conclusion
NgRx is a powerful and scalable solution for managing state in Angular applications, especially
for larger and more complex apps with significant asynchronous interactions. By using the
Redux pattern combined with Angular’s reactive programming paradigm, NgRx helps
developers build maintainable, predictable, and testable applications. It may introduce a learning
curve, but once understood, it provides a robust framework for handling state in Angular
applications efficiently.
Lazy loading in Angular is a design pattern used to load modules only when they are needed,
rather than loading them upfront with the initial application load. This improves performance,
especially in large applications, by reducing the initial load time and only loading the necessary
parts of the app when the user navigates to a specific route. Lazy loading is typically
implemented using the Angular Router and can be configured using the loadChildren property
in routing.
Example:
typescript
Copy code
const routes: Routes = [
{
path: 'feature',
loadChildren: () => import('./feature/[Link]').then(m =>
[Link])
}
];
Dependency Injection (DI) is a design pattern and core concept in Angular. It allows objects to
be injected into a class, rather than the class creating them itself. In Angular, DI is used to
provide services and other dependencies to components, directives, pipes, and other services. It
improves modularity, testability, and flexibility by decoupling the components from their
dependencies. The Angular framework handles the lifecycle and instantiation of dependencies
automatically.
Example:
typescript
Copy code
@Injectable({
providedIn: 'root'
})
export class MyService {
constructor(private http: HttpClient) { }
}
TypeScript enforces type safety in Angular applications by providing a static type system. This
allows developers to define the types of variables, function parameters, return values, and
properties, ensuring that data conforms to expected types at compile time. TypeScript helps catch
errors early, improving the maintainability and reliability of code. For example, it prevents
passing a string where a number is expected, or calling a method on an object that does not have
that method.
Example:
typescript
Copy code
let age: number = 30; // TypeScript enforces that 'age' must be a number
age = '30'; // This will cause an error because 'age' is declared as a number
8. What is NgRx?
NgRx is a state management library for Angular applications, inspired by Redux. It uses
Observables to manage state reactively, making it easier to handle complex application states.
NgRx is built around the Store pattern, where the state of the application is centralized in one
place, and changes are managed through actions and reducers. It also supports effects to
manage side effects like HTTP requests. NgRx improves the predictability, maintainability, and
testability of Angular apps.
9. Define a Subject in RxJS
A Subject in RxJS is a special type of Observable that allows values to be multicasted to many
Observers. Unlike a regular Observable, which only sends notifications to subscribers, a Subject
can act as both an Observable and an Observer. This means it can both emit values and listen to
them. Subjects are often used to share values among multiple parts of an application.
Example:
typescript
Copy code
import { Subject } from 'rxjs';
An Observable in RxJS is a data stream that can emit values over time. It allows you to model
asynchronous operations like HTTP requests, user inputs, and WebSocket messages.
Observables are the core concept of reactive programming and are used to represent events, data,
or messages. You can subscribe to an Observable to start receiving its values, and you can use
operators to transform, filter, and combine these streams.
Example:
typescript
Copy code
import { Observable } from 'rxjs';
[Link]({
next: value => [Link](value),
complete: () => [Link]('Done!')
});
11. What are the Testing Strategies used for AngularJS Applications?
12. What are the Testing Strategies used for Angular Applications?
In Angular (the modern version), testing strategies are similar to AngularJS but with some
improvements:
Unit Testing: Using Jasmine for writing tests and Karma for running them, unit tests
are written for services, components, pipes, and directives.
Component Testing: Angular provides TestBed to configure and test Angular
components in isolation, allowing you to mock dependencies and simulate user
interaction.
End-to-End (E2E) Testing: Tools like Cypress or Protractor are used to simulate real
user scenarios and test the whole application. Cypress is gaining popularity due to its
speed and ease of use.
The core concepts of RxJS revolve around Observables, Observers, and Operators:
1. Observables: Represent streams of data that can emit values over time. They can handle
both synchronous and asynchronous data.
2. Observers: Functions that subscribe to an Observable and define how to react to the data
emitted by the Observable.
3. Operators: Functions that allow you to transform, filter, combine, and manipulate data
streams. Some common operators include:
o map(): Transforms emitted values.
o filter(): Filters emitted values based on a condition.
o mergeMap(), concatMap(): Handle multiple Observables.
o catchError(): Handles errors in a stream.
4. Subjects: Special types of Observables that allow values to be multicasted to multiple
subscribers. Subjects are useful for sharing data and acting as a bridge between different
parts of an application.
5. Schedulers: Manage the execution of Observables, allowing you to control when and
how values are emitted.
RxJS is widely used in Angular to handle asynchronous data, such as HTTP requests, events, and
user input, and it provides a declarative way to manage complex data flows.
1. What is the purpose of @Input() and @Output() in Angular?
@Input(): The @Input() decorator is used to pass data from a parent component to a
child component. It allows the child component to receive data from the parent and use it
within the component. Essentially, @Input() marks a property of a child component as a
target for data binding from the parent component.
Example:
typescript
Copy code
@Component({
selector: 'app-child',
template: `<p>{{message}}</p>`
})
export class ChildComponent {
@Input() message: string;
}
html
Copy code
<app-child [message]="parentMessage"></app-child>
@Output(): The @Output() decorator is used to send data from a child component to a
parent component. It is commonly used with an EventEmitter to emit events that the
parent component can listen to. This creates a mechanism for child components to
communicate back to their parents.
Example:
typescript
Copy code
@Component({
selector: 'app-child',
template: `<button (click)="sendData()">Send</button>`
})
export class ChildComponent {
@Output() dataEvent = new EventEmitter<string>();
sendData() {
[Link]('Data from child');
}
}
Angular provides a set of predefined lifecycle hooks that allow developers to tap into the
different stages of a component’s life, such as creation, updates, and destruction. However,
Angular doesn’t allow custom lifecycle hooks directly. Developers can use predefined lifecycle
hooks like ngOnInit, ngOnChanges, and others to customize the behavior during specific stages.
For example, custom logic like fetching data from an API or performing clean-up tasks can be
written in these hooks.
However, there is no concept of truly "custom" lifecycle hooks beyond the predefined ones
provided by Angular. These hooks are sufficient for managing and responding to various events
in a component’s lifecycle.
3. Describe how the OnPush change detection strategy works and how it
optimizes performance.
In Angular, the default change detection strategy checks all components in the component tree
for changes whenever any change occurs. This can be inefficient in larger applications.
The OnPush change detection strategy optimizes performance by reducing the number of checks
Angular performs. When a component uses the OnPush strategy, Angular only checks the
component and its children for changes under the following conditions:
This means that Angular does not check the component for changes every time the application
state changes, but rather only when something the component depends on actually changes.
Example:
typescript
Copy code
@Component({
selector: 'app-example',
changeDetection: [Link],
template: `<p>{{data}}</p>`
})
export class ExampleComponent {
@Input() data: string;
}
By using OnPush, Angular checks only when necessary, significantly improving performance,
especially in large applications.
ngOnChanges():
o This hook is called whenever an @Input() property of the component changes.
It’s called before ngOnInit and can be used to react to changes in the input
values. It receives a SimpleChanges object, which contains the previous and
current values of the inputs.
Example:
typescript
Copy code
ngOnChanges(changes: SimpleChanges) {
[Link]('Previous:', changes['inputData'].previousValue);
[Link]('Current:', changes['inputData'].currentValue);
}
ngOnInit():
o This hook is called once after the component’s first change detection cycle, i.e.,
after the component's input properties are initialized. It’s commonly used for
initialization tasks like fetching data from a server.
Example:
typescript
Copy code
ngOnInit() {
[Link]();
}
ngDoCheck():
o This hook is called during every change detection cycle, regardless of whether the
input properties have changed. It’s useful for custom change detection or when
you need to perform tasks not automatically handled by Angular’s default change
detection.
Example:
typescript
Copy code
ngDoCheck() {
[Link]('Change detection cycle has run.');
}
ngAfterContentInit():
o This hook is called once after Angular has projected content into the component,
meaning it is called after content (from <ng-content>) is placed inside the
component’s view. This is useful if you need to perform actions once the content
is ready.
Example:
typescript
Copy code
ngAfterContentInit() {
[Link]('Content has been projected into the component.');
}
5. Explain the need for security in Angular and XSS, CSRF prevention
XSS (Cross-Site Scripting): XSS occurs when attackers inject malicious scripts into web
pages that are viewed by other users. This can lead to stealing sensitive data, session
hijacking, etc. Angular prevents XSS by automatically escaping HTML, CSS, and
JavaScript in the templates to ensure that any injected content is treated as plain text, not
executable code.
Example: Angular automatically escapes dangerous characters like <, >, and & in the
template, so even if malicious data is rendered, it won’t be executed as code.
html
Copy code
<div>{{userInput}}</div> <!-- Automatically escapes dangerous HTML
content -->
CSRF (Cross-Site Request Forgery): CSRF occurs when an attacker tricks the user into
making unwanted requests to a server that the user is authenticated on. This is commonly
done by sending requests with the user's credentials (like cookies or tokens) to perform
actions on behalf of the user without their consent.
To prevent CSRF attacks, Angular provides an HttpClient that can be configured to send
a CSRF token with requests. The server needs to validate this token to ensure that the
request is legitimate.
Example:
typescript
Copy code
@Injectable({
providedIn: 'root'
})
export class AuthService {
constructor(private http: HttpClient) {}
login(credentials: any) {
return [Link]('/api/login', credentials, {
headers: new HttpHeaders().set('X-CSRF-Token',
[Link]())
});
}
private getCsrfToken() {
return [Link]('=')[1]; // Example for extracting
CSRF token from cookies
}
}
By implementing these security measures and practices, Angular helps developers protect their
applications from common web vulnerabilities.
1-2 Marks Question 1. What is a decorator in TypeScript? 2. What are utility types in TypeScript? 4-5
Marks Question 1. Explain method decorator in TypeScript. 2. Demonstrate generics in TypeScript with
suitable example. 3. What are utility types in TypeScript?Explain Conditional Type (any four)? 4. What
are decorators in TypeScript? Provide an example of using a class decorator. 5. What are decorators in
TypeScript? Provide an example of using a class decorator. 6. What are utility types in TypeScript.
Explain Conditional Type (any four)?
A decorator in TypeScript is a special kind of function that can be applied to classes, methods,
properties, or parameters to modify their behavior or add additional functionality. Decorators are
part of the metadata reflection mechanism in TypeScript, which allows you to add metadata or
modify the way elements work at runtime.
Decorators are prefixed with an @ symbol and are often used in frameworks like Angular to add
behaviors to classes, properties, and methods.
There are several types of decorators in TypeScript:
@Component
class MyComponent {
constructor() {
[Link]('MyComponent initialized');
}
}
In this example:
class MyClass {
@Log
myMethod(arg: number) {
[Link]('Method executed with arg:', arg);
}
}
In this example, the @Log decorator is applied to the myMethod method to log the arguments
when the method is called.
Types of Decorators:
json
Copy code
{
"compilerOptions": {
"experimentalDecorators": true
}
}
Utility types in TypeScript are predefined generic types that help perform common
transformations or operations on types. These utility types simplify type manipulation, making
code more concise and readable. They can be used to create new types based on existing ones.
1. Partial<T>
The Partial<T> utility type makes all properties of a given type T optional.
typescript
Copy code
interface Person {
name: string;
age: number;
}
2. Required<T>
The Required<T> utility type makes all properties of a given type T required, even if they were
originally optional.
typescript
Copy code
interface Person {
name: string;
age?: number;
}
3. Readonly<T>
The Readonly<T> utility type makes all properties of a given type T read-only, meaning they
cannot be reassigned after initialization.
typescript
Copy code
interface Person {
name: string;
age: number;
}
4. Pick<T, K>
The Pick<T, K> utility type allows you to create a new type by picking a subset of properties K
from the type T.
typescript
Copy code
interface Person {
name: string;
age: number;
address: string;
}
5. Omit<T, K>
The Omit<T, K> utility type creates a new type by omitting certain properties K from the type T.
typescript
Copy code
interface Person {
name: string;
age: number;
address: string;
}
The Record<K, T> utility type constructs a type with a set of properties K of type T. This is
useful for creating objects with specific keys and values.
typescript
Copy code
type Person = Record<'name' | 'age', string>;
7. Exclude<T, U>
The Exclude<T, U> utility type constructs a type by excluding types from T that are assignable
to U.
typescript
Copy code
type A = string | number | boolean;
type B = Exclude<A, boolean>; // Excludes 'boolean' from 'A', resulting in
'string | number'
8. Extract<T, U>
The Extract<T, U> utility type constructs a type by extracting the types from T that are
assignable to U.
typescript
Copy code
type A = string | number | boolean;
type B = Extract<A, string | number>; // Extracts 'string | number' from 'A'
9. NonNullable<T>
The NonNullable<T> utility type constructs a type by removing null and undefined from the
type T.
typescript
Copy code
type A = string | number | null | undefined;
type B = NonNullable<A>; // Removes 'null' and 'undefined' from 'A',
resulting in 'string | number'
10. Infer
The infer keyword is used in conditional types to infer a type within a conditional block. It’s
often used to extract a type from another type.
typescript
Copy code
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
Utility types allow developers to manipulate types in a flexible and reusable way, making
TypeScript a more powerful language for handling complex type transformations.
class Calculator {
@Log
add(a: number, b: number) {
return a + b;
}
}
In this example:
The Log decorator wraps the add method, logging the arguments and the result when the
method is called.
Generics in TypeScript allow you to define reusable components or functions while maintaining
type safety. They enable you to work with different data types without compromising on the
specific type checks.
In this example:
The identity function is a generic function that accepts a parameter of type T and returns a
value of type T.
The type T is inferred from the passed argument, ensuring that the function is type-safe.
constructor(value: T) {
[Link] = value;
}
getValue(): T {
return [Link];
}
}
In this example:
The Box class uses a generic type T to hold a value, and the type of the value is determined
when the class is instantiated.
3. What are Utility Types in TypeScript? Explain Conditional Type (Any Four)?
Utility types in TypeScript are pre-defined generic types that allow you to perform type
transformations and operations. These utility types can help manipulate existing types in a
concise and reusable manner.
1. Partial<T>:
The Partial<T> utility type makes all properties of a given type T optional.
typescript
Copy code
interface Person {
name: string;
age: number;
}
2. Required<T>:
The Required<T> utility type makes all properties of a given type T required.
typescript
Copy code
interface Person {
name: string;
age?: number;
}
3. Readonly<T>:
The Readonly<T> utility type makes all properties of a given type T read-only, meaning they
cannot be reassigned after initialization.
typescript
Copy code
interface Person {
name: string;
age: number;
}
4. Record<K, T>:
The Record<K, T> utility type constructs an object type with keys of type K and values of type
T.
typescript
Copy code
type RolePermissions = Record<string, boolean>;
Decorators in TypeScript are functions that can be applied to classes, methods, properties, or
parameters to modify or extend their behavior. A class decorator is a special kind of decorator
applied to a class constructor to modify its behavior.
@ClassLogger
class MyClass {
constructor() {
[Link]('MyClass instance created.');
}
}
In this example:
The @ClassLogger decorator is applied to MyClass. It logs a message when the class is
created.
This question is similar to the previous one, so the answer is already covered above. However, I
will provide another example of a class decorator for clarity.
@Timestamp
class Event {
constructor(public name: string) {}
}
In this example:
The Timestamp decorator adds a timestamp property to the class, holding the current date
and time when an instance is created.
6. What are Utility Types in TypeScript? Explain Conditional Type (Any Four)?
As mentioned earlier, utility types are predefined types in TypeScript that help manipulate and
transform types. In addition to the commonly used utility types already discussed, conditional
types are a powerful feature in TypeScript that allow you to create types based on conditions.
1. Conditional Types:
Conditional types allow you to create types based on a condition, typically checking if one type
extends another type.
typescript
Copy code
type IsString<T> = T extends string ? 'Yes' : 'No';
2. Extract<T, U>:
The Extract<T, U> utility type extracts types from T that are assignable to U.
typescript
Copy code
type A = string | number | boolean;
type B = Extract<A, string | number>; // 'string | number'
3. Exclude<T, U>:
The Exclude<T, U> utility type removes types from T that are assignable to U.
typescript
Copy code
type A = string | number | boolean;
type B = Exclude<A, boolean>; // 'string | number'
4. NonNullable<T>:
typescript
Copy code
type A = string | number | null | undefined;
type B = NonNullable<A>; // 'string | number'
Summary:
Body parsing in [Link] refers to the process of extracting and parsing the body of incoming
HTTP requests. When a client sends data to the server (e.g., through a POST request), the data is
typically included in the request body. [Link], by default, does not parse the body of requests.
Instead, middleware is used to parse the body content and make it available in the request object
([Link]).
For example, in a JSON payload, body parsing ensures that the data is parsed and converted into
a JavaScript object, making it easy to interact with the data.
In [Link], to send a JSON response, you can use the [Link]() method. This method sends
a JSON-formatted response to the client. It automatically sets the Content-Type header to
application/json and converts the JavaScript object or array into a JSON string.
Example:
javascript
Copy code
[Link]('/data', (req, res) => {
const data = { message: 'Hello, World!' };
[Link](data);
});
In this example, the [Link]() method sends a JSON response containing { message:
'Hello, World!' }.
In [Link], the middleware used to parse JSON request bodies is [Link](). This
middleware is built into Express and is used to automatically parse incoming JSON data in the
request body, making it available as [Link].
Example:
javascript
Copy code
const express = require('express');
const app = express();
Here, the [Link]() middleware parses the incoming request body, and the data is
accessible via [Link].
Lazy loading in Angular is a technique used to load feature modules only when they are needed,
instead of loading all modules at the start of the application. This improves the performance of
the application by reducing the initial load time and only loading the necessary resources when
the user navigates to specific parts of the app.
In Angular, lazy loading is achieved using the loadChildren property in the router
configuration. Instead of importing the module directly, Angular loads the module only when the
route corresponding to that module is accessed.
In this example, the FeatureModule is lazy-loaded when the user navigates to the /feature
route.
Dependency Injection (DI) is a design pattern used in Angular to manage the dependencies of a
class or service. DI allows objects to be provided with their dependencies rather than creating
them internally. In Angular, services, components, and other classes can have their dependencies
injected automatically by the Angular injector.
Example:
typescript
Copy code
@Injectable({
providedIn: 'root'
})
export class MyService {
constructor(private http: HttpClient) {}
}
TypeScript enforces type safety in Angular applications by using static typing. This means that
developers define types for variables, function parameters, and return values at compile time.
TypeScript then checks that the values conform to these types during development and alerts
developers to potential errors before runtime.
For example:
Type annotations: Developers explicitly define types for variables, function parameters, and
return types.
Interface & Class types: TypeScript can enforce the structure of objects using interfaces or class
types.
Generics: TypeScript allows defining generic types for reusable components or functions,
ensuring type safety across different types.
Example:
typescript
Copy code
function greet(name: string): string {
return `Hello, ${name}`;
}
In this example, TypeScript enforces that the argument passed to the greet function must be of
type string.
In [Link], middleware is a function that sits between the request and response cycle. It
processes requests and modifies them (if necessary), executes code, handles errors, or terminates
the request-response cycle. Middleware functions can be used for tasks like logging,
authentication, parsing request bodies, serving static files, and error handling.
Middleware functions can be applied globally or to specific routes. Express provides a simple
API to create and manage middleware functions.
Types of Middleware:
Example of middleware:
javascript
Copy code
const express = require('express');
const app = express();
// A route
[Link]('/', (req, res) => {
[Link]('Hello, World!');
});
[Link](3000, () => {
[Link]('Server running on port 3000');
});
In this example:
4. Explain HTTPS.
5. What is middleware in [Link], and how is it used for request processing and error handling?
10. Explain the role of the event loop and non-blocking I/O in [Link] with examples.
12. Write a NodeJs program that saves a document in Mongodb using mongoose.
Middleware in [Link] is a function that is executed during the lifecycle of a request to the
server. It has access to the request object, response object, and the next function in the
application’s request-response cycle. Middleware functions are used for tasks such as logging,
authentication, request body parsing, and error handling.
Middleware can be applied at the application level, router level, or error-handling level.
Express processes middleware in the order it is declared, so the order of middleware is
important.
Example:
javascript
Copy code
const express = require('express');
const app = express();
// Route
[Link]('/', (req, res) => {
[Link]('Hello, world!');
});
[Link](3000, () => {
[Link]('Server running on port 3000');
});
Advanced routing in [Link] refers to defining more complex and flexible routes that go
beyond basic HTTP methods and paths. It involves handling dynamic routes, route parameters,
and multiple HTTP methods.
Route Parameters: Dynamic values in the URL, which can be accessed via [Link].
javascript
Copy code
[Link]('/user/:id', (req, res) => {
[Link](`User ID: ${[Link]}`);
});
Query Strings: Data passed in the URL after the ?, accessed via [Link].
javascript
Copy code
[Link]('/search', (req, res) => {
const query = [Link].q;
[Link](`Search term: ${query}`);
});
Handling Multiple HTTP Methods: Handling routes for different HTTP methods
(GET, POST, PUT, DELETE).
javascript
Copy code
[Link]('/profile')
.get((req, res) => [Link]('GET Profile'))
.post((req, res) => [Link]('POST Profile'));
Middleware for Specific Routes: Using middleware only for specific routes.
javascript
Copy code
[Link]('/admin', (req, res, next) => {
[Link]('Admin route middleware');
next();
});
Promises: A Promise is an object that represents the eventual completion (or failure) of
an asynchronous operation and its resulting value. A promise can be in one of three
states: pending, resolved (fulfilled), or rejected.
javascript
Copy code
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("Completed"), 1000);
});
Async/Await: Async and Await are syntactic sugar built on top of promises to make
asynchronous code more readable and look like synchronous code. async defines an
asynchronous function, and await pauses the execution of the function until the promise
resolves.
javascript
Copy code
async function fetchData() {
let data = await someAsyncFunction();
[Link](data);
}
The main difference is that async/await provides a more readable and synchronous-like structure
for handling asynchronous operations, while promises can result in more complex code when
multiple asynchronous operations are chained.
4. Explain HTTPS
HTTPS (HyperText Transfer Protocol Secure) is an extension of HTTP. It uses SSL/TLS
encryption to secure data transmission between the client and the server. This ensures data
privacy, integrity, and authentication. HTTPS encrypts HTTP requests and responses to prevent
eavesdropping, tampering, and man-in-the-middle attacks.
SSL/TLS Certificate: A digital certificate that validates the identity of a website and
encrypts the data exchanged between the client and server.
HTTPS Request: A secure connection is established over port 443 using SSL/TLS
protocols, ensuring confidentiality and data integrity.
const options = {
key: [Link]('[Link]'),
cert: [Link]('[Link]')
};
Middleware in [Link] is used to intercept incoming requests, process them (e.g., logging,
authentication), and optionally modify the request/response before it reaches the route handler. It
can also handle errors.
Request processing middleware: Used for tasks like request body parsing,
authentication, logging, etc.
javascript
Copy code
[Link]([Link]()); // Parses incoming JSON requests
Error-handling middleware: These are specifically used for catching and handling
errors in your app. They have four parameters: (err, req, res, next).
javascript
Copy code
[Link]((err, req, res, next) => {
[Link](err);
[Link](500).send('Something went wrong!');
});
6. Explain Body Parsing and Validation Work in [Link]
Body Parsing: In [Link], body parsing refers to the process of converting the raw data in the
body of an HTTP request into a usable format, such as a JSON object or URL-encoded string.
Validation: Validation ensures that the incoming data meets certain criteria before processing.
For this, you can use packages like express-validator or Joi.
// Body parser
[Link]([Link]());
// Validation middleware
[Link]('/user',
body('email').isEmail().normalizeEmail(),
body('age').isInt({ min: 18 }),
(req, res) => {
const errors = validationResult(req);
if (![Link]()) {
return [Link](400).json({ errors: [Link]() });
}
[Link]('User data is valid');
}
);
[Link] uses non-blocking I/O to handle asynchronous operations. Instead of waiting for tasks
like reading files or querying databases to complete, [Link] continues processing other requests
while waiting for these tasks to finish. This is achieved through an event-driven architecture and
the event loop.
When an I/O operation is requested, [Link] delegates it to the system's kernel or thread pool and
continues processing other tasks. When the I/O operation is completed, a callback function is
triggered.
The event loop is a key feature of [Link] that allows it to handle many operations concurrently.
[Link] runs on a single thread, but it can handle multiple asynchronous operations without
blocking the execution of other tasks. The event loop manages the execution of operations and
ensures that the non-blocking I/O operations are handled asynchronously.
Steps in the event loop:
The event loop in [Link] handles multiple requests by processing asynchronous operations (like
database queries, HTTP requests, etc.) one at a time. While [Link] waits for an I/O operation to
complete, it does not block other operations but continues to process other incoming requests.
This is achieved through callbacks, promises, and asynchronous functions.
10. Explain the Role of the Event Loop and Non-blocking I/O in [Link] with
Examples
The event loop and non-blocking I/O allow [Link] to handle concurrent operations without
blocking the main thread. This is crucial for building highly scalable applications that require
handling many I/O operations.
Here, readFile is asynchronous, so [Link] doesn't block the execution of subsequent code
while waiting for the file read operation to finish.
As mentioned earlier, non-blocking I/O in [Link] means that operations like file reading,
database queries, or HTTP requests are handled asynchronously. While the system waits for I/O
to complete, other requests or operations continue to run.
[Link]()
.then(() => [Link]('Document saved successfully'))
.catch(err => [Link]('Error saving document:', err));
These explanations cover key concepts in [Link], [Link], and the workings of non-blocking
I/O, middleware, event loop, and more!
MongoDB Atlas is a fully managed cloud database service for MongoDB. It is hosted and
operated by MongoDB, Inc. and provides automated database management, scaling, security,
and monitoring features. Atlas is designed to help developers deploy, manage, and scale
MongoDB databases on cloud platforms like AWS, Azure, and Google Cloud without having to
manually configure and manage database servers.
With MongoDB Atlas, developers can focus on building applications without worrying about the
operational overhead of managing database infrastructure.
Mongoose is an Object Data Modeling (ODM) library for MongoDB and [Link]. It provides a
schema-based solution to model the data in a MongoDB database, allowing developers to define
the structure of their data, enforce validation, and provide methods for querying and
manipulating the data.
Mongoose helps manage data relationships, query building, and data validation, making
MongoDB easier to work with in a [Link] application.
Schema-based modeling: Defines data structures and validates data before saving.
Middleware: Supports pre- and post-hook middleware to handle asynchronous operations.
Query building: Mongoose provides an easy-to-use query interface for CRUD operations.
Population: Mongoose can reference and populate related data across collections.
const newUser = new User({ name: 'John Doe', email: 'john@[Link]', age:
30 });
[Link]();
The populate() method in Mongoose is used to populate fields in a document with data from
other collections. This is especially useful when working with references between collections.
For example, if a Post has a reference to a User (i.e., a user who created the post), the
populate() method can automatically fetch the associated user data when querying for posts.
The populate() method helps to retrieve and join related data in a more efficient way, without
manually performing multiple queries.
Example:
javascript
Copy code
const mongoose = require('mongoose');
In this example, when querying the Post collection, populate('author') will automatically
replace the author field (which is just an ID) with the full user document.
4. What is Mongoose in MongoDB?
(This question is a duplicate of Question 2, and the explanation is already provided above).
(This question is a duplicate of Question 1, and the explanation is already provided above).
Summary:
MongoDB Atlas is a fully managed cloud database platform for MongoDB that simplifies
deployment, scaling, and management of MongoDB databases.
Mongoose is an ODM library for MongoDB that simplifies data modeling and interaction with
MongoDB in [Link] applications.
The populate() method in Mongoose is used to automatically populate referenced fields in
documents with data from related collections, streamlining complex queries involving
relationships between collections.
This pipeline first filters orders by status, then groups them by customerId and calculates the
total amount per customer, and finally sorts the customers by their total amount.
Schema Validation in Mongoose allows you to define constraints and rules for data before
saving it to the database. You can specify required fields, types, default values, custom
validation, and more.
Middleware in Mongoose are functions that are executed during specific stages of the lifecycle
of a document, such as before saving or after updating. Middleware functions can be used to
perform actions like hashing passwords, logging, or setting default values.
[Link]()
.then(() => [Link]('User saved'))
.catch(err => [Link]('Error saving user:', err));
In this example:
Encryption at Rest: This refers to encrypting data stored on disk (i.e., the data stored in
MongoDB files on disk). It ensures that sensitive data is protected in case the physical
storage media is compromised.
o MongoDB provides encryption at rest through the Encrypted Storage Engine which uses
the Key Management Interoperability Protocol (KMIP) for managing encryption keys.
o Encryption at rest is important to protect data in storage, especially when dealing with
compliance regulations such as HIPAA or GDPR.
Encryption in Transit: This refers to encrypting data while it is being transmitted over
the network (i.e., between the MongoDB client and the database server). It prevents
sensitive data from being exposed during transmission, especially in untrusted networks.
o TLS/SSL is used to encrypt the communication between clients and MongoDB servers.
o Enabling TLS/SSL encryption ensures that all data exchanged between clients and
servers is encrypted, reducing the risk of man-in-the-middle (MITM) attacks.
Both encryption at rest and in transit are essential for securing sensitive data and ensuring
privacy and integrity.
MongoDB stores user credentials in the admin database or the application database.
MongoDB enables you to configure roles for different users and restrict access based on the
principle of least privilege.
(This question is a duplicate of Question 2, which has already been answered above.)
(This question is a duplicate of Question 3, which has already been answered above.)
// Connect to MongoDB
[Link]('mongodb://localhost:27017/mydatabase', {
useNewUrlParser: true,
useUnifiedTopology: true
});
// Define a schema
const documentSchema = new [Link]({
title: String,
content: String
});
In this example:
Summary:
Some common tools used for unit testing in web applications are:
Code splitting is a technique in web development that involves breaking up the codebase into
smaller bundles or chunks that can be loaded on-demand, rather than loading the entire codebase
at once. This helps improve the initial loading time and performance of web applications.
Faster loading times: Only necessary code is loaded when needed, improving the initial
load time.
Efficient use of resources: Non-essential code is only loaded when required.
Improved user experience: Reduces the time users wait for the application to load.
Some common tools for end-to-end (E2E) testing in web applications are:
Cypress: A modern E2E testing framework for web applications, known for its speed and
ease of use.
Selenium: A popular web automation tool for E2E testing, compatible with multiple
browsers and programming languages.
Playwright: A testing framework for automating browsers, similar to Selenium but with
more modern features.
Puppeteer: A [Link] library for automating Chrome and Chromium, often used for E2E
testing.
TestCafe: A framework for E2E testing that doesn’t require browser plugins.
[Link]: A testing framework based on [Link] and Selenium for automating E2E
tests.
Each of these tools is used to simulate user interactions with a web application, testing its overall
functionality from start to finish.
5 Marks Question
1. Define code splitting in web development.
2. Explain the Need for security in Angular and XSS, CSRF prevention
Code splitting is a technique used in web development to improve the performance of web
applications by splitting the large JavaScript codebase into smaller chunks or bundles. These
smaller bundles can then be loaded on demand, rather than loading the entire application upfront.
This method ensures that only the necessary code is loaded for the current page or feature,
improving the initial loading time of the application.
Chunks: The smaller parts that the application is divided into. They can be loaded dynamically
when required.
Lazy Loading: Code splitting often works in conjunction with lazy loading, where chunks are only
loaded when a user interacts with the application (e.g., when navigating to a different page).
Entry Points: These are the parts of the application where code splitting occurs. For example,
routes or features that are loaded only when the user visits them.
Improved Initial Load Time: Since only the necessary code is loaded on startup, the application
loads faster.
Reduced Memory Usage: As only required chunks are loaded, the browser’s memory usage is
optimized.
Better User Experience: Faster load times and responsiveness lead to a better overall user
experience.
javascript
Copy code
// This will split the code into two chunks
const loadComponent = () => import('./Component');
When a user navigates to the specific page or feature, the component will be loaded dynamically.
2. Explain the Need for Security in Angular and XSS, CSRF Prevention
Security is a critical aspect of any web application, especially when it deals with sensitive user
data. Angular, being a popular front-end framework, provides built-in tools and practices to
secure applications. However, developers need to understand and implement various security
measures to protect the application from common web vulnerabilities like Cross-Site Scripting
(XSS) and Cross-Site Request Forgery (CSRF).
Angular provides a secure environment for web development through features like sanitization,
content security policy, and security best practices. However, developers must still be aware
of threats and implement additional measures where necessary to ensure the application's
integrity, protect user data, and maintain trust.
XSS is a vulnerability that occurs when an attacker injects malicious scripts into web pages
viewed by other users. These scripts can steal cookies, session data, or perform actions on behalf
of the user without their consent.
Automatic escaping of data: Angular automatically escapes HTML content to prevent malicious
scripts from executing in templates.
Sanitization: Angular sanitizes potentially dangerous data before rendering it in the browser. It
ensures that HTML, JavaScript, and CSS inserted into the DOM are safe to execute.
For example, Angular uses DomSanitizer to prevent unsafe content from being rendered:
typescript
Copy code
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
In this case, bypassSecurityTrustHtml sanitizes the input and ensures it's safe before
rendering it.
CSRF is an attack where an attacker tricks the user into performing unwanted actions on a web
application where the user is authenticated, like making a purchase or changing account settings.
1. The server generates a CSRF token and stores it in the session or as a cookie.
2. The token is included in each form or AJAX request sent by Angular via an HTTP interceptor.
3. The server checks the CSRF token on incoming requests and validates it before processing.
typescript
Copy code
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler } from
'@angular/common/http';
@Injectable()
export class CsrfInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler) {
// Assuming CSRF token is stored in a cookie or local storage
const csrfToken = [Link]('csrfToken');
return [Link](clonedRequest);
}
}
In this example, the CSRF token is added to the headers of each request using an HTTP
interceptor.
XSS Protection: Angular automatically sanitizes inputs to prevent the execution of malicious
scripts, ensuring that untrusted data is handled safely.
CSRF Protection: CSRF tokens are used to verify that requests are legitimate, ensuring the
authenticity of user actions.
By utilizing Angular's built-in security mechanisms and adhering to best practices, developers
can prevent common attacks like XSS and CSRF, ensuring the safety of their web applications.