How to make API requests with Angular

Making API requests is a day-to-day task of a developer, depending on the technology we're working with on the client, that task may vary a little (or a lot). In this article, we'll learn how to perform the such task with Angular.

If you want to code along with this example, make sure to have installed Node.js and the Angular CLI.

Let's create a new Angular project by typing:

ng new http-request

As we'll not deal with routing or CSS, it doesn't matter what option we choose for the following prompted questions.

Once bootstrapped the Angular app, we change the directory into the created project folder http-request and we'll start by generating a new service with the Angular CLI:

ng generate service services/pokemon

Nothing is stopping us from making the API calls in an Angular component, but we should abide by the good practices by creating a service layer.

Unlike components whose main purpose are rendering the UI, services are generally used to perform another kind of tasks such as data fetching or database connection. With those services, we can deliver the result to single or multiple components through dependency injection.

Once we create our service, we should add it to our main app module. So at app.module.ts, import HttpClientModule from @angular/common/http package and add it to the imports array.

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [AppComponent, CardComponent],
  imports: [BrowserModule, AppRoutingModule, HttpClientModule],
  providers: [],
  bootstrap: [AppComponent],
})

Then in the newly created service file, we must add HttpClient as a dependency injection in the Class constructor. We'll be using the pokéAPI endpoint to create our HTTP request. Here I created a simple Pokemon type only to avoid any 😆:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

export type Pokemon = {
  name: string;
  types: {
    type: {
      name: string;
    };
  }[];
};

@Injectable({
  providedIn: 'root',
})
export class PokemonService {
  private baseURL: string = 'https://pokeapi.co/api/v2/pokemon/';

  constructor(private http: HttpClient) {}

  getPokemon(pokemon: string): Observable<Pokemon> {
    return this.http.get<Pokemon>(this.baseURL + pokemon);
  }
}

Notice the getPokemon(pokemon: string) Class method. It is in this method that return an Observable that we make the GET request. We concatenate the API endpoint with the pokemon name (or id) we're trying to fetch.

If we try to log the return value from the http.get() method we should see an Observable, this is something that reminds a javascript promise.

To handle this Observable we should subscribe to it in the component we want to access the API response. And we'll do this in its ngOnInit() lifecycle method.

Ok, now our service is ready to be consumed by our component. So I'll create simple steps to showcase how we'll be doing this:

  • Import the newly created service to the component;
import { PokemonService } from 'src/app/services/pokemon.service';
  • Add it to the constructor as a dependency injection;
constructor(private service: PokemonService) {}
  • Create a new Class attribute to wrap the API response;
pokemon: Pokemon = {
    name: '',
    types: [
      {
        type: {
          name: '',
        },
      },
    ],
  };
  • Subscribe to the service in the lifecycle ngOnInit() hook to make the request as soon as the component mounts and pass the data to the Class attribute we just created. Where you will call the service is up to you, here I chose to call it the ngOnInit() hook.
ngOnInit(): void {
    this.service.getPokemon('pikachu').subscribe({
      next: (res) => {
        this.pokemon = {
          name: res.name,
          types: res.types,
        };
      },
      error: (err) => console.log(err),
    });
  }

And voilà, now you should get the Pokemon name and its types you just requested and display it on your component template by binding it.

<p>{{pokemon.name}}</p>
<ul>
    <li *ngFor="let item of pokemon.types">{{item.type.name}}</li>
</ul>