Exploring the Differences between Angular's Http Module and the Fetch API

While I grasp the process Angular uses for HTTP requests, I find myself leaning towards utilizing the Fetch API instead. It eliminates the need to subscribe and unsubscribe just for a single request, making it more straightforward. When I integrated it into my Angular app, there were no errors, the page didn't refresh (which is important for a Single Page Application), and everything functioned smoothly. It seems that each method has its own time and place.

Consider this example:

fetch('/api/get_post_by_id/1').then(response => response.json()).then(data => { console.log(data); });

This approach seems simpler compared to:

const observable = this.http.get('/api');
observable.subscribe(() => { ... });
observable.unsubscribe();

So, my question remains: Is it inappropriate to utilize the Fetch API while working on Angular projects?

Answer №1

Every tool encountered during development comes with its own set of pros and cons, prompting the need to question the rationale behind its usage.

For instance, HttpClient was introduced as a solution to streamline the chaos caused by XMLHttpRequest, much like how $.ajax operated initially. Embracing the concept that everything is an observable, HttpClient brought forth both advantages (such as seamless mixing with other observables) and drawbacks (like added complexity).

Upsides of HttpClient

  • It facilitates effortless integration of two observables, enabling tasks like zipping together a stream-returning observable with a single-response API call. Furthermore, converting a promise into an observable merely requires importing from from rxjs.
  • If you overlook adding an abstraction layer for all requests routed through an apiService, interceptors can be utilized to achieve similar outcomes magically.
  • It steepens the learning curve for budding Angular developers, thereby increasing the uniqueness of your skillset.
  • HttpClient performs certain operations automatically, such as retrying requests.
  • Being inherently embedded in Angular implies there's no need to load a polyfill (unlike with fetch) when catering to outdated browsers like IE11.

Goods about fetch

Note: All references to fetch expect the existence of a basic abstraction (e.g., apiService in this context), mirroring the setup of an interceptor in HttpClient territory.

  • As the contemporary industry norm, familiarity with fetch translates to applicability across various environments (even after eventual obsolescence of frameworks like Angular and React).

  • Interaction with service workers is simplified due to consistent use of Request and Response objects shared with standard code implementations.

  • Typically, HTTP requests yield singular responses (barring exceptional scenarios like chunked file loading), aligning well with the Promise-based nature of fetch. This compatibility extends to leveraging modern language features like async and await.

  • When examining a request statement such as:

    this.apiService.get('/posts');

    any developer, irrespective of their framework background, can easily explore the function definition to discern specifics like domain and authentication headers being appended. Conversely, observing:

    this.http.get('/posts');

    provides limited insights unless versed in Angular peculiarities, contributing to the perceived steep learning curve associated with the framework.

  • This method eliminates hidden functionalities (like automatic request retries) which could cause unintended multiple triggers on the server without explicit awareness.

  • Inclusion within browsers (excluding support for ancient versions) results in marginally smaller bundle sizes compared to external dependencies like with HttpClient.

Neck-and-neck Situation

  • The presence or absence of type distinctions seems inconsequential, given that typing return values from any method is feasible. Example:
    <Model>this.apiService.get('/posts')
    operates smoothly.

Final Thoughts

I personally advocate utilizing fetch alongside an abstraction layer. This choice promotes clearer code readability (even novices unfamiliar with async and await can comprehend it) and empowers adaptation even in rare scenarios necessitating multiple returns from the apiService. Opting for the standard (fetch) makes sense unless alternatives deliver significant benefits. Even if feature parity exists between options, favoring a 'framework-specific' approach may not justify the trade-off.

From my perspective, HttpClient fails to offer substantial perks beyond minor time savings during initial project configuration where setting up an API request abstraction isn't immediately required.

Answer №2

this.http.get('/api').subscribe(j => console.log(j)); 

Don't overcomplicate things, the code above is all you need and it works similarly to using window.fetch. By utilizing the generic version, you can ensure type safety with the expected interface.

this.http.get<IModel>('/api').subscribe(j => console.log(j));

There's no necessity for unsubscribe, only add pipe + map if you want to manipulate the result beforehand. The use of json() was needed with the "old" HttpModule, which has now been replaced by HttpClient from version 4.3 onwards


If you prefer using a Promise rather than an Observable, you can still convert it using toPromise().

this.http.get('/api').toPromise().then(j => console.log(j)); 

For more information, refer to HttpClient


Is it wrong to opt for the Fetch API when working on Angular projects?

Using the Fetch API isn't necessarily wrong, but there are reasons why you may want to avoid it. With HttpClient, you have the ability to write thorough unit tests for various scenarios, URLs, HTTP methods, etc. This becomes challenging if your code extensively relies on window.fetch. Additionally, HttpClient provides type system support for your results and offers advantages like richer features compared to Promises, especially in complex scenarios such as managing multiple microservices or conditional call cancellation with additional user input.

Given these reasons, incorporating HttpClient seems advantageous and I struggle to identify any significant drawbacks apart from a minor learning curve.

Answer №3

After two years of delving into Angular, I have stumbled upon some intriguing discoveries:

  1. One gem that caught my attention is a library called RxJS - https://rxjs-dev.firebaseapp.com/guide/overview, crafted in TypeScript (an extension of JavaScript). It stands out as one of the premier libraries for JavaScript.

In essence, it simplifies event-driven applications in JS through the use of the Observable paradigm. While a Promise can only yield a value once and operates solely asynchronously, Observables have the versatility to return single or multiple values synchronously or asynchronously based on how you employ them. With the ability to incorporate pipes and operators to manipulate results prior to consumption by the subscriber, it imparts a functional programming essence to interactions, which is truly exceptional. The embrace of Observables transcends the limitations of promises, rendering it exceptionally rich in features.

A subscriber engages with an Observable by "subscribing" to it (.subscribe() method on an observable). An Observable emits three types of events: next, error, and complete. 'Next' signifies an event with or without data being emitted, 'error' conveys errors within the event stream, while 'complete' signals the cessation of the event stream with no further emissions from the observable.

To clarify, encountering an error does not halt the event stream; it persists until the completion event occurs. A subscriber has the option to unsubscribe from an observable, effectively discontinuing its monitoring of the event stream.

  1. The HttpClient service within Angular harnesses RxJS at its core. Essentially, it replaces the traditional XmlHttpRequest approach for requesting data – https://github.com/angular/angular/blob/main/packages/common/http/src/xhr.ts#L193.

Upon initiating a request using Angular's HttpClient service, the observable automatically concludes upon receiving an ok response, eliminating the necessity to manually unsubscribe since it completes the lifecycle anyway. Although a complete call isn't triggered on error responses, HTTP calls only emit a single response.

  1. Observables remain dormant until they are subscribed to; in contrast, a Promise executes promptly.

In my perspective, Observables surpass Promises in functionality; the enduring relevance of RxJS indicates that it will likely continue to play a pivotal role in development landscapes.

Answer №4

Unfortunately, I am unable to leave a comment due to my limited access as a new member. Regarding the concept of abstraction, one suggestion is to utilize HttpBackend for the fetch call and simply extend the HttpClient.


import { HttpBackend, HttpClient, HttpEvent, HttpHeaders, HttpRequest, HttpResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, Observer } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class CustomFetchBackend implements HttpBackend {
  handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
    
    if (!('fetch' in window)) {
      throw new Error(
        `This browser does not support Fetch`);
    }

    if (req.method === 'JSONP') {
      throw new Error(
        `Attempting Jsonp request without HttpClientJsonpModule installed.`);
    }

    return new Observable((observer: Observer<HttpEvent<any>>) => {
      const request = new Request(req.urlWithParams, { method: req.method});
      fetch(request)
        .then((r) => {
          r.json().then((body) => {
            const headers = new HttpHeaders();
            r?.headers.forEach((value, name) => {
              headers.append(name, value)
            })
            observer.next(new HttpResponse({
              url: r.url,
              status: r.status,
              statusText: r.statusText,
              body: body,
              headers: headers
            }))
          });
        })

    });
  }
}

@Injectable({
  providedIn: 'root'
})
export class CustomFetchClient extends HttpClient {
  constructor(handler: CustomFetchBackend) {
    super(handler);
  }
}

StackBlitz

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Coloring input fields in Angular Material 2

Changing Angular Material 2 Input Color <md-input-container > <input type="password" md-input placeholder="password"> </md-input-container> I am looking to change the color of the input field when it is clicked. Can anyone provide gu ...

Adjust the background color of child divs when the parent div is being hovered over

I am facing a challenge with my current setup: <div class="parent"> <div class="child"> </div> <div class="child"> </div> <div class="child"> </div> </div> My goal is to change the background co ...

How can we bring in a function into a Vue component?

I'm currently facing an issue with importing a single function into my Vue component. To tackle this problem, I separated the function into its own js file: randomId.js: exports.randomId = () => //My function ... Within my Vue component, I attem ...

What is the proper type declaration for incoming data from the backend in my TypeScript code when using axios?

In the TypeScript code snippet provided, the type for 'e' (used in the function for form submission) has been figured out. However, a question arises if this type declaration is correct. Additionally, in the catch block, the type "any" is used fo ...

Leveraging ngModel within Form Arrays in Angular 4 with ReactiveFormsModule

While working with simple array forms in Angular 4, I encountered an unusual problem with ngModel ...

Utilizing Express Routes to specify React page components

Currently, as I delve into the world of learning Express.js, I find myself faced with a unique scenario involving 2 specific URLs: /security/1 /security/2 As per the requirements of these URLs, the expected response will vary. If the URL is "/securi ...

Exploring TypeAhead functionality in Reactjs 18

I have encountered an issue while using react-bootstrap-typeahead version 5.1.8. The problem arises when I try to utilize the typeahead feature, as it displays an error related to 'name'. Below is my code snippet: import { Typeahead } from " ...

What is the most effective method for incorporating CSS using Javascript to target a specific aria-label attribute?

Is there a way to add a CSS property to a specific tag with a particular aria-label on document load? My goal is to change the flex order of a section to 2. I need help using JavaScript to target the aria-label 'block 1' so I can set the order t ...

Having Trouble Finding Vue Component Definition Using Vite Alias in Import Path

When I click on the Component within the code snippet: import Component from '@/components/Component.vue'; I am unable to navigate to its definition when using vite alias. Seeking a potential solution. ...

Ways to incorporate a dictionary into your website's content

I am in the process of developing a website for educational purposes while also honing my web programming skills. On this website, I have encountered some complicated terms that may be difficult for users to understand, so I want to implement a tooltip/mod ...

Get information collectively in node.js

How can I retrieve 10 records from a MongoDB collection using NodeJs, with each batch containing 10 records? ...

Node-server hosted in Azure experiencing difficulties with websockets connectivity

I have a simple example that works fine on my local machine but fails to work properly when deployed on Azure. The original issue I had related to a CORS error, which I have since resolved by editing it out. However, I am still struggling to get WebSockets ...

A specialized <T> interface, now enhanced with additional functionalities

Looking to create a generic type (with parameter T) that exhibits the following behavior: If K represents a key of T, allow the value type to be either T[K] | ((params?: Partial<T>) => string) If K is not a key of T, allow the value type to be ( ...

Enhancing the accessibility of Material UI Autocomplete through a Custom ListboxComponent

I have developed a custom ListboxComponent for the MUI Autocomplete component in MUI v4. How can I ensure that it meets the necessary accessibility requirements, such as navigating through options using the arrow keys? <Autocomplete ListboxComponent ...

discord.js fails to provide a response

const fs = require('node:fs'); const path = require('node:path'); const { Client, Collection, Events, GatewayIntentBits } = require('discord.js'); const { token } = require('./config.json'); const client = new Clien ...

Can you provide me with instructions on how to create a toggle effect for a button using vanilla JavaScript?

Looking for guidance on creating a toggle effect with a button that switches between 2 images. I've managed to get it working with event listeners on btn2 and btn3, but can't seem to implement the 'toggle' effect on btn1. Any insights o ...

What is the best way to tally the frequency of words in a collection of URLs using JavaScript?

I have a JSON object in WordPress that contains a list of URLs. I would like to determine the frequency of occurrence of the second part of each URL. Currently, the code snippet below is able to extract the remaining part of the URL after the prefix https ...

Unable to find solutions for all parameters in AnalysisComponent: ([object Object], ?, ?, [

As a newcomer to the Angular framework, I encountered an issue when adding project services. Error: Can't resolve all parameters for AnalysisComponent: ([object Object], ?, ?, [object Object], [object Object], [object Object], [object Object], [obj ...

Is there a way to update components in Angular without affecting the current URL?

I want to update a component without changing the URL. For example, I have a component called register. When I visit my website at www.myweb.com, I would like to register by clicking on sign up. How can I display the register component without altering the ...

Assigning a value to an Angular class variable within the subscribe method of an HTTP

Understanding the inner workings of this process has been a challenge for me. I've come across numerous articles that touch on this topic, but they all seem to emphasize the asynchronous nature of setting the class variable only when the callback is t ...