Skip to content

Medium MEAN Stack Interview Questions

95 medium questions with answers. Applied questions that check whether you can use the concepts on real work.

Topics in the medium set

Services, Dependency Injection and Routing: 14 Security, Testing and Deployment: 14 RxJS, Signals and State Management: 13 Angular Forms and HTTP Client: 13 TypeScript and Modern JavaScript: 12 MongoDB Data Modelling and Queries: 12 Node.js and Express APIs: 9 Angular Components and Templates: 8
Solved — mediumStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

Explain the any, unknown and never types in TypeScript.

Save to ▾
Show answer
any switches off type checking, so any operation is allowed and errors move to runtime. unknown also accepts any value but forces you to narrow it with typeof, instanceof or a type guard before using it, making it the safe choice for parsed JSON or caught errors. never represents values that never occur, such as a function that always throws, and is used in exhaustive switch checks.
02

What are generics in TypeScript? Give an Angular-related example.

Save to ▾
Show answer
Generics let you write reusable code that works with many types while keeping type safety, using type parameters like T. For example, an ApiResponse<T> interface can wrap any payload, and a service method get<T>(url: string): Observable<T> returns correctly typed data. Angular's HttpClient.get<User[]>() uses generics so the component knows it receives an array of users, without casting.
03

What are TypeScript utility types such as Partial, Pick, Omit and Record used for?

Save to ▾
Show answer
Utility types transform existing types instead of duplicating them. Partial<User> makes all fields optional, useful for update payloads. Pick<User, 'id' | 'name'> selects fields, and Omit<User, 'password'> removes them, handy for safe API responses. Record<string, number> describes an object map with typed keys and values. Readonly<T> and Required<T> are also common, and they keep frontend and backend models consistent.
04

What is type narrowing and what are type guards?

Save to ▾
Show answer
Narrowing is TypeScript refining a broad type to a more specific one inside a code block based on checks. typeof, instanceof, the in operator, equality checks and discriminated union tags all narrow types. A custom type guard is a function returning a predicate like value is Admin, which tells the compiler the type after the check. This makes handling union types, such as API success or error responses, safe.
05

What do the strict compiler options in tsconfig.json do?

Save to ▾
Show answer
Setting strict to true enables a family of checks, including strictNullChecks, so null and undefined must be handled explicitly; noImplicitAny, which errors on untyped values; strictPropertyInitialization, which requires class fields to be initialised; and strictFunctionTypes. New Angular projects enable strict mode and strict templates by default, which catches many bugs early, though migrating an old non-strict project needs gradual fixes.
06

A teammate uses any everywhere to silence TypeScript errors. How would you address it?

Save to ▾
Show answer
Explain that any hides real bugs and removes autocompletion, then show concrete fixes: proper interfaces for API models, unknown with narrowing for untrusted data, and generics for reusable helpers. Enable the noImplicitAny compiler option and the ESLint no-explicit-any rule as a warning, fix the most critical files first, and add a review guideline. Keep the conversation constructive by pairing on one module together.
07

Write a generic TypeScript function that groups an array of items by a key.

Save to ▾
Show answer
Generics keep the result strongly typed. function groupBy<T, K extends keyof T>(items: T[], key: K): Record<string, T[]> { return items.reduce((acc, item) => { const group = String(item[key]); (acc[group] ||= []).push(item); return acc; }, {} as Record<string, T[]>); } interface Order { id: number; status: string } const byStatus = groupBy<Order, 'status'>(orders, 'status'); K extends keyof T ensures only real property names are accepted.
08

Write a custom type guard to check whether an API response is an error.

Save to ▾
Show answer
A type predicate narrows the union. type ApiError = { error: true; message: string }; type ApiSuccess<T> = { error: false; data: T }; type ApiResult<T> = ApiError | ApiSuccess<T>; function isApiError<T>(res: ApiResult<T>): res is ApiError { return res.error === true; } if (isApiError(result)) { console.error(result.message); } else { render(result.data); } Inside each branch TypeScript knows exactly which fields exist.
09

Write a debounced search helper in TypeScript using a closure.

Save to ▾
Show answer
A typed debounce keeps argument types. function debounce<A extends unknown[]>(fn: (...args: A) => void, ms = 300) { let timer: ReturnType<typeof setTimeout> | undefined; return (...args: A) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); }; } const search = debounce((term: string) => console.log('search', term), 400); search('ang'); In Angular you would usually use the RxJS debounceTime operator instead.
10

Show the tsconfig settings you would enable for a strict Node.js Express API.

Save to ▾
Show answer
A typical strict configuration: { "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "dist", "rootDir": "src", "strict": true, "noUncheckedIndexedAccess": true, "esModuleInterop": true, "skipLibCheck": true, "sourceMap": true }, "include": ["src"] } noUncheckedIndexedAccess adds undefined to indexed lookups, catching missing keys.
11

How do you approach learning a new framework version or language feature on the job?

Save to ▾
Show answer
Situation: our team decided to adopt Angular signals in new features. Task: I had to use them in a sprint while still delivering. Action: I read the official guide, built a small sample, compared it with our RxJS patterns, then implemented one component and asked a senior to review. I shared a short note with examples for the team. Result: my component became the reference pattern for later features.
12

How do you set and enforce TypeScript coding standards across a development team?

Save to ▾
Show answer
Situation: our MEAN team had inconsistent code, with some files strict and others full of any. Task: as a senior developer I was asked to standardise it. Action: I proposed a shared tsconfig with strict mode, ESLint with typescript-eslint rules, Prettier and a pre-commit hook, discussed exceptions with the team, and fixed violations module by module. Result: review comments on style dropped sharply and type-related bugs in QA reduced.
13

What are Angular's lifecycle hooks and when is each typically used?

Save to ▾
Show answer
ngOnChanges runs when input values change. ngOnInit runs once after the first inputs are set, used for initial data loading. ngDoCheck allows custom change detection. ngAfterContentInit and ngAfterViewInit run after projected content and the view are ready, used for DOM access. ngOnDestroy runs before removal, used for cleanup. With signals, effect, computed and DestroyRef often replace several of these hooks.
14

What are directives in Angular and what types exist?

Save to ▾
Show answer
Directives add behaviour to elements. Components are directives with templates. Attribute directives change appearance or behaviour of an existing element, such as ngClass, ngStyle or a custom appHighlight using host bindings. Structural directives change the DOM layout by adding or removing elements, like the older *ngIf and *ngFor, now largely replaced by built-in control flow. Custom directives keep repeated DOM logic out of components.
15

What are pipes in Angular and what is the difference between pure and impure pipes?

Save to ▾
Show answer
Pipes transform values in templates, such as {{ price | currency:'INR' }}, date, uppercase, json and async. A pure pipe, the default, runs only when its input reference or primitive value changes, so it is very efficient. An impure pipe runs on every change detection cycle, which can hurt performance, and is needed only when output depends on mutable data. Prefer pure pipes or computed signals.
16

How does change detection work in Angular, and what does OnPush do?

Save to ▾
Show answer
Change detection checks component bindings and updates the DOM when data changes. Traditionally Zone.js patched async APIs and triggered a check of the whole tree after events, timers and HTTP calls. With ChangeDetectionStrategy.OnPush, a component is checked only when an input reference changes, an event fires inside it, an async pipe emits or a signal it reads changes. OnPush with immutable data greatly reduces work.
17

What are @defer blocks and how do they help performance?

Save to ▾
Show answer
@defer lets you lazy load part of a template and its dependencies only when a trigger occurs, such as on viewport, on interaction, on hover, on idle, on timer or a custom condition with when. Angular automatically splits that code into a separate chunk. You can show @placeholder, @loading and @error blocks. It is ideal for heavy below-the-fold widgets like charts, comments and maps.
18

A product list with 2,000 rows re-renders slowly whenever any data changes. How do you optimise it?

Save to ▾
Show answer
Use @for with a proper track expression, such as track product._id, so Angular reuses DOM nodes instead of recreating them. Switch the component to OnPush and update data immutably or with signals. Replace function calls in templates with computed signals or pure pipes. For very long lists, use virtual scrolling from the Angular CDK and paginate on the server.
19

Create a child component with a signal input and an output that emits when a button is clicked.

Save to ▾
Show answer
The parent passes data in and listens for events. import { Component, input, output } from '@angular/core'; @Component({ selector: 'app-todo-item', template: ` <span>{{ title() }}</span> <button (click)='remove.emit(id())'>Delete</button> ` }) export class TodoItemComponent { id = input.required<number>(); title = input(''); remove = output<number>(); } // parent template // <app-todo-item [id]='t.id' [title]='t.title' (remove)='onRemove($event)' />
20

Write a custom attribute directive that highlights an element on hover.

Save to ▾
Show answer
Host listeners handle the events. import { Directive, ElementRef, HostListener, inject, input } from '@angular/core'; @Directive({ selector: '[appHighlight]' }) export class HighlightDirective { private el = inject(ElementRef); color = input('yellow', { alias: 'appHighlight' }); @HostListener('mouseenter') onEnter() { this.el.nativeElement.style.backgroundColor = this.color(); } @HostListener('mouseleave') onLeave() { this.el.nativeElement.style.backgroundColor = ''; } } // usage: <p appHighlight='lightblue'>Hover me</p>
21

What does providedIn: 'root' mean and what are other ways to provide a service?

Save to ▾
Show answer
providedIn: 'root' registers the service with the application's root injector, so one shared instance exists and it is tree-shakable, meaning it is removed from the bundle if unused. You can also provide services in a component's providers array, giving each component instance its own copy, in a route's providers for a lazy feature, or in app.config.ts. The provider location decides scope and lifetime.
22

What is the inject() function and how does it compare to constructor injection?

Save to ▾
Show answer
inject() retrieves a dependency inside an injection context, such as a field initialiser, constructor, factory or functional guard. It removes long constructor parameter lists, works in plain functions like functional guards, interceptors and resolvers, and makes inheritance simpler because subclasses do not need to pass dependencies to super. Constructor injection still works, but modern Angular code and CLI templates favour inject().
23

What are injection tokens and when do you need them?

Save to ▾
Show answer
An InjectionToken is a unique key for providing values that are not classes, such as configuration objects, API base URLs or feature flags. You create it with new InjectionToken<AppConfig>('APP_CONFIG'), provide it with { provide: APP_CONFIG, useValue: config }, and read it with inject(APP_CONFIG). Other provider types include useClass to swap implementations, useFactory for computed values and useExisting for aliases.
24

How does lazy loading work with the Angular router?

Save to ▾
Show answer
Lazy loading defers downloading a feature's code until the user navigates to it. Use loadComponent: () => import('./admin/admin.component').then(m => m.AdminComponent) for a single component, or loadChildren to load a file of child routes. The CLI builds a separate chunk for each lazy route. You can add preloading strategies like withPreloading(PreloadAllModules) to fetch lazy chunks in the background after startup.
25

What are route guards and what kinds exist in modern Angular?

Save to ▾
Show answer
Guards decide whether navigation can proceed. canActivate checks before entering a route, canActivateChild covers child routes, canDeactivate runs before leaving, often to warn about unsaved changes, and canMatch decides whether a route definition even matches, useful for role-based lazy loading. Modern guards are plain functions using inject(), returning true, false, a UrlTree for redirect, or an Observable or Promise of these.
26

What is a route resolver and when would you use one?

Save to ▾
Show answer
A resolver fetches data before a route activates, so the component receives ready data instead of showing an empty state first. A functional resolver, ResolveFn<Product>, uses inject() to call a service and returns an Observable or Promise. The data is available through ActivatedRoute or bound inputs. Use it for detail pages that are useless without data, but avoid it for slow calls, because navigation waits.
27

Users lose a long half-filled form when they accidentally click a menu link. How would you prevent this?

Save to ▾
Show answer
Add a canDeactivate guard on the form route. The guard checks whether the form is dirty and unsaved through a method or signal on the component, and if so asks the user to confirm leaving with a dialog. Return true to allow or false to stay. Also handle browser refresh and tab close with a beforeunload listener, and consider auto-saving drafts to local storage or the server.
28

Your app must call different API base URLs for development, staging and production. How do you configure this in Angular?

Save to ▾
Show answer
Use environment files such as environment.ts and environment.prod.ts with fileReplacements in angular.json build configurations, or load a config.json at startup with provideAppInitializer so one build works in every environment. Expose the URL through an InjectionToken and inject it in services or an interceptor. Never put secrets in these files, because everything in the Angular bundle is public.
29

Write an injectable service that fetches and caches a list of categories.

Save to ▾
Show answer
Cache the Observable with shareReplay so the API is called once. import { Injectable, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, shareReplay } from 'rxjs'; export interface Category { _id: string; name: string } @Injectable({ providedIn: 'root' }) export class CategoryService { private http = inject(HttpClient); private categories$?: Observable<Category[]>; getAll(): Observable<Category[]> { this.categories$ ??= this.http.get<Category[]>('/api/categories') .pipe(shareReplay({ bufferSize: 1, refCount: false })); return this.categories$; } }
30

Configure routes with lazy loading, a child route and a wildcard 404 route.

Save to ▾
Show answer
app.routes.ts: import { Routes } from '@angular/router'; export const routes: Routes = [ { path: '', loadComponent: () => import('./home/home.component').then(m => m.HomeComponent) }, { path: 'products', loadChildren: () => import('./products/product.routes').then(m => m.PRODUCT_ROUTES) }, { path: 'login', loadComponent: () => import('./auth/login.component').then(m => m.LoginComponent) }, { path: '**', loadComponent: () => import('./not-found.component').then(m => m.NotFoundComponent) } ]; // app.config.ts providers: [provideRouter(routes, withComponentInputBinding())]
31

Write a functional auth guard that redirects unauthenticated users to the login page.

Save to ▾
Show answer
Return a UrlTree to redirect. import { inject } from '@angular/core'; import { CanActivateFn, Router } from '@angular/router'; import { AuthService } from './auth.service'; export const authGuard: CanActivateFn = (route, state) => { const auth = inject(AuthService); const router = inject(Router); return auth.isLoggedIn() ? true : router.createUrlTree(['/login'], { queryParams: { returnUrl: state.url } }); }; // { path: 'orders', canActivate: [authGuard], loadComponent: ... }
32

Provide a configuration object through an InjectionToken and use it in a service.

Save to ▾
Show answer
Tokens carry non-class values. import { InjectionToken, inject, Injectable } from '@angular/core'; export interface AppConfig { apiUrl: string; pageSize: number } export const APP_CONFIG = new InjectionToken<AppConfig>('APP_CONFIG'); // app.config.ts providers: [{ provide: APP_CONFIG, useValue: { apiUrl: environment.apiUrl, pageSize: 20 } }] @Injectable({ providedIn: 'root' }) export class OrderService { private config = inject(APP_CONFIG); private http = inject(HttpClient); list() { return this.http.get(`${this.config.apiUrl}/orders`, { params: { limit: this.config.pageSize } }); } }
33

Tell me about a time you improved the structure of an Angular application.

Save to ▾
Show answer
Situation: our app had one huge shared module and every page loaded everything, so the first load was slow. Task: I proposed restructuring as part of a performance goal. Action: I converted features to standalone components, split them into lazy routes with canMatch guards, moved shared logic into root services and removed dead code. Result: the initial bundle shrank by about 45 percent and new developers found features faster.
34

Describe how you handled a situation where requirements changed late in a sprint.

Save to ▾
Show answer
Situation: two days before release, the client asked to add role-based access to a reporting page. Task: deliver without breaking the release. Action: I clarified the minimum needed with the product owner, implemented a canMatch guard and hid admin actions, and coordinated with the backend developer for API checks, while moving extra filters to the next sprint. Result: we released on time and the client approved the change.
35

What is the difference between a cold and a hot Observable?

Save to ▾
Show answer
A cold Observable starts producing values when each subscriber subscribes, and every subscriber gets its own independent execution; an HttpClient call is cold, so two subscriptions send two requests. A hot Observable produces values regardless of subscribers, and subscribers share the same stream, like mouse events or a websocket. You can make a cold Observable shared with operators like share or shareReplay.
36

What are Subject, BehaviorSubject, ReplaySubject and AsyncSubject?

Save to ▾
Show answer
A Subject is both an Observable and an observer, multicasting values to subscribers but giving late subscribers nothing from the past. BehaviorSubject needs an initial value and gives the latest value to new subscribers, popular for state like the current user. ReplaySubject replays a set number of past values. AsyncSubject emits only the final value on completion. In new code, signals often replace BehaviorSubject for state.
37

How do you avoid memory leaks from subscriptions in Angular?

Save to ▾
Show answer
Prefer the async pipe in templates or toSignal, which subscribe and unsubscribe automatically. For manual subscriptions, use takeUntilDestroyed() from the rxjs-interop package, which completes the stream when the component's DestroyRef fires. HttpClient requests complete on their own, but long-lived streams like intervals, store selectors, router events and websockets must be cleaned up. Avoid nested subscribe calls; use flattening operators instead.
38

How do toSignal and toObservable bridge RxJS and signals?

Save to ▾
Show answer
toSignal(observable$) subscribes to an Observable and exposes its latest value as a signal, unsubscribing automatically when the injection context is destroyed; you can supply an initialValue or requireSync. toObservable(signal) creates an Observable that emits whenever the signal changes, letting you apply RxJS operators like debounceTime and switchMap. Together they let you keep simple state in signals while using RxJS for async logic.
39

Implement a type-ahead search box that calls the API only after the user pauses typing and ignores outdated results. Which RxJS approach would you use?

Save to ▾
Show answer
Take the input stream from a FormControl's valueChanges or toObservable of a signal, then pipe debounceTime(300) to wait for a pause, map to trimmed text, filter out terms shorter than two characters, distinctUntilChanged to skip repeats, and switchMap to call the API, which cancels any in-flight request when a new term arrives. Add catchError inside switchMap so one failed request does not kill the stream.
40

Users double-click the Pay button and two payment requests are sent. How would you prevent it on the frontend?

Save to ▾
Show answer
Disable the button while the request is pending, using an isSubmitting signal. In RxJS, model clicks as a stream and use exhaustMap, which ignores new clicks until the current payment request completes. Show a loading state and handle errors so the button re-enables. The backend must still use idempotency keys, because frontend protection alone cannot stop network retries or duplicate tabs.
41

A dashboard needs data from three independent APIs before it can render. How would you load them?

Save to ▾
Show answer
Use forkJoin to run all three requests in parallel and emit once when all complete, giving an object or array of results. Handle errors per request with catchError returning a fallback value, so one failed widget does not block the whole dashboard. If any source emits repeatedly, use combineLatest instead. With signals, you could use three httpResource instances and a computed for the combined loading state.
42

A component subscribes to a service Observable in ngOnInit, and after navigating back and forth several times, the API is called multiple times per action. What is wrong?

Save to ▾
Show answer
The subscriptions are never cleaned up, so each visit adds another live subscriber that reacts to every emission. Use the async pipe or toSignal in the template, or add takeUntilDestroyed() to manual subscriptions. Also check that the service does not create a new long-lived stream per call and that nested subscribes are replaced with switchMap. Angular DevTools and network logs confirm the fix.
43

Write a type-ahead search using a reactive FormControl and RxJS operators.

Save to ▾
Show answer
switchMap cancels stale requests. export class SearchComponent { private api = inject(ProductService); search = new FormControl('', { nonNullable: true }); results = toSignal( this.search.valueChanges.pipe( debounceTime(300), map((t) => t.trim()), distinctUntilChanged(), filter((t) => t.length >= 2), switchMap((t) => this.api.search(t).pipe(catchError(() => of([])))) ), { initialValue: [] } ); } // template: <input [formControl]='search'> @for (p of results(); track p._id) {...}
44

Load three APIs in parallel with forkJoin and handle a failure in one of them.

Save to ▾
Show answer
Each request gets its own fallback. import { forkJoin, of, catchError } from 'rxjs'; loadDashboard() { return forkJoin({ sales: this.api.getSales().pipe(catchError(() => of(null))), orders: this.api.getRecentOrders().pipe(catchError(() => of([]))), users: this.api.getUserStats().pipe(catchError(() => of(null))) }); } dashboard = toSignal(this.loadDashboard()); // template: @if (dashboard(); as d) { ... d.sales ... } forkJoin emits once, after every inner Observable completes.
45

Write a cart service using signals with computed totals.

Save to ▾
Show answer
Expose read-only state and mutation methods. @Injectable({ providedIn: 'root' }) export class CartService { private items = signal<CartItem[]>([]); readonly cart = this.items.asReadonly(); readonly count = computed(() => this.items().reduce((n, i) => n + i.qty, 0)); readonly total = computed(() => this.items().reduce((s, i) => s + i.qty * i.price, 0)); add(product: Product) { this.items.update((list) => { const found = list.find((i) => i.id === product.id); return found ? list.map((i) => (i.id === product.id ? { ...i, qty: i.qty + 1 } : i)) : [...list, { ...product, qty: 1 }]; }); } remove(id: string) { this.items.update((l) => l.filter((i) => i.id !== id)); } }
46

Tell me about a time you fixed a difficult asynchronous bug.

Save to ▾
Show answer
Situation: users sometimes saw another customer's details after quickly switching between records. Task: find the cause in a busy sprint. Action: I reproduced it with network throttling and found nested subscribes, where slow responses for an earlier id arrived last. I replaced them with switchMap so stale requests were cancelled, and added a test with delayed responses. Result: the bug disappeared and we added a review rule against nested subscribes.
47

Describe a time you helped a teammate who was struggling with RxJS.

Save to ▾
Show answer
Situation: a new teammate kept writing nested subscribes and could not follow our streams. Task: help him become productive quickly. Action: I drew marble diagrams for map, switchMap and combineLatest, paired with him to refactor one of his components, and shared a short list of the operators we use most with examples. Result: within two weeks his pull requests used flattening operators correctly and he started reviewing others.
48

What are typed reactive forms?

Save to ▾
Show answer
Since Angular 14, reactive forms are strongly typed. A FormControl<string> knows its value type, so form.value and getRawValue return typed objects and the compiler catches wrong field names. Controls are nullable by default because reset sets them to null; using nonNullable: true or NonNullableFormBuilder resets to the initial value instead. Typed forms make it safe to map form values directly to API request interfaces.
49

What are async validators and when do you use them?

Save to ▾
Show answer
Async validators return an Observable or Promise of validation errors, used when validity needs a server check, such as whether a username or email is already taken. Angular runs them only after synchronous validators pass, and the control's status is PENDING meanwhile. Use updateOn: 'blur' or debounce inside the validator to avoid a request on every keystroke, and still enforce uniqueness on the backend.
50

What are HTTP interceptors and what are common use cases?

Save to ▾
Show answer
Interceptors sit between HttpClient and the server and can modify every request and response. Modern Angular uses functional interceptors of type HttpInterceptorFn registered through withInterceptors. Common uses are attaching an Authorization header, adding a base URL, showing a global loading indicator, logging, retrying failed requests, refreshing expired tokens and mapping errors to user-friendly messages. Interceptors run in the order they are listed.
51

How should HTTP errors be handled in an Angular application?

Save to ▾
Show answer
Handle them at two levels. A global error interceptor catches HttpErrorResponse, redirects to login on 401, shows a toast for 500 errors and logs details. Component or service code uses catchError to provide fallbacks or show specific messages, such as field errors from a 422 response. Use retry with a delay for transient network failures, and never leave errors unhandled so the UI shows a blank state.
52

What is the difference between valueChanges and statusChanges, and what does updateOn do?

Save to ▾
Show answer
valueChanges is an Observable that emits the new value whenever a control or group changes, useful for dependent fields or type-ahead search. statusChanges emits when validation status changes between VALID, INVALID, PENDING and DISABLED. The updateOn option controls when value and validation update: change by default, blur to validate when the field loses focus, or submit to validate only on form submission.
53

An order form lets users add any number of items with product, quantity and price. How do you build it?

Save to ▾
Show answer
Use a FormArray of FormGroups, each with product, quantity and price controls and validators like min(1). Provide addItem and removeItem methods that push or removeAt on the array, and render rows with @for over items.controls. Calculate the total from valueChanges or a computed signal. On submit, send getRawValue() typed as the order DTO, and disable the submit button while invalid or pending.
54

Users complain that the app shows a blank screen whenever the backend is down. How do you improve this?

Save to ▾
Show answer
Add a global error interceptor that maps network and 5xx errors to a friendly toast or banner, with retry for transient failures. In each data component, handle loading, error and empty states explicitly, using httpResource status signals or catchError with fallback values. Show a retry button, keep cached data visible if available, and log errors to monitoring. A health check banner helps during outages.
55

A form must show fields based on earlier answers, such as company name only when employment type is salaried. How would you build it?

Save to ▾
Show answer
Subscribe to the employment type control's valueChanges, or use a signal, and enable or disable the dependent controls accordingly; disabled controls are excluded from value and validation. Show the fields in the template with @if. For forms driven by configuration, build controls dynamically from a JSON schema into a FormGroup. Remember to clear stale values when a field is hidden.
56

Users upload large documents and want to see upload progress. How do you implement it in Angular?

Save to ▾
Show answer
Send a FormData body with HttpClient post and options reportProgress: true and observe: 'events'. Filter the event stream for HttpEventType.UploadProgress to calculate percent from loaded and total, and for HttpEventType.Response to get the final result. Show a progress bar bound to a signal, allow cancelling by unsubscribing, and validate size and type before upload. For very large files, upload directly to storage with pre-signed URLs.
57

Write a custom validator that rejects passwords without a number and an uppercase letter.

Save to ▾
Show answer
A ValidatorFn returns null or an error map. import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; export function strongPassword(): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { const value = control.value as string; if (!value) return null; const ok = /[A-Z]/.test(value) && /\d/.test(value); return ok ? null : { weakPassword: true }; }; } // password: ['', [Validators.required, strongPassword()]] // @if (form.controls.password.hasError('weakPassword')) { ... }
58

Write a group validator that checks password and confirm password match.

Save to ▾
Show answer
Group validators see all child controls. export const passwordsMatch: ValidatorFn = (group: AbstractControl) => { const pass = group.get('password')?.value; const confirm = group.get('confirm')?.value; return pass && confirm && pass !== confirm ? { passwordMismatch: true } : null; }; form = this.fb.group( { password: ['', Validators.required], confirm: ['', Validators.required] }, { validators: passwordsMatch } ); // @if (form.hasError('passwordMismatch') && form.controls.confirm.touched) { ... }
59

Write a functional HTTP interceptor that adds a JWT and handles 401 errors.

Save to ▾
Show answer
Register with provideHttpClient(withInterceptors([authInterceptor])). export const authInterceptor: HttpInterceptorFn = (req, next) => { const auth = inject(AuthService); const router = inject(Router); const token = auth.token(); const authReq = token ? req.clone({ setHeaders: { Authorization: `Bearer ${token}` } }) : req; return next(authReq).pipe( catchError((err: HttpErrorResponse) => { if (err.status === 401) { auth.logout(); router.navigate(['/login']); } return throwError(() => err); }) ); };
60

Tell me about a complex form you built and the challenges you solved.

Save to ▾
Show answer
Situation: I built a loan application form with five steps and over sixty fields. Task: make it reliable and user friendly. Action: I used typed reactive forms split into step groups, cross-field validators for income rules, a FormArray for co-applicants, auto-saved drafts every thirty seconds and mapped server validation errors back to fields. Result: drop-offs reduced noticeably and QA found very few form bugs.
61

How does the Node.js event loop affect the way you write Express route handlers?

Save to ▾
Show answer
Every request handler runs on the same main thread, so any synchronous heavy work, such as a large loop, JSON parsing of huge payloads, sync file reads or bcrypt with sync methods, blocks all other requests. Write handlers with async I/O, keep CPU work small, stream large data, and offload heavy jobs to worker threads or a queue. Monitor event-loop lag in production to catch blocking code.
62

What is the role of a controller-service-repository structure in an Express API?

Save to ▾
Show answer
Controllers handle HTTP: they read request data, call services and format responses with status codes. Services contain business rules, such as checking stock before creating an order, and are independent of Express. Repositories or models encapsulate database access through Mongoose. This separation makes code easier to test, lets you reuse services in jobs or other transports, and stops route files from turning into large unmaintainable blocks.
63

How do you serve an Angular build and an Express API from the same Node server?

Save to ▾
Show answer
Build Angular with ng build, which outputs static files to dist/project/browser. In Express, register API routes under /api first, then serve the static files with express.static, and finally add a catch-all GET route that returns index.html so Angular routing works on refresh. In larger deployments, Nginx or a CDN usually serves the Angular files while Express handles only the API.
64

How do real-time features work in a MEAN application?

Save to ▾
Show answer
Use WebSockets, commonly through Socket.IO on the Express server and its client library in an Angular service that exposes events as Observables or signals. The server emits events, such as new chat messages or order status changes, to rooms of interested users. For scaling across instances, add a Redis adapter. Server-sent events are a simpler option for one-way updates like notifications or live dashboards.
65

An Express endpoint generates a large PDF report and the whole API slows down while it runs. How do you fix it?

Save to ▾
Show answer
PDF generation is CPU-heavy and blocks the event loop. Move it to a background job: the endpoint creates a job in a queue such as BullMQ with Redis and immediately returns 202 Accepted with a job id. A separate worker generates the PDF, uploads it to storage and updates the job status. Angular polls the status or receives a websocket notification, then downloads the file.
66

Your API needs to send welcome emails and SMS after signup, but this makes signup slow. What would you change?

Save to ▾
Show answer
Do not make the user wait for third-party providers. After saving the user, publish an event or add jobs to a queue and return the response immediately. Workers send the email and SMS with retries and backoff, and failures are logged without affecting signup. An EventEmitter is enough for a quick in-process version, but a persistent queue survives restarts and scales across instances.
67

Your Express API is used by thousands of users and occasionally crashes due to an unhandled promise rejection. How do you make it more resilient?

Save to ▾
Show answer
Find the root cause from logs and fix missing await or catch blocks. Use Express 5, which forwards async errors to error middleware, or an async wrapper in Express 4. Add a central error handler, log unhandledRejection and uncaughtException and then exit cleanly. Run under PM2 or a container orchestrator with multiple instances and health checks so a crash restarts one instance while others keep serving.
68

Write a zod validation middleware for an Express route in TypeScript.

Save to ▾
Show answer
Reusable middleware with typed output. import { z, ZodSchema } from 'zod'; import { RequestHandler } from 'express'; export const validateBody = (schema: ZodSchema): RequestHandler => (req, res, next) => { const parsed = schema.safeParse(req.body); if (!parsed.success) { return res.status(400).json({ errors: parsed.error.flatten().fieldErrors }); } req.body = parsed.data; next(); }; const createOrder = z.object({ items: z.array(z.object({ productId: z.string(), qty: z.number().int().min(1) })).min(1), address: z.string().min(10) }); router.post('/orders', validateBody(createOrder), ordersController.create);
69

Serve the built Angular app and the API from one Express server.

Save to ▾
Show answer
API first, static files next, fallback last. import express from 'express'; import path from 'node:path'; const app = express(); app.use(express.json()); app.use('/api', apiRouter); const dist = path.join(process.cwd(), 'dist/shop/browser'); app.use(express.static(dist, { maxAge: '1y', index: false })); app.get('/*splat', (req, res) => { res.sendFile(path.join(dist, 'index.html')); }); app.listen(process.env.PORT || 3000); The named wildcard follows Express 5 path syntax.
70

How do you use Mongoose with TypeScript?

Save to ▾
Show answer
Define a TypeScript interface for the document, then create a Schema typed with that interface and a model with model<IUser>('User', userSchema). Mongoose infers types for queries, so findById returns a typed document. For lean queries, results are plain typed objects. Schema options like timestamps add createdAt and updatedAt, and you can type instance methods, statics and virtuals through additional generic parameters.
71

What are Mongoose virtuals, instance methods and statics?

Save to ▾
Show answer
Virtuals are computed properties not stored in MongoDB, such as fullName from firstName and lastName, or a virtual populate that links related documents. Instance methods are functions available on each document, like user.comparePassword(). Statics are functions on the model itself, like User.findByEmail(email). Virtuals are excluded from JSON output unless you enable toJSON: { virtuals: true } in schema options.
72

What types of indexes does MongoDB support?

Save to ▾
Show answer
MongoDB supports single-field and compound indexes, multikey indexes for array fields, text indexes for keyword search, geospatial 2dsphere indexes for location queries, hashed indexes for sharding, wildcard indexes for unpredictable fields, TTL indexes that delete documents after a time, and unique, partial and sparse options. Atlas also provides Atlas Search for full-text relevance and Vector Search for AI similarity queries.
73

How does $lookup work in an aggregation pipeline?

Save to ▾
Show answer
$lookup performs a left outer join with another collection in the same database. The basic form matches localField to foreignField and writes matching documents into an array field. The pipeline form lets you add conditions, filtering and projections on the joined collection using let variables. Often you follow it with $unwind to flatten the array. Index the foreign field so the join stays efficient.
74

You are building an e-commerce product catalogue where each category has different attributes, such as size for clothes and RAM for laptops. How would you model it in MongoDB?

Save to ▾
Show answer
Store common fields like name, price, category and stock at the top level, and keep variable specifications in an attributes array of { key, value } pairs, the attribute pattern. Create a compound index on attributes.key and attributes.value so filters work on any attribute. This avoids dozens of sparse fields and lets new categories be added without schema changes, while Mongoose validates the common fields.
75

Users can search products by name, and a regex query has become very slow. What would you do?

Save to ▾
Show answer
A regex without an anchored prefix cannot use a normal index efficiently and scans the collection. For simple word search, create a text index and use $text with a relevance score. For a better search experience with typo tolerance, autocomplete and facets, use Atlas Search or a dedicated search engine. Paginate results, limit fields with projection and debounce requests from the Angular search box.
76

A list API that uses Mongoose populate on three references has become slow. How would you improve it?

Save to ▾
Show answer
Check how many queries populate triggers and how much data each returns. Select only needed fields in populate, use lean(), and add indexes on the referenced fields. If the list always needs a customer name, store it with the extended reference pattern to avoid the join entirely. For complex filtering on related data, switch to one aggregation with $lookup and $project, and paginate.
77

Define a typed Mongoose model in TypeScript with an instance method.

Save to ▾
Show answer
Interface, methods type and schema together. import { Schema, model, Model } from 'mongoose'; import bcrypt from 'bcrypt'; interface IUser { name: string; email: string; password: string; role: 'user' | 'admin' } interface IUserMethods { comparePassword(plain: string): Promise<boolean> } type UserModel = Model<IUser, {}, IUserMethods>; const userSchema = new Schema<IUser, UserModel, IUserMethods>({ name: { type: String, required: true }, email: { type: String, required: true, unique: true, lowercase: true }, password: { type: String, required: true, select: false }, role: { type: String, enum: ['user', 'admin'], default: 'user' } }, { timestamps: true }); userSchema.method('comparePassword', function (plain: string) { return bcrypt.compare(plain, this.password); }); export const User = model<IUser, UserModel>('User', userSchema);
78

Write an aggregation that finds the top five customers by total spend with their names.

Save to ▾
Show answer
Group, sort, limit, then join. db.orders.aggregate([ { $match: { status: 'paid' } }, { $group: { _id: '$customerId', spend: { $sum: '$total' }, orders: { $sum: 1 } } }, { $sort: { spend: -1 } }, { $limit: 5 }, { $lookup: { from: 'users', localField: '_id', foreignField: '_id', as: 'customer' } }, { $unwind: '$customer' }, { $project: { _id: 0, name: '$customer.name', spend: 1, orders: 1 } } ]) Joining after $limit means only five lookups run.
79

Create a text index and run a relevance-sorted search in MongoDB.

Save to ▾
Show answer
Text search with scores: db.articles.createIndex({ title: 'text', body: 'text' }, { weights: { title: 5, body: 1 } }) db.articles.find( { $text: { $search: 'angular signals' } }, { score: { $meta: 'textScore' }, title: 1 } ).sort({ score: { $meta: 'textScore' } }).limit(10) Weights make title matches rank higher. A collection can have only one text index, so include all searchable fields in it.
80

Write mongosh commands to inspect a slow query and the indexes on a collection.

Save to ▾
Show answer
Useful diagnostic commands: db.orders.getIndexes() db.orders.find({ status: 'pending', city: 'Pune' }) .sort({ createdAt: -1 }) .explain('executionStats') db.setProfilingLevel(1, { slowms: 100 }) db.system.profile.find().sort({ ts: -1 }).limit(5) db.orders.createIndex({ status: 1, city: 1, createdAt: -1 }) Compare totalDocsExamined with nReturned before and after creating the index.
81

Tell me about a data modelling decision you made and how it worked out.

Save to ▾
Show answer
Situation: in a learning portal, I first embedded all quiz attempts inside each user document. Task: attempts grew quickly and user loads became slow. Action: I moved attempts to their own collection with an index on userId and quizId, kept a small summary of best scores on the user, and wrote a migration script. Result: profile pages became much faster and reporting queries became simpler.
82

How does Angular protect against cross-site scripting?

Save to ▾
Show answer
Angular treats all values as untrusted by default and sanitises them before inserting into the DOM: interpolation escapes HTML, and binding to innerHTML, styles or URLs is sanitised to strip dangerous content. Bypass methods in DomSanitizer, like bypassSecurityTrustHtml, should be used only for trusted content. Avoid direct DOM manipulation through ElementRef with user data, and add a Content Security Policy for defence in depth.
83

What testing tools are used in Angular projects today?

Save to ▾
Show answer
Angular's CLI has moved to Vitest as the default unit test runner for new projects, replacing the deprecated Karma, while many existing projects still run Karma with Jasmine or have switched to Jest. TestBed configures components and services for tests, HttpTestingController mocks HTTP calls, and component harnesses from the CDK simplify interaction tests. Playwright or Cypress handle end-to-end tests.
84

What is TestBed and how is it used to test an Angular component?

Save to ▾
Show answer
TestBed is Angular's testing utility that creates a test environment similar to the application's. You call TestBed.configureTestingModule with the standalone component in imports and any mock providers, then createComponent to get a ComponentFixture. The fixture gives access to the component instance and its rendered DOM. Call fixture.detectChanges() or await fixture.whenStable() to update the view, then assert on the DOM or component state.
85

How do you test an Angular service that makes HTTP calls?

Save to ▾
Show answer
Provide provideHttpClient() and provideHttpClientTesting() in TestBed, then inject the service and HttpTestingController. Call the service method and subscribe, use httpMock.expectOne('/api/products') to capture the request, assert its method and body, and flush a fake response. Finally call httpMock.verify() to ensure no unexpected requests remain. This tests the service logic without a real backend.
86

How do containers and orchestration fit into deploying a MEAN stack?

Save to ▾
Show answer
Docker packages the Express API and an Nginx image serving the Angular build into portable images with all dependencies. docker compose runs them with MongoDB locally. In production, services like AWS ECS, Azure Container Apps or Kubernetes run multiple replicas, perform rolling updates, restart failed containers and scale on load. Images are built and pushed to a registry by the CI pipeline, tagged by commit.
87

A penetration test report says your API returns other users' invoices when the invoice id is changed. How do you fix it?

Save to ▾
Show answer
This is broken object-level authorization, the top API risk in the OWASP list. Fix every query to scope by the authenticated user, for example Invoice.findOne({ _id: id, userId: req.user.id }), and return 404 when not found. Centralise ownership checks in services or middleware, add tests that try cross-user access, and review similar endpoints. Avoid relying on unguessable ids as protection.
88

An npm audit shows several high-severity vulnerabilities in the Express project. How do you handle it?

Save to ▾
Show answer
Read each advisory to see whether the vulnerable code path is actually used in production or only in dev tooling. Run npm audit fix for safe updates, upgrade direct dependencies that pull vulnerable transitive packages, and use overrides in package.json if a fix is not yet released upstream. Test thoroughly after upgrading, enable Dependabot or Renovate for continuous updates and track any accepted risks.
89

After a new release, a bug affects many users. How do you respond and prevent a repeat?

Save to ▾
Show answer
First limit the impact: roll back to the previous version or disable the feature with a flag, and communicate status to support. Then reproduce the bug, fix it with a test that covers the case, and redeploy through the normal pipeline. Afterwards, run a blameless post-mortem to find gaps, such as missing tests, review or monitoring, and add the actions to the backlog.
90

Write a unit test for an Angular component using TestBed.

Save to ▾
Show answer
Test what the user sees. import { TestBed } from '@angular/core/testing'; import { CounterComponent } from './counter.component'; describe('CounterComponent', () => { it('increments when the button is clicked', async () => { const fixture = TestBed.createComponent(CounterComponent); await fixture.whenStable(); const el: HTMLElement = fixture.nativeElement; el.querySelector('button')!.click(); await fixture.whenStable(); expect(el.querySelector('p')!.textContent).toContain('Count: 1'); }); }); Standalone components need no testing module declarations.
91

Test an Angular service's HTTP call with HttpTestingController.

Save to ▾
Show answer
Capture and flush the request. describe('ProductService', () => { let service: ProductService; let httpMock: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ providers: [provideHttpClient(), provideHttpClientTesting()] }); service = TestBed.inject(ProductService); httpMock = TestBed.inject(HttpTestingController); }); it('fetches products', () => { service.getAll().subscribe((p) => expect(p.length).toBe(1)); const req = httpMock.expectOne('/api/products'); expect(req.request.method).toBe('GET'); req.flush([{ _id: '1', name: 'Pen' }]); httpMock.verify(); }); });
92

Write a multi-stage Dockerfile that builds Angular and serves it with Nginx.

Save to ▾
Show answer
Build in Node, ship only static files. FROM node:22-alpine AS build WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npx ng build --configuration production FROM nginx:alpine COPY nginx.conf /etc/nginx/conf.d/default.conf COPY --from=build /app/dist/shop/browser /usr/share/nginx/html EXPOSE 80 The final image contains no Node.js or source code. nginx.conf should include try_files $uri /index.html for Angular routes.
93

Write an Nginx server block that serves Angular and proxies /api to Node.

Save to ▾
Show answer
One domain, no CORS needed. server { listen 80; server_name shop.example.com; root /usr/share/nginx/html; location /api/ { proxy_pass http://api:3000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { try_files $uri $uri/ /index.html; } location ~* \.(js|css|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; } } Angular hashed file names make long caching safe.
94

Tell me about a time you improved test coverage or quality in a project.

Save to ▾
Show answer
Situation: our MEAN project had almost no tests and every release broke something. Task: I volunteered to improve this. Action: I set up Supertest with an in-memory MongoDB for critical APIs, added component tests for checkout, wrote a short testing guide and made tests required in CI. I started with the five most bug-prone areas. Result: production bugs per release dropped sharply within three months.
95

Walk me through the MEAN project you are most proud of.

Save to ▾
Show answer
Situation: for my final-year project I built a hospital appointment system. Task: let patients book slots and doctors manage schedules. Action: I designed MongoDB collections with indexes for slots, built a TypeScript Express API with JWT and role checks, and an Angular frontend with reactive forms, guards and signals. I added tests and deployed with Docker on a cloud VM. Result: our college clinic used it for a semester.

Frequently asked questions

Who should practise medium MEAN Stack questions?

Anyone with some hands-on practice: most real interview time is spent on medium questions like these.

How should I practise these?

Answer each question aloud before opening the answer, mark it as solved only when your answer matches the key idea, and save misses to Last-Minute Revision.

Other difficulty levels