Question

Fix Angular HTTP GET map Is Not a Function with RxJS

typescriptjavascriptangularrxjs

Question

In an Angular 2 application, I want to fetch a JSON list through an HTTP service and display it in a component. The following service calls http.get(...).map(...), but it throws this error:

TypeError: this.http.get(...).map is not a function

How can I make the RxJS map operator available and correctly return parsed JSON from the HTTP request?

import { Injectable } from "angular2/core";
import { Http, Response } from "angular2/http";
import { Hall } from "./hall";

@Injectable()
export class HallService {
  public static PATH: string = "app/backend/";

  constructor(private http: Http) {}

  getHalls() {
    return this.http
      .get(HallService.PATH + "hall.json")
      .map((res: Response) => res.json());
  }
}

The component subscribes to the returned value:

ngOnInit() {
  this._service.getHalls().subscribe((halls: Hall[]) => {
    this.halls = halls;
  });
}

Short Answer

You will learn why an Angular HTTP request returns an RxJS Observable, why .map() may be missing at runtime, and how to import and use the operator correctly in legacy Angular 2 applications. You will also see the equivalent approach for modern Angular.

Concept

Angular 2's legacy Http service returns an RxJS Observable from http.get().

An Observable represents a value that will arrive later, such as an HTTP response. Its value is not available immediately, so you use operators to transform it and subscribe() to receive it.

In older RxJS versions, operators such as map were not always attached to Observable automatically. The TypeScript code can compile, but the browser may still fail at runtime if the module that adds map was never loaded:

.map is not a function

For the old Angular 2 Http API, import the operator for its side effect:

import "rxjs/add/operator/map";

That import extends the Observable prototype with .map(). Then res.json() transforms the legacy Angular Response object into the JavaScript value represented by the JSON response.

This matters because imports affect both:

  • Type information: what TypeScript believes is available.
  • Runtime code: what methods actually exist in the browser.

angular2/http is a legacy API. In modern Angular, use HttpClient from @angular/common/http; it parses JSON automatically and RxJS operators are used inside pipe().

Mental Model

Think of an Observable as a conveyor belt that will deliver a package later.

  • http.get() starts a conveyor belt that will deliver an HTTP Response.
  • map() is a processing station that opens the package and converts its contents with res.json().
  • subscribe() is the receiving desk where your component gets the processed result.

In legacy RxJS, the map processing station is not installed unless you import it. Without that import, calling .map() is like asking for a machine that does not exist on the conveyor belt.

Take Quiz

Syntax and Examples

For Angular 2's legacy Http module, import map before calling the instance method.

import { Injectable } from "angular2/core";
import { Http, Response } from "angular2/http";
import "rxjs/add/operator/map";
import { Observable } from "rxjs/Observable";
import { Hall } from "./hall";

@Injectable()
export class HallService {
  private static readonly PATH = "app/backend/";

  constructor(private http: Http) {}

  getHalls(): Observable<Hall[]> {
    return this.http
      .get(HallService.PATH + "hall.json")
      .map((response: Response) => response.json() as Hall[]);
  }
}

The component subscribes to the transformed Observable:

ngOnInit(): void {
  this._service.getHalls().subscribe((halls: Hall[]) => {
    this.halls = halls;
  });
}

map() does not send a second request. It transforms each response emitted by the Observable.

Modern Angular equivalent

Modern Angular uses HttpClient, which parses JSON by default. RxJS operators use pipe() rather than chained prototype methods.

import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";

@Injectable({ providedIn: "root" })
export class HallService {
  constructor(private http: HttpClient) {}

  getHalls(): Observable<Hall[]> {
    return this.http.get<Hall[]>("/api/halls");
  }
}

Step by Step Execution

Consider this legacy Angular 2 code:

return this.http
  .get("app/backend/hall.json")
  .map((response: Response) => response.json());

Execution proceeds as follows:

  1. getHalls() is called by the component.
  2. this.http.get(...) creates and returns an Observable. At this point, the response has not necessarily arrived.
  3. .map(...) registers a transformation: when a Response arrives, call response.json().
  4. getHalls() returns the transformed Observable to the component.
  5. The component calls .subscribe(...).
  6. Subscribing starts the HTTP request for this cold Observable.
  7. When the server returns hall.json, the HTTP Observable emits a Response.
  8. map() converts that Response to a JavaScript array or object.
  9. The subscription callback receives the parsed value and assigns it to this.halls.

If rxjs/add/operator/map was not imported, step 3 fails immediately because the returned Observable has no .map method.

Real World Use Cases

Observable transformations are useful whenever an HTTP response must be converted before the UI uses it.

  • API response parsing: Convert a response body into Hall[], User[], or a single Order.
  • Data shaping: Convert server field names or nested structures into the shape required by a component.
  • Filtering data: Remove inactive records before displaying a list.
  • Calculating view values: Convert prices, dates, or status codes into display-ready values.
  • Combining requests: In modern RxJS, compose related API requests before updating a screen.

Example transformation in legacy Angular 2:

return this.http
  .get("app/backend/hall.json")
  .map((response: Response) => response.json() as Hall[])
  .map((halls: Hall[]) => halls.filter(hall => hall.isOpen));
Take Quiz

Real Codebase Usage

In production code, services usually expose typed Observables and keep HTTP details out of components.

Keep parsing in the service

getHalls(): Observable<Hall[]> {
  return this.http
    .get("app/backend/hall.json")
    .map((response: Response) => response.json() as Hall[]);
}

The component only handles UI state:

ngOnInit(): void {
  this._service.getHalls().subscribe(
    halls => this.halls = halls,
    error => this.errorMessage = "Could not load halls."
  );
}

Validate data at application boundaries

A TypeScript assertion such as as Hall[] helps the compiler, but it does not validate server data at runtime. Real applications often validate important API data, especially when data comes from external services.

Use modern patterns in current Angular

With HttpClient, request types are declared directly and operators are placed in pipe() when needed:

getOpenHalls(): Observable<Hall[]> {
  return this.http.get<Hall[]>("/api/halls").pipe(
    map(halls => halls.filter(hall => hall.isOpen))
  );
}

A service should generally return the Observable rather than subscribing internally. This lets the calling layer decide when and how to handle loading, success, and errors.

Common Mistakes

Forgetting to import the legacy operator

This causes the error in the question:

// Broken in legacy RxJS if map was not loaded
return this.http.get("app/backend/hall.json").map(res => res.json());

Fix it with:

import "rxjs/add/operator/map";

Importing map using modern RxJS syntax in an old Angular 2 project

This is for modern RxJS and does not add a .map() instance method:

import { map } from "rxjs/operators";

For the legacy chained style, use rxjs/add/operator/map. For current Angular, use pipe(map(...)).

Using Http without registering HTTP providers

In older Angular 2 setups, Http must be configured in application bootstrap providers. Depending on the Angular 2 version, this commonly used HTTP_PROVIDERS or provideHttp.

A missing provider produces a dependency-injection error, not a missing .map() error, but both are common while configuring old projects.

Expecting TypeScript types to validate JSON

.map(response => response.json() as Hall[])

This tells TypeScript how you expect to use the value. It does not prove that hall.json really contains an array with valid Hall properties.

Forgetting error handling

A failed HTTP request does not call the success callback. Handle failures:

this._service.getHalls().subscribe(
  halls => this.halls = halls,
  error => console.error("Loading halls failed", error)
);

Calling response.json() with modern HttpClient

With HttpClient, the emitted value is already parsed JSON. Calling .json() is incorrect:

// Broken with HttpClient
this.http.get<Hall[]>("/api/halls").pipe(
  map(response => response.json())
);

Comparisons

SituationLegacy Angular 2 HttpModern Angular HttpClient
Import pathangular2/http@angular/common/http
Value emitted by GETResponseParsed response body by default
Parse JSONresponse.json()Usually unnecessary
Transform syntax.map(...) after importing an RxJS patch.pipe(map(...))
Operator importimport "rxjs/add/operator/map";import { map } from "rxjs/operators";
Type request resultOften cast after json()http.get<Hall[]>(url)

map() versus subscribe()

MethodPurpose
map()Creates a new Observable whose emitted values are transformed.
subscribe()Receives values and typically starts an HTTP request.

Do not use subscribe() merely to transform data in a service. Return a transformed Observable so consumers can subscribe and handle errors appropriately.

Take Quiz

Cheat Sheet

// Legacy Angular 2 Http: enable the chained map operator
import "rxjs/add/operator/map";

// Legacy Angular 2 Http: parse the Response body
getHalls(): Observable<Hall[]> {
  return this.http
    .get("app/backend/hall.json")
    .map((response: Response) => response.json() as Hall[]);
}
// Component: receive the result
this.service.getHalls().subscribe(
  halls => this.halls = halls,
  error => console.error(error)
);
// Modern Angular HttpClient: JSON is already parsed
getHalls(): Observable<Hall[]> {
  return this.http.get<Hall[]>("/api/halls");
}

Rules to remember:

  • Legacy RxJS instance operators require their rxjs/add/operator/... imports.
  • map() transforms emitted values; it does not manually fetch data.
  • subscribe() receives results and errors.
  • Response.json() belongs to the old Http API, not modern HttpClient.
  • A type assertion does not validate server JSON at runtime.

FAQ

Why does http.get(...).map say it is not a function?

In legacy Angular 2/RxJS, the Observable returned by Http.get() does not receive the .map() method until you load it with import "rxjs/add/operator/map";.

Where should I import rxjs/add/operator/map?

Import it in the service file that calls .map(), or in a shared RxJS setup file loaded before that service. Importing it directly in the service is easiest to understand in a small project.

Does map() parse JSON automatically?

No. In the old Http API, map() runs your function. response.json() inside that function parses the response body.

Should I use angular2/http in a new project?

No. It is a legacy Angular 2 API. Use HttpClient from @angular/common/http in modern Angular applications.

Why does modern Angular use pipe(map(...)) instead of .map(...)?

Modern RxJS uses pipeable operators. This avoids modifying the Observable prototype and makes dependencies more explicit.

Does subscribing in a component trigger the HTTP request?

For standard Angular HTTP Observables, yes. The request is typically made when a consumer subscribes.

Is as Hall[] enough to ensure my API returned valid halls?

No. It only informs TypeScript about the expected type. It does not inspect or validate the actual JSON data at runtime.

Take Quiz

Mini Project

Description

Build a small legacy Angular 2 data service that loads a list of halls from a JSON file. The project demonstrates the missing piece behind the runtime error: loading the RxJS map operator before using chained Observable methods.

Goal

Fetch hall.json, transform the legacy HTTP response into a Hall[], and display the hall names after subscribing.

Requirements

Requirement list is provided below.

Take Quiz

Keep learning

Related questions

View more