What is the correct way to wrap an http.get in TypeScript?

My understanding of Typescript is limited, so I have a basic question related to my web application's frontend. In most http get-requests, I need to include two parameters. To simplify this process, I created a simple wrapper for HttpClient (from "angular/common/http") that automatically adds these parameters based on an object passed to it. Here is the current code snippet:

public get<T>(url: string, additionalObj?: AdditionalObject) {
  if (additionalObj == null) {
    return this.http.get<T>(url, {
      headers: {
        "Content-Type": "application/json",
      },
    });
  } else {
    const params: Record<string, string> = {};
    const param1: string | undefined = additionalObj?.param1;
    const param2: string | undefined = additionalObj?.param2;

    if (param1) {
      params["param1"] = param1;
    }
    if (param2) {
      params["param2"] = param2;
    }

    return this.http.get<T>(url, {
      headers: {
        "Content-Type": "application/json",
      },
      params,
    });
  }
}

Although this function works well in most cases, I also need to pass additional parameters in certain scenarios. However, I am unsure how to merge these additional parameters with the existing ones without modifying the functions that call my function. How can I achieve this without impacting the existing code?

Answer №1

It seems like your approach may be a bit complex for your current requirements. Have you considered utilizing Http Interceptors in Angular?

One point of confusion is that you always pass 2 parameters, but the initial condition (additionalObj == null) does not make use of these values. To address this, let's consider three scenarios:

  1. No Parameters provided
  2. Two Parameters supplied
  3. Two Parameters + Extra added

You can streamline this by creating a helper function to extract keys from an object and populate a record, reducing the need for multiple if checks.

GetParams(obj: any, params: Record<string, string>): Record<string, string>{
    for (const p of Object.keys(obj)){
      if(p){
        params[p] = obj[p];
      }
    }
    return params;
}

Now, tweak your wrapper method as follows:

 public get<T>(url: string, additionalObj?: AdditionalObject) {
    if (additionalObj == null) {
      return this.http.get<T>(url, {
        headers: {
          "Content-Type": "application/json",
        },
      });
    } else {
      let params: Record<string, string> = GetParams(additionalObj, {});
    
      return this.http.get<T>(url, {
        headers: {
          "Content-Type": "application/json",
        },
        params,
      });
    }
  }

}

This adjustment maintains functionality while enhancing cleanliness and scalability.

To include extra parameters, you have two choices:

  1. Update the existing properties of AdditionalObject. If modifying the object significantly is impractical, slightly revise the function signature for type safety by including additional parameters in additionalObj.

public get<T>(url: string, additionalObj?: Partial<AdditionalObject>)

  1. Add another object to the function call to handle these properties.

    public get<T>(url: string, additionalObj?: Partial<AdditionalObject>, evenMoreParams?: any) {
    if (additionalObj == null) {
      return this.http.get<T>(url, {
        headers: {
          "Content-Type": "application/json",
        },
      });
    } else {
      let params: Record<string, string> = GetParams(additionalObj, {});
      params = GetParams(evenMoreParams, params);
    
      return this.http.get<T>(url, {
        headers: {
          "Content-Type": "application/json",
        },
        params,
      });
    }
    

    }

    }

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

Is it possible to send requests to multiple APIs using a TypeScript event handler?

I'm facing a challenge in pinging multiple APIs within a single function. It seems like it should be possible, especially since each API shares the same headers and observable. I attempted to write a function for this purpose, but unfortunately, it do ...

Having trouble with customizing a selected ListItemButton in Material-UI - need some help with

After reviewing the documentation, I discovered a method to override the styling of the selected class by introducing a new class under .MuiSelected. The implementation looks something like this: const customStyles = makeStyles(() => ({ customizedSele ...

How to enable Autocomplete popper to expand beyond the menu boundaries in Material UI

Within my Menu component, I have an Autocomplete element. When the Autocomplete is clicked, the dropdown list/Popper appears but it's confined within the Menu parent. How can I make it so that the Autocomplete's dropdown list/Popper isn't re ...

Error Encountered During Angular 2 Protractor End-to-End Testing Runtime

Whenever I try to run protractor, I encounter this error message: [15:47:46] E/launcher - Error: TSError: ? Unable to compile TypeScript Conflicting library definitions for 'selenium-webdriver' found at 'G:/WebServers/home/smsc/SMSC2/module ...

Divide the string into several segments according to its position value

Here is a piece of text that I would like to divide into multiple sections, determined by the offset and length. If you have any questions or comments and would like to get in touch with ABC, please go to our customer support page. Below is a function ...

Is it possible to enforce strict typing for a property within an object that is declared as type 'any'?

In my code, I am dealing with a parent object of type 'any' that remains constant and cannot be changed. Within this context, I need to define a property for the parent object, but no matter what I try, it always ends up being loosely typed as &a ...

What are some tips for integrating AppInsights with Angular?

Trying to integrate AppInsights with Angular has been a bit challenging for me: import { AppInsights } from 'applicationinsights-js'; .... if (!AppInsights.config) { var config: Microsoft.ApplicationInsights.IConfig = { instrumenta ...

Is there an array containing unique DateTime strings?

I am dealing with an Array<object> containing n objects of a specific type. { name: 'random', startDate: '2017-11-10 09:00', endDate: '2017-11-23 11:00' } My goal is to filter this array before rendering the resu ...

Can a mapped union type be created in TypeScript?

Can the features of "mapped types" and "union types" be combined to generate an expression that accepts the specified interface as input: interface AwaActionTypes { CLICKLEFT: 'CL'; CLICKRIGHT: 'CR'; SCROLL: 'S'; ZOOM ...

Whenever I attempt to make changes to the React state, it always ends up getting reset

Currently, I am attempting to utilize Listbox provided by Headless UI in order to create a select dropdown menu for filtering purposes within my application. However, the issue I have encountered is that whenever I update my "selectedMake" state, it revert ...

Ways to remove newly added tasks using JavaScript function?

I have an existing list of li elements in my HTML that can be deleted using JavaScript. However, whenever I add a new li, the delete function no longer works on the newly added item. I suspect the issue lies within the current implementation of the for loo ...

Performing operations on information within a map function

While using toLocaleString within this map, I encountered an issue where only one of the payment.amount's returned formatted as currency. {props.paymentDates.map((payment, index) => ( <tr key={"payment-" + index}> <td>{i ...

What is the process for selectively adding interceptors to app.module?

After searching through various topics, I have not found a solution that addresses my specific issue. To provide some context, we have an Angular App that operates in two modes - one mode uses one API while the other mode utilizes a different API. My goal ...

Refresh Form (Reactive Forms)

This is the HTML code snippet: <div class="container"> <ng-template [ngIf]="userIsAuthenticated"> <form [formGroup]='form' name="test"> <div class="form-group"> <input type="text" class="form-contr ...

Exploring the world of Angular CLI testing and the versatility of

Struggling with integrating Angular CLI's test framework and enum types? When creating an enum like the following (found in someenum.ts): const enum SomeEnum { Val0, Val1 } Utilizing it in this way (in app.component.ts): private someEnum = Some ...

Tips for accessing a specific value within an array of objects using a key

Is there a way to retrieve the value in an object array based on a key that is present within the same array? The structure of the object array is as follows: const objectArray = [ {key: "1", value: "12321"}, {key: "2", value: "asdfas"} ] For ex ...

What is the best way to retrieve the value of the selected mat-option?

I've been struggling to extract the selected value of a mat-option using this specific HTML and TypeScript code. html <mat-form-field appearance="outline" floatLabel="always"> <mat-label>TRA Type</mat-label> ...

Is there a method to indicate not using the watch feature through the command line in TSC?

Is it possible to disable the watch mode in the Typescript compiler cli through command line, instead of relying on the configurations from tsconfig.json? ...

Navigating through template files in Angular 2 components

Currently, I am working on developing a top-level component that requires an input of type @Input(): Object. This object needs to contain an array of components, which will be iterated through using *ngFor, and the templates of these components must be p ...

Best practices for transferring objects between components while navigating routes in Angular

I need some advice on handling a specific component in my project. Here is the code snippet: <div class="animal"> <a routerLink="/animal/{{animal.id}}"> <div> ... </div> </a> </div> This component receives ...