Working with APIs in Angular
Overview
Most web applications feed data into the system and provide an interactive UI to visualize it. This system requires communication with the API server to display data on the HTML page. Generally, web applications make an ajax call to an API server. Whatever data they receive will be displayed on the UI. The same can be done in the Angular framework.
There is a dedicated API developed by Angular Framework for making an ajax call. @angular/http is the API name. Using this, you can make an ajax call with all kinds of methods GET, PUT, POST, DELETE, and UPDATE. Http also provides a way to intercept each request and run code before making a request.
Communicating with the Backend/Server in Angular
As we said, to display the data from the API server. We will fetch the data from the API call. For the same, we would use the HttpClient service. To understand it better, we would try to build something.
Let's build a Post Listing application with the below requirements.
- Show posts listed on the page.
- If clicked on Post, it should redirect to Post details.
- Should have the option to add/edit Post.
Setup HTTPClientModule
To use HttpClient provider for the ajax call, we have to import the HTTPClientModule angular module in the appropriate place.
To set up HttpClientModule
- Import the HttpClientModule dependency in AppModule(root module).
- Inject the HttpClient service inside a constructor.
And then we call API inside a component method. http.get methods return an observable. We can subscribe to the observable returned. Object with next property to the subscribe method. When an API call receives the data, it calls a next property callback.
Note: The http method returns an Observable, we can either subscribe to it or use it as a stream to combine somewhere.
Build a Basic Application
To build an application we would define the components first and then we would link them to their routes via route configuration. We would use JSON placeholder API to get fake data from the API server. JsonPlaceholder is open source built for giving back fake data.
Create Post List component
Create a Post list component using Angular CLI.
Create Post Details component
Create a Post Details component using Angular CLI.
Folder Structure
Create an Interface For Post
Modify Templates
Modify the templates of both components to show dummy HTML with dummy data. Since we want to list down posts one below another, we would use ul > li HTML elements there. On the details page, we would simply populate the details in the input box, so that the user would have the provision to modify the data fields.
post-list.component.ts
Component displaying the list of posts by using the ngFor directive. Maybe in the future, the same data will be populated from API calls. [routerLink]="['/post/details', post.id]" will form an URL to navigate to the post details view by passing post.idthe in anchor tag URL.
Output
post-details.component.ts
Output
Component display post populated from stubbed data. That would be displayed based on the API call passing post Id retrieve from the URL.
Configure Routing
We can define a couple of routes
- For the Post list page
- Another one for the post details page.
The separate component can be loaded from the route configuration. Post is described as a parent route. Under that chil,dren routes are defined, namely list and details. Other than that **(wild card) route is defined as a fallback route to the redireTo to the post/list page when no route is matched.
Service Interacting with Server
Now we will retrieve data from the API server, rather than local stubbed variables. We will be using JSONPlaceholder open source API for Free fake API for testing and prototyping.
We need to create an ApiService that will interact with the backend.
The above command would help us to create a service under the services folder.
service/api.service.ts
Component Using Service Methods
The next step is to add methods to retrieve the needful data in service as a method. First thing, we have to inject the HttpClient service inside your service constructor.
GET Method Call
We would require two GET API calls
- To retrieve the post list
- Single post data
getPosts make sure it gets all posts from the API URL, and the type Post[] is inferred on the returned result. On another hand getPost method single post based on the id passed in the API URL.
Changes in PostListComponent
- Line:16 - Defined posts as [].
- Line:18 - Inject ApiService in the constructor.
- Line:15 - Call the getPosts method, and subscribe to it
- Line:22-24 - Assign posts the to posts variable.
Output Post List
POST Method Call
- Add new button "Add new" button
- Add a new component route.
- Call the apiService addPost method from PostComponent.
post-details.component.ts
Understand the changes made in the post-details component.
- Line:15 - Added ngIf to show the form when the post value is populated.
- Line:16-23 - Add name and ngModel to each input field.
- Line:24 - Added [disabled]="form.invalid" button disable state.
- Line:24 - Added (click)="save()" to add new post.
- Line:45-52 - Assign post and id values conditionally by checking the route id parameter.
- Line:54-61 - Make the addPost API call, and after saving redirect back to the listing page.
PUT Method Call
- Firstly, prepopulate existing Post data based on Id. getPost code added on line 7 when there is no id in the URL.
- Add the updatePost method in ApiService.
- Call updatePost method conditionally.
- Call addPost when id is empty
- Call updatePost when id contains a value.
Handling Errors
There are various techniques to handle errors coming from API calls.
Catch Error in Component
You can catch errors on a component level where you subscribe to the method. Pass the error property inside the subscribe method. It will call the error callback. You can rethrow error if you wanted to handle it on a global level.
Catch Error in Service
You can catch errors on the service method level. Where all callee will get benefit from it. catchError operator can be used to catch errors on observable streams.
If suppose the getPosts API call fails.
- catchError operator will trigger.
- Error logging can be performed here based on the error object.
- Either return a custom object, that will call the next method subscription.
- OR you can rethrow the error object, which leads to calling the error method of subscription.
Global Http Error Handler
The global error handler can be done by applying HttpInterceptor. Yes, the interceptor is the way to go here. Interceptor can be used for various scenarios
- retry two times, if API fails
- auth interceptor
- error interceptor
- HTTP Interceptor.
The above service implements the intercept method where we get access to the request object. We can attach catchError operator to all HTTP call observable streams. If an error occurs then log the error and rethrow it using throwError. This global Http handler would be the best way to place an error logger to log all error logs for HTTP failures.
Add HTTP_INTERCEPTORS in the provider's array, and pass its class implementations, here it's a GlobalHttpInterceptorService with multi true.
Conclusion
- Utilize HttpClient API
- HTTP interceptor use cases
- Error handling when dealing when with HTTP calls on various levels.