Best practices for handling HTTP requests in Angular 5

I'm currently developing multiple applications using Angular 5. My aim is to adhere to all the dos and don'ts of Angular.

However, I'm facing some confusion regarding a few things.

1) What is the difference between this...

this._http.get<User>(this._ubiRest.servicesUrls.getUser)

...and this?

this._http.get(this._ubiRest.servicesUrls.getUser)

If I still have to use the map method to convert it to type User (or maybe not?).

2) In a service, would it be preferable to do this...

getUserData(): Observable<User> {

        return new Observable((observable) => {

            if (!!this._loggedUser) {
                observable.next(this._loggedUser);
                observable.complete();
            }
            else {
                this._http.get(this._ubiRest.servicesUrls.getUser)
                    .map(this._extractData)
                    .subscribe(user => {
                        this._loggedUser = user;
                        observable.next(user);
                        observable.complete();
                    }, this._handleError);
            }

        })
    }

...or this?

getUserDataX(): Observable<User> {
    if (!!this._loggedUser) {
        return new Observable(observable => {
            observable.next(this._loggedUser);
            observable.complete();
        });
    }
    else {
        return this._http.get<User>(this._ubiRest.servicesUrls.getUser)
           .map(this._extractData)
           .catch(this._handleError);
    }
}

Answer №1

It is considered a 'best practice' to utilize Angular 4's HttpClient over Angular 2's Http. The code provided by the original poster appears to be using HttpClient, not Http.

Here's the difference...

If I have to use the map method to cast to type User regardless.

The essence of a generic method lies in its ability to internally apply the generic parameter type. This, in turn, affects the type of observable:

this._http.get<User>(this._ubiRest.servicesUrls.getUser)
.map(user => { /* user has User type */ })

This distinction is clearly outlined in the HttpClient API; where get(...) returns Observable<any> and get<T>(...) returns Observable<T>.

In a service scenario, it would be more beneficial to follow this approach...

However, none of the above options showcase best practices. Utilizing

new Observable(observable => { ... })
represents an antipattern when constructing observables, akin to promise constructor antipatterns. An improved implementation could be:

   if (!!this._loggedUser) {
        return Observable.of(this._loggedUser);
    }
    else {
        return this._http.get<User>(this._ubiRest.servicesUrls.getUser)
       .map(this._extractData)
       .catch(this._handleError);
    }

Answer №2

One issue with Estus' solution is that it may not function properly when there is a "Finally" operator on the other side. After some trial and error, I found a workaround that worked for my situation:

retrieveUserData(): Observable<User> {
      return new Observable(observable => {
            if (!!this._loggedUser) {
                observable.next(this._loggedUser);
                observable.complete();
            }
            else {
                this._http.get<User>(this._ubiRest.servicesUrls.getUser)
                    .retry(2)
                    .map(this._mapUserResponse)
                    .subscribe(x => {
                        console.log("getUserData", x);
                        observable.next(x);
                        observable.complete();
                    }, error => {
                        console.warn("LoggedUserService error: ", error);
                        this._ubiFunctions.showSnackBar({
                            message: error.statusText
                        });
                        observable.error(error);
                    })
            }
      });
}

private _mapUserResponse(rawResponse: User) {
    this._loggedUser = rawResponse;
    return this._loggedUser;
}

my-component.ts

updateUserData():void{
        this._progressDialog.openProgress();
        this._loggedUser.retrieveUserData()["finally"](() => {
             this._progressDialog.closeProgress();
        }).subscribe(data => {
            this.user = data;
            this._router.navigate(['/home']);
            this._ubiFunctions.showSnackBar({
                message: "User loaded successfully"
             });
    });
}

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

Implementing Asynchronous Custom Validators in Angular 4

I've encountered the following code snippet: HTML: <div [class]="new_workflow_row_class" id="new_workflow_row"> <div class="col-sm-6"> <label class="checkmark-container" i18n>New Workflow <input type="che ...

Angular: Check the validity of a date entered by the user depending on the value selected in another date input

I am working on a form with two input fields: InvoiceDate and InvoiceDueDate. My goal is to ensure that the InvoiceDueDate is set at least 30 days after the selected InvoiceDate. Currently, I have implemented validation for the InvoiceDueDate by setting [ ...

The error message "Property 'value' is not present on type 'EventTarget & HTMLSelectElement'" indicates that the 'value' property is not recognized on the Event

Here is the code snippet that I am working with: interface IHandleSelection { (value: string): any | void; } interface IPipeChangeEventValueToFunction { (handler: IHandleSelection): (event: React.ChangeEvent<HTMLSelectElement>) => void; ...

Facing issues with Angular 13 migration: Schema validation encountered errors stating that the data path "/error" needs to be a string

Currently in the process of migrating from Angular 8 to 13 and encountering an issue. I have been following the guidelines outlined on https://update.angular.io/, however, every time I attempt to build certain custom libraries from my application root fold ...

Troubleshooting CORS problem: Angular 2 and AspNetCore WebApi encounter error with preflight response having invalid HTTP status code 401

Hello there! I am currently working on implementing a straightforward token based authentication method in an Angular 2 RC6 application against an AspNetCore WebApi project that I developed using Visual Studio 2015. If you're interested, I have uploa ...

ag-grid provides unique filter options for custom date filtering in Angular 2

Currently, I am attempting to assign new options to a date column field by using the following method. However, these new options are not being displayed in the grid. let dateValues = ["equals", "inRange","quarter1","quarter2","quarter3","quarter4"]; { ...

The Typescript Module augmentation seems to be malfunctioning as it is throwing an error stating that the property 'main' is not found on the type 'PaletteColorOptions'

Recently, I've been working with Material-UI and incorporating a color system across the palette. While everything seems to be running smoothly during runtime, I'm facing a compilation issue. Could someone assist me in resolving the following err ...

Troubleshooting: Angular universal 7 unable to initiate HTTP requests

Recently, I've embarked on the journey of converting my Angular 7.2.0 application into an Angular universal app. The process has been successful in rendering server-side and transferring state swiftly on high-performance PCs and fast internet connecti ...

What is the best way to convert Observable<Observable<{...}>[ ]> to Observable<{...}[ ]>?

I am currently working on merging two observable objects into a single observable to access data from both. These observables represent documents from separate collections in a NoSQL database, specifically a Cloud Firestore database. Both collections have ...

How to selectively make properties optional in Typescript conditions

Currently, I am working on creating a utility type to unwrap nested monads of Options in my code. Here is the progress I have made so far: export interface Option<T> { type: symbol; isSome(): boolean; isNone(): boolean; match<U>(fn: Mat ...

Enhance your TypeScript skills by leveraging types on the call() method in redux-saga

Is there a way to specify the types of a function using call()? Consider this function: export function apiFetch<T>(url: string): Promise<T> { return fetch(url).then(response => { if (!response.ok) throw new Error(r ...

When attempting to access Angular routes directly through a browser, they are not discoverable

After creating routes for /home, /contact, and others, I generated the dist folder using ng build --prod --base-href. I then transferred the contents of the dist folder to my hosting server via FileZilla. While navigating the website normally works fine, w ...

Node C++ Addon Typescript declaration file

I have developed a Node C++ Addon that wraps a class similar to the one outlined in the official Node documentation. By using require(), I am able to access my addon and retrieve the constructor for my class in order to instantiate it. const { MyClass } = ...

The type 'Observable<boolean>' cannot be assigned to type 'Observable<UserRegistration>'

function completeRegistration(email: string, password: string, firstName: string, lastName: string, location: string): Observable<UserDetails> { let body = JSON.stringify({ email, password, firstName, lastName,location }); let headers = new H ...

Angular synchronous observables are designed to provide real-time data

API integration is a crucial part of my process for obtaining information. However, the data retrieval can be inconsistent at times; I may receive all the necessary information, only portions of it, or the data might not be in the correct order. getData(s ...

TS2339: The attribute 'size' is not present on the 'string' data type

Within my Typescript file, I have the following line: return stringToValidate.length <= maxLength; Despite the code executing without issues, an error is displayed: TS2339: Property 'length' does not exist on type 'string'. I am cu ...

Angular 4's OrderBy Directive for Sorting Results

I've been working on implementing a sorting pipe based on the code provided in this resource: The issue I'm facing revolves around handling undefined values within my data. The sorting pipe functions correctly when there are no undefined values ...

Creating mock objects with Jest

I am currently delving into the world of jest testing. Here is a snippet from an implementation class I'm working with: import { ExternalObject } from 'external-library'; export class MyClass { public createInstance(settings : ISettings) ...

What is the best method for implementing Datepicker translations in Angular?

I am looking to incorporate the DatePicker component in Angular, enabling users to select a date that can be translated based on their browser's settings. Any suggestions on how to achieve this? <mat-form-field appearance="fill"> ...

Establish a connection between two ionic and angular applications using a node server

Currently, I am managing two Ionic applications that both interact with the same API hosted on a node server. My goal is to enable one app to send a post request and have the other app receive and utilize the information from that request. I was consider ...