DEV Community

Cover image for Angular HTTP calls using Angular Service
Ramanan Balamurugan
Ramanan Balamurugan

Posted on

Angular HTTP calls using Angular Service

Introduction:

Angular is a popular Typescript framework by Google used for building web applications. One of the key features of Angular is its ability to make HTTP calls to retrieve data from a server or send data to a server. In this article, we will explore how to perform HTTP calls using an Angular service in a generic way. We will cover the basic concepts, demonstrate the implementation steps, and provide some practical examples.

Table of Contents:

1. What is Angular Service?
2. Setting up a Angular Http Client
3. Making basic Http request
4. Typed Http request
5. Creating an Angular Service
6. Why service and why to make generic?
7. Http call using service
8. Making it Generic

1. What is Angular Service?

Before we dive into HTTP calls, it's important to understand the role of an Angular service. Services in Angular are used to encapsulate and share functionality across components. They provide a way to centralize common logic, such as making HTTP requests, so that it can be easily reused throughout an application.

2. Setting Up the Angular HTTP Client

To begin making HTTP calls, we need to set up the Angular HTTP client. We'll discuss how to import and configure the HTTP client module in your Angular project.

In app.module.ts

import { NgModule } from '@angular/core';

import { HttpClientModule } from '@angular/common/http';// <-- import HttpClientModule
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    HttpClientModule,         // <-- add it in import section
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

Enter fullscreen mode Exit fullscreen mode

3. Making basic Http request

After the setup done in app.module.ts file we can jump onto the component

// app.component.ts
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-http',
  templateUrl: './http.component.html',
  styleUrls: ['./http.component.scss'],
})
export class HttpComponent implements OnInit {
  constructor(private http: HttpClient) {
  // Basic http GET request
    this.http.get('url to get data').subscribe(
      (res) => {
        console.log(res);
      },
      (err) => {
        console.log(err);
      }
    );
  }

  ngOnInit(): void {}
}
Enter fullscreen mode Exit fullscreen mode

Inside the constructor HttpClient has to be injected to make http calls using http variable that we used to inject.
http provide basic http calls like GET, POST, PUT, DELETE, PATCH. These are the basic http calls we need.

// GET request
this.http.get('url').subscribe();
// POST request
this.http.post('url', { dataToSend }).subscribe();
// PUT request
this.http.put('url', { dataToSend }).subscribe();
// DELETE request
this.http.delete('url', { dataToSend }).subscribe();
// PATCH request
this.http.delete('url').subscribe();
Enter fullscreen mode Exit fullscreen mode

subscribe() you can see that there is a subscribe function is called on every http calls. subscribe function tells browser to make request to the url with data that you've given. To make it simple creating connection using http and opening/ calling the request using subscribe().
It is required to use subscribe function so that we can get response and error back from the server.

this.http.get('url').subscribe(
  (res) => {
    console.log(res);
  },
  (err) => {
    console.log(err);
  }
);
Enter fullscreen mode Exit fullscreen mode

Inside this subscribe it gives two outputs either resultObject when the request is success or errorObject when request is failure. Using those object we can handle things further.

4. Typed Http request

Now comes the magic 🪄 of the typescript. We can even get the result as we expected by annotate the request with type.

// creating type for Post
interface Post {
  userId: number;
  title: string;
  body: string;
}

this.http.get<Post[]>('url').subscribe(
  (res) => {
    console.log(res); // <-- this res will be in the type of Post array
  },
  (err) => {
    console.log(err);
  }
);
Enter fullscreen mode Exit fullscreen mode

Since the above get request in annotated with <Post[]>() the subscribe function result in the type of Post[] so the result will in the type of array of Post object and every object will contain userId, title and body.

This goes to all http request.

5. Creating an Angular Service

We can generate a service in angular by,

ng generate service {your-service-name}
Enter fullscreen mode Exit fullscreen mode

6. Why service and why to make generic?

Service is basically used to reduce the repetition of the code in angular. It can easily injected in any component and can directly access the functions variables inside the service.

Now coming to the main point Why http calls have to be in service and why it has to be a generic service.

  1. http calls are repeated in many places.
  2. Since every object commonly have all GET, PUT, POST, DELETE requests, making it a generic service and inheriting it make our work easier, simpler and cleaner.

7. Http call using service

Using generate command create a service.

// post.service.ts
import { Injectable, EventEmitter } from '@angular/core';
@Injectable({
  providedIn: 'root',
})
export class PostService {

  getPost(id: number): Observable<Post> {
    return this.client.get<Post>(`{apiUrl}/posts/${id}`);
  }

  getPosts(): Observable<Post[]> {
    return this.client.get<Post[]>(`{apiUrl}/posts`);
  }

  putPost(id: number, data: Post): Observable<Post> {
    return this.client.put<Post>(`{apiUrl}/posts/${id}`, data);
  }

  postPost(data: Post): Observable<Post> {
    return this.client.post<Doctor>(`{apiUrl}/posts`, data);
  }

  deletePost(id: number): Observable<Post> {
    return this.client.delete(`{apiUrl}/posts/${id}`);
  }

}
Enter fullscreen mode Exit fullscreen mode

@Injectable tells angular that it is injectable class (i.e) to create a new object of the class.
The class PostService can be injected in any component and the functions like getPost, getPosts, putPost, postPost, deletePost can be used.

// app.component.ts
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { PostService } from './service/post.service.ts'; // <-- import service

@Component({
  selector: 'app-http',
  templateUrl: './http.component.html',
  styleUrls: ['./http.component.scss'],
})
export class HttpComponent implements OnInit {
  constructor(private post: PostService) { // <-- inject the service
  // Basic http GET request
    this.post.getPosts().subscribe( // <-- use it where ever needed
      (res) => {
        console.log(res);
      },
      (err) => {
        console.log(err);
      }
    );
  }

  ngOnInit(): void {}
}
Enter fullscreen mode Exit fullscreen mode

By injecting the service in the component we can access its methods. Since it returns an Observable we need to subscribe it for further computations.

But, the problem is we need to create the same thing for the other objects like Post.

Let's say we need to create a service for Comment. What we need to do is create another service and define everything that we did in post.service.ts. So what we can do is making an abstract Generic service and by inheritance we can easily achieve what we need in easiest way

8. Making it Generic

// generic.service.ts

function createOptions(options: any) {
  if (!options) return '';
  let string = '?';
  Object.keys(options).forEach((key, id, s) => {
    if (s.length == id) string += `${key}=${options[key]}`;
    else string += `${key}=${options[key]}&`;
  });
  return string;
}

export abstract class GenericService<T> {
  private baseUrl = environment.apiUrl;
  constructor(private httpClient: HttpClient, protected apiUrl: string) {}

  public create(resource: Partial<T>): Observable<T> {
    return this.httpClient.post<T>(`${this.baseUrl}${this.apiUrl}`, resource);
  }

  public get(options?: any): Observable<T[]> {
    return this.httpClient.get<T[]>(
      `${this.baseUrl}${this.apiUrl}${createOptions(options)}`
    );
  }

  public getAll(options?: any): Observable<T> {
    return this.httpClient.get<T>(
      `${this.baseUrl}${this.apiUrl}${createOptions(options)}`
    );
  }
  public getById(id: number): Observable<T> {
    return this.httpClient.get<T>(`${this.baseUrl}${this.apiUrl}/${id}`);
  }

  public update(resource: Partial<T>, id: number): Observable<T> {
    return this.httpClient.put<T>(
      `${this.baseUrl}${this.apiUrl}/${id}`,
      resource
    );
  }

  public delete(id: number): Observable<void> {
    return this.httpClient.delete<void>(`${this.baseUrl}${this.apiUrl}/${id}`);
  }
}

Enter fullscreen mode Exit fullscreen mode

By extending this Generic service in every other class we can achieve all the api calls.

// api.service.ts
@Injectable({ providedIn: 'root' })
export class PostService extends GenericService<Post> {
  constructor(private http: HttpClient) {
    super(http, `/posts`);
  }
}

@Injectable({ providedIn: 'root' })
export class CommentService extends GenericService<Comment> {
  constructor(private http: HttpClient) {
    super(http, `/comments`);
  }
}
Enter fullscreen mode Exit fullscreen mode

This PostService and CommentService will provide same functions provided by old service.

By extending this Generic Service we can create as many service we need.

Happy Coding 💻 :).

Top comments (3)

Collapse
 
suresh02 profile image
Suresh Hariharan

Excellent explanation with easily understandable examples..! helped alot..!

Collapse
 
tbalakpm profile image
Balamurugan Thanikachalam

Clearly explained on the topic. Nice post

Collapse
 
priyadharshan_senthil_2e1 profile image
Priyadharshan senthil

Clear cut explanation. Excellent work.
Expecting more blogs like this.