Sending HTTP Requests in Angular, What’s the Best Practice?

While working on Angular project, one thing you can never skip is to make HTTP requests to your API server, including GET, POST, PUT, DELETE or even PATCH requests.

My recent project involve one of my colleagues and me, so we split our works and do separately. At the time we integrate our parts together, we surprisingly noticed that we are handling our HTTP requests quite differently. That makes me think about this problem: what’s the best practice of handling HTTP requests in Angular?

To explain the problem, I will use 2 example files, which are list.component.ts and list.service.ts

Some Assumptions

Assume that

  • list.component.ts is an Angular component handling display of a list. The component needs to initiate an HTTP call to the server to get a list and then bind it to the property.
  • list.service.ts is an Angular service contains the definition of HTTP calls.

First Way

Let’s first see my colleagues way of doing it.

list.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.scss']
})
export class ListComponent implements OnInit {
public list: string = []

constructor(
private listService: ListService,
) { }

ngOnInit() {
this.getList();
}

getList() {
this.listService.getList().subscribe(list => this.list = list);
}
}

list.service.ts

1
2
3
4
5
6
7
8
9
10
11
12
@Injectable({
providedIn: 'root'
})
export class ListService {
constructor(
private httpClient: HttpClient
) { }

public getlist(): Observable {
return this.httpClient.get('http://localhost:3000/list');
}
}

His service just contains one method, and the method basically just returns an observable. The logics after the request results are returned, are handled directly as a callback in the subscribe() function.

His method is very straight-forward.

Second Way

Now let’s see my solution.

list.component.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.scss']
})
export class ListComponent implements OnInit {
public list: string = []

constructor(
private listService: ListService,
) { }

ngOnInit() {
this.observeList();

this.listService.getList();
}

observeList() {
listService.observeList().subscribe(list => this.list = list);
}
}

list.service.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Injectable({
providedIn: 'root'
})
export class ListService {
private listSubject: BehaviorSubject = new BehaviorSubject();

constructor(
private httpClient: HttpClient
) { }

public observeList(): Observable {
return this.listSubject.asObservable();
}

public getlist(): Observable {
this.httpClient.get('http://localhost:3000/list').subscribe(resp => this.listSubject.next(resp));
}
}

My solution is less straight-forward since I do not handle the logic right after the http calls. Instead, I let my component observe the subject in the service, and then trigger the HTTP call. Once the result is returned from the HTTP call, the component will observe the changes and then proceed to execute the following logics.

However, my method can store the records in the service. Since a particular service is a unique instance through the angular app lifecycle, I can store those frequently used data in the services.

Another good thing is that, using this approach, the rendering list part does not care when and how the list is fetched. As long as the subject in the service is updated, the changes can be observed by the components.

Comparison

After carefully thinking about the differences between the 2 approaches, I can make a summarisation as below:

Dirct Approach (My colleague’s solution)

  • Much more straight forward
  • Simple implementation
  • Lost records when component re-rendered
  • One call one action, less flexibility

Indirect Approach (My solution)

  • Complicated implementation
  • Store records even if component re-rendered
  • Decouple data call and logic handling after calling. (e.g. HTTP call can be made by other components while the changes are still handled by the current component)

Conclusion

The direct approach is more like a traditional HTTP call handling using Promise. It is straight-forward and easy to understand. Developers can adopt this method if he/she is not familiar with RxJs concepts.

The indirect approach is more sophisticated but more complexed. If this method is adopted, your program structure can be more flexible and maintainable.

This conclude all my thoughts about this matter. If you have a better idea about it, please feel free to share your thoughts with me!