Fetching data from an API using Observables in Angular

I am facing a challenge with an API endpoint that returns an array of strings in JSON format. My goal is to display these contents on a webpage using an Angular Service. Below is the code snippet I have implemented so far (working with Angular 7):

export class FieldService {
  constructor(private httpClient: HttpClient) { }

  fieldTypesURL = 'http://localhost:3000/fields/types';

  public getTypes(): Observable<any[]> {
    return this.httpClient.get<any[]>(this.fieldTypesURL)
    .pipe(map((response: any) => response.json()),
      catchError((error: any) => Observable.throw(error.json().error || 'Server error')));
  }
}

The issue I'm encountering during compilation is as follows:

Type 'Observable<any[]>' is missing the following properties from type 'Promise<string[]>': then, catch, [Symbol.toStringTag], finally

I find it confusing why the error references a Promise when my intention is to utilize an Observable. Any insights on how to resolve this would be greatly appreciated!

Answer №1

While utilizing httpClient, it automatically interprets the response as JSON which means that

.pipe(map((response: any) => response.json())
might be where the issue lies.

In addition, consider changing 'any' to 'string'

Try this out:

public getTypes(): Observable<string[]> {
return this.httpClient.get<string[]>(this.fieldTypesURL)
  .catch((error: any) => Observable.throw(( error && JSON.parse(error).error) || 'Server error')));
}

The .json() method carries out a similar task as illustrated here Angular Response.json() not documented

Answer №2

It was mentioned by @hamzakhan that parsing the response as JSON is not necessary. However, if your code is still not functioning, you may want to try a different approach. I suggest modifying Observable to Observable in the return type of the getTypes() function. Hopefully, this adjustment will solve the issue. Best of luck!

export class FieldService {
  constructor(private httpClient: HttpClient) { }

  fieldTypesURL = 'http://localhost:3000/fields/types';

  public getTypes(): Observable<any> {
    return this.httpClient.get(this.fieldTypesURL)
    .pipe(map((response: any) => console.log(response),
      catchError((error: any) => Observable.throw(( error && JSON.parse(error).error) || 'Server error')));
  }
}

Answer №3

1) Utilizing the httpClient method with a generic parameter takes care of the json conversion and type casting on your behalf.

2) It's worth noting that Observable#throw is now deprecated, so opt for using the throwError operator instead. Remember to handle errors properly and consider defining a specific type for error handling to enhance overall type safety.

3) Always ensure you are invoking your service method correctly...

// field.service.ts
export class FieldService {

  constructor(private httpClient: HttpClient) { }

  fieldTypesURL = 'http://localhost:3000/fields/types';

  public getTypes(): Observable<string[]> {
    return this.httpClient.get<string[]>(this.fieldTypesURL).pipe(
      catchError((r: HttpErrorResponse) => throwError(r.error || 'Server error'))
    );
  }
}
// your.component.ts
export class YourComponent {

  constructor(private fieldService: FieldService){}

  // ... component logic ...

  public types: string[];
  public types$: Observable<string[]>;

  public callService() {

    // An example of a correct invocation
    this.fieldService.getTypes().subscribe(types => this.types = types)

    // Another valid usage with additional observable pipeline operations
    this.types$ = this.fieldService.getTypes().pipe(
      catchError((err: any) => {
        // Error handling at the component level can be implemented here
        return throwError(err);
      }),
      flatMap(types => types),
      filter(type => !!type),
      map(type => type.trim()),
      toArray()
    );

    // Incorrect calls leading to compiler errors
    this.fieldService.getTypes().then(types => /* whatever */);
    this.fieldService.getTypes().catch(err => /* whatever */);
    let r: Promise<string[]> = this.fieldService.getTypes();
  }
}

Hopefully, this provides some clarity and assistance :-)

Answer №4

To handle errors and failed Http requests, simply add catchError(this.handleError) to your code.

export class DataService {
  constructor(private httpClient: HttpClient) { }

  dataURL = 'http://localhost:3000/data';

  public getData(): Observable<any[]> {
    return this.httpClient.get<any[]>(this.dataURL)
    .pipe(
      catchError(this.handleErrors)
    );
  }

  private handleErrors(error: HttpErrorResponse) {

    if (error.error instanceof ErrorEvent) {
      // Handle client-side or network error
      console.log('An error occurred:', error.error.message);
    } else {
      // Handle unsuccessful response code from backend
      console.log(
        `Backend returned code ${error.statusText}, ` +
        `body was: `,error.message);
    }
    // Return observable with user-friendly error message
    return _throw('Something went wrong. Please try again later.');
  };
}

I made a small adjustment by removing .map() from the code since it wasn't necessary for processing the response data.

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

Guidelines for creating a binary release of Node.js with native modules

Currently, I am in the midst of exploring the world of Node.js projects, delving into different bundlers and various other components. One interesting concept that came to mind is the idea of bundling Node.js into a single binary for Linux, macOS, or Windo ...

Difficulty establishing a connection between Typescript and Postgres results in a prolonged

I am attempting to establish a connection to a Postgres database using typescript. For the ORM, I have opted for sequelize-typescript. The issue lies in the fact that the script seems to hang at await sequelize.sync();. Below is the content of the sequeliz ...

Coverage testing is not embracing all aspects

Currently, I am tackling an Angular 2 project and in the process of writing test cases for the services. It's odd that previously everything was working flawlessly, but now I'm encountering some "no provider" errors such as (No provider for AppSe ...

What is the process for obtaining a literal type from a class property when the class is passed as an argument, in order to use it as a computed property

Just a moment ago I posted this question on Stack Overflow, and now I have a follow-up query :) Take a look at this code snippet: import { ClassConstructor } from "class-transformer"; import { useQuery as useApolloQuery } from "@apollo/clie ...

Tips for displaying data by pivoting on a column value within a table using Angular's mat-table feature

I am working with a dataset that resembles the sample data provided below: [{ "testDisplayName": "Test_Name_1", "data": { "metrics": [ { "metricValue": -0.18, ...

What is the Typescript compiler utilized by Visual Studio 2015 when compiling on save?

Currently using Visual Studio 2015 Update 3 with TypeScript 2 for VS installed. I have a basic ASP.NET Core MVC web application with a few simple TypeScript files. The project contains a tsconfig.json file in the root folder with "compileOnSave": true. I ...

Angular2/4 preflight request encountered an invalid response which resulted in a redirect

In my project, I am utilizing angular4 for the frontend and a spring boot application for the backend. The communication between the frontend and BFF (backend for frontend) is done via RESTful requests. When the frontend sends a POST request to the backen ...

Is there a way to access FormArray within a formGroup nested inside another formGroup?

I have a set of data structured like this: [ { id: "1", name: "task1", taskForms: [ { id: "8782", name: "ProcedureComment", sortOrder: null, descr ...

An undefined variable in Angular 2's evaluation

I am currently working with the following code: @ViewChild('MondayPicker') MondayPicker; @ViewChild('TuesdayPicker') TuesdayPicker; @ViewChild('WednesdayPicker') WednesdayPicker; @ViewChild('ThursdayPicker') Thursda ...

What is the best way to remove all validators from a different component in Angular 7 using reactive forms?

I need to find a way to clear all validation in a form group on a sibling component when a boolean value is selected on another component within the same application. Is there a solution for achieving this? We have implemented a method in our application ...

Can TypeScript and JavaScript be integrated into a single React application?

I recently developed an app using JS react, and now I have a TSX file that I want to incorporate into my project. How should I proceed? Can I import the TSX file and interact with it within a JSX file, or do I need to convert my entire app to TSX for eve ...

Is it possible for VSCode to automatically generate callback method scaffolding for TypeScript?

When working in VS + C#, typing += to an event automatically generates the event handler method scaffolding with the correct argument/return types. In TypeScript, is it possible for VS Code to offer similar functionality? For instance, take a look at the ...

Dropdown Pattern with React CTA Modal

While using MaterialUI's ButtonGroup for a dropdown menu, I encountered an issue trying to set up a series of CTAs that are easily interchangeable within it. The goal is to have all components reusable and the choices in the dropdown dynamic. const C ...

Error encountered when trying to access children components in Typescript, even though React.FC is being

I am facing an issue with a child component that has the following structure: interface ChildProps extends AnotherInterface{ route: string, exitAction: ActionCreatorWithoutPayload, } const ChildComponent:FC<ChildProps> = ({title, shape, rout ...

What is the process of extracting an observable from another observable using the pipe method?

Is there a more efficient way to convert an Observable of Observables into an array of Observables in my pipe method? Here is the scenario: // The type of "observables" is Observable<Observable<MyType>[]> const observables = this.http.get<M ...

How to Retrieve Class Variables in Angular 2 Form Validator Function

I'm in the process of creating a modal-driven form with custom validation requirements. Specifically, I want to ensure that the user's password meets certain criteria (including having an uppercase letter, lowercase letter, and number). Instead o ...

I haven't encountered any type warnings in the places where I anticipated them

When I define an object like this: const x: { str: string, num: number } = { str: str, num: not_a_num }; I am surprised to find that even though 'not_a_num' is a string and not a number, the compiler does not throw an error. Instead, ...

The InAppPurchase Plugin in Cordova is throwing the error message "Encountered an error: Cannot access the 'getProducts' property as it is undefined."

Currently, I am utilizing the cordova in-app-purchase plugin for my application. However, I am encountering an error that reads "ERROR TypeError: Cannot read property 'getProducts' of undefined" The .ts file appears as follows: window['plu ...

What is the proper way to send a list as a parameter in a restangular post request

Check out this code snippet I found: assignUserToProject(pid: number, selectedUsers: any, uid: number) { let instance = this; return instance.Restangular.all("configure/assign").one(pid.toString()).one(uid.toString()).post(selectedUsers); } ...

Is there a way to render a component without having to render AppComponent constantly?

I am looking to display two components (AppComponent and UserComponent) without constantly displaying AppComponent. Here's how my code is structured: app.routing.module.ts const routes: Routes = [ { path: '', component: AppComponent ...