Beginners Guide to Using HttpClient in Angular

The HttpClient is an Angular module that allows your application to communicate with backend services over the HTTP protocol. You can perform all HTTP requests including GET, POST, PUT, PATCH and DELETE. You can also modify headers to insert authorization parameters, or to specify the type of content your application needs, e.g., JSON, XML e.t.c.

The module also provides features such as testability, typed request and response objects, interception, Observable APIs and error handling. If you are wondering what all those terms mean, don't worry. We'll cover them in this chapter. To use HttpClient in your application, you'll need to activate it in the project's root AppModule. Here is an example:

What will we build?

In the project we are going to build, we are going to explore how to use Angular's 6 HttpClient module. We'll use Semantic UI CSS Framework to build the view layouts, and a free online JSON server as our backend. Later, we'll install a local JSON Server on our machine and use it in our project.

Example Code

You can find the full source code for the project on GitHub. You can also check out the live code of the project on StackBlitz. The following link will take you straight to the live demo of the application.

Before we start working on the project, we'll need to look at a couple of technologies that we'll use to build the application.

RxJS Library

RxJS stands for Reactive Extensions Library for JavaScript.

Why do we need this?

Well, about 20 years ago, the Internet had about 280 million users. The web technology used at that time was quite capable of handling the traffic then.

Fast forward to 2018. We now have over 4 billion Internet users. Facebook alone deals with 2 billion active users per month. That's like the entire Internet of 2010. Dealing with such massive traffic requires spreading our application across multiple servers. The problem with that is that each server is manipulating data concurrently. This makes it difficult to ensure data remains consistent among all servers at any given time. Definitely, new technology is needed to solve modern problems.

Today, we have what is known as Reactive Programming, also known as Reactive Architecture. The goal of this technology to help developers build applications that are responsive, resilient, scalable and message-driven.

As an Angular developer, you have access to this technology via the open-source RxJS library. This comes already shipped in your project. You don't have to install anything. This means you can easily build an application that is easy to scale and will remain consistent whether traffic is high or low.

Reactive programming is a comprehensive topic that needs a chapter of its own. For the sake of clarity, I'll just mention only the RxJS classes and operators that we'll use to build the application.

Observable

An Observable is a class that provides support for passing data between publishers and subscribers in an application. It provides additional benefits over techniques such as Promises. Observables allow you to synchronously or asynchronously receive data from an HTTP response, keystroke, interval timer or an event listener. When you subscribe to an observable, the function responsible for fetching or pushing data gets executed. When the function completes, the subscriber gets a notification which can either be a success or a fail.

Pipe

A pipe is a class that takes input data and transforms it into the desired output. In our case, we'll pipe received data through an error handler. We can also call a retry() operation within a pipe to deal with network interruptions. Here is an example:

Take note that retry() is placed before the error handler.

Tap

This is a mechanism for wiretapping data passing through an Observable without causing a disturbance. It's often used for logging.

Error Operators

We have two operators that can help us manage errors that may be caused either by network interruptions or the server rejecting the request. These operators are:

  • catchError - we'll use this to call our custom error handler
  • throwError - we'll use this to pass a custom error message to the view

That's enough RxJS for now. You can check out their reference API page for a complete list.

Semantic UI CSS Framework

We'll use Semantic UI to style our app with minimal effort. We'll also use an Angular version of the framework, ng2-semantic-ui, to make the site interactive. Below is the documentation for the elements we'll use. Do read the documentation to familiarize yourself before we get started.

  • Container : Restricts width of page elements based on screen size
  • Segment : Groups related elements
  • Header : Styling for page headers, content headers, sub headers e.t.c
  • Menu : Navigation bar styling
  • Loader : Displays Loading animation
  • sui-dimmer : Dims page when loading
  • sui-message : Styling for info, warning and error messages
  • Table : Styling for responsive html table
  • sui-pagination : Table pagination controls
  • Form : Styling for html form

Take note that elements starting with sui are Angular versions. The rest are just CSS styling.

Project Setup

You'll need a recent version of NodeJS. It doesn't have to be the latest, but you should at least have version 6.9.0 or higher. The npm version also needs to be at least v3 or higher. In my case, am using Node v8.11, and npm v5.6.0. Once you've confirmed your Node environment meets the minimum specifications, proceed with installing or updating the following global packages:

Next, let's set up the project and install semantic-ui.

Open src/index.html and add this line in the <head> section:

Open src/app.module.ts and add the following lines at the correct positions:

Feel free to update the title as well. Let's now fire up the application to confirm everything is working.

Give the compilation process a moment to finish. Once it's ready, you should be able to access the app at localhost:4200

ng-serve

Generate Components and Routes

Next, we'll generate the necessary components required for our project. You'll need to stop the server to proceed with this task.

Let's now set up routes. The PostForm component will be shared by the CREATE and EDIT routes. Open app.module.ts and insert the following code at the correct locations:

Open app.component.html and delete all existing code. Replace it with this one which contains a Navigation menu:

Fire up ng serve. The browser should now have the following output:

ng-routes

Click on Create Posts menu to ensure it works. It should output 'post-form works!'. Let's now proceed to the next step.

Display List of Posts

As mentioned earlier, we'll be using a free online JSON server. We'll use the route https://jsonplaceholder.typicode.com/posts to access posts JSON data. Here is a small sample:

First, we are going to need a Post model to encapsulate the json structure. Simply create the folder models under src/app directory. Then create the file post.model.ts inside the folder. Copy the following code:

We are creating a class instead of an interface since we'll need to instantiate it when we want to create a new post.

Next, we'll need a Http Client service that will fetch data from the JSON site for our app. First, close the running server with Ctrl+C and generate the service like this:

The file post.service.ts will be created for you. Insert the following code in the right location:

Next, we need to enable the HttpClientModule module in app.module.ts for our service to work. Simply copy the following code in the right sections:

Next, we need to update the PostList component to perform the following actions:

  • Perform a GET request via PostService
  • Paginate the data
  • Display the data on a table

Let's start with the post-list.component.ts. We're going to setup a paginated table that will list 10 records at a time. When we perform the GET /posts request, the application will receive 100 records which will be assigned to the variable allPosts. Using simple logic, we'll split this data into multiple pages each holding a maximum of 10 records. Update the code as follows:

Now overwrite the contents of post-list.component.html with this code. This will create a view of the paginated table that the user can interact with.

Start the server and check the browser. You should have the following view:

post-list

Do click the pagination buttons to ensure everything works as expected. Next, we'll add some error handling code.

Error Handling

Now that we have PostList working, we need to write some error handling code. A couple of things can go wrong with the PostList component:

  1. Network interruption
  2. Server sends an error response i.e. 404, 500

Currently, if either of the two happens, our application will continue to display the spinning icon forever with no indication to the user that something has gone wrong. To fix this, open post.service.ts and update the code as follows:

Now our service is capable of handling errors. The handleError function simply constructs a custom error message which it sends back to the view layer. We need to update our HTML to display this error message. First update post.list.component.ts:

Next, add an element to display an error message in post.list.component.html. Place this section above the table tag.

Now let's test our error handling code. You can either change the URL in post.service to something incorrect or simply disconnect from the internet. Refresh the page and see if you get an error message:

error-handling

You should get a similar error message. Now, fix the problem you just simulated and move on to the next section.

Display Single Post

Let's now work on displaying a single post. Start with adding a getPost() function to post.service.ts. Place this method below the getPosts() function:

Next, update the code in post-view.component.ts in the relevant sections as follows:

The way PostView works is that it expects a URL in the format post/{id}. The id is extracted from the URL and is used to call the getPost(id) function we defined in post.service.ts. If a post is found, it gets displayed. Otherwise, an error message is displayed if the post is not found. Let's replace the code in post-view.component.html first before we test the new code:

If you look back at post-list.component.html, you'll notice that the column title is made up of hyperlinks. The cell code looks like this:

This link will take us to the post-view component page. Now refresh the page and click on any title. You should be taken to a view like this:

post-view

Try entering a non-existent id in the URL such as: http://localhost:4200/post/500. An error message should get displayed. However, it's a little cryptic for casual end users. You can customize the post.service error handling code in order to send a simpler error message. You can use the following error status codes to determine an appropriate error message.

  • 404 : Post not found
  • Unknown error : Network interruption
  • 500: Server error

Now let's take a look at how we can Create, Update and Delete posts.

Create Post Form

In order to use forms in Angular, we need to activate the FormsModule in app.module.ts:

Now we're ready to build Angular forms. The Create, Update and Delete features will all be implemented within the PostForm component and the PostService class. Let's start by updating the HTML file first. Open post-form.component.html and replace the existing code with this:

We are using Template-driven forms. Validation is enforced by disabling the submit button and only enabling it when the form is valid. An error message will appear in case something goes wrong on the service end. This form is designed to handle both Create and Update operations. Let's look at how post-form.component.ts handles both situations. Update the code as follows:

There are two ways this form is displayed to the user. If you look at the PostList table, we have a column called edit. It's cell code looks like this:

Clicking on any of the edit links will take you to PostForm. An id is passed via the URL which is then extracted and used to fetch a post. The fetched post is then loaded on the form ready for editing. The submit button text changes to Update letting the user know that they can update the existing record. The second way of accessing this form is through the Create Post menu link at the bottom. Since no id is supplied, a new Post instance is created and a blank form is loaded. The submit text button changes to Create letting the user know that they can Create a new record.

Now you may notice you may have some errors in your code due to non-existent functions in post-service.ts. Let's go ahead and fix that. Open the file and update the code accordingly:

The service code is simple and self-explanatory. For Update and Delete functions, an id has to be passed to the backend service via the url. Now everything should work properly. Try the following:

  • Create a new post
  • Update an existing post
  • Delete an existing post
  • Simulate an error condition e.g. not passing an id for the update function

post-edit-form

The Create, Update, Delete operations should sort of work. The reason am saying sort of is because the backend server is actually returning fake responses to those requests. Nothing has actually changed. Later, we'll set up a local JSON server where actual changes will occur when we make those requests. First, let's look at interceptors.

Interceptors - Logging

HTTP Interceptors allow developers to inspect and transform HTTP requests and responses passing between the application and the server. Interception can occur in both directions. Common use cases of interception include authentication, logging and cache manipulation.In this chapter, we'll take a look at implementing interceptors for logging and caching. The structure of an interceptor looks like this:

The above interceptor simply does nothing. It allows the HttpRequest to pass through without inspection nor modification. Let's create one for logging. Creating an interceptor is easy. Start by creating a folder called http-interceptors under the app folder. Next create the file log.interceptor.ts and copy the following code:

In the above example, we allow the request to pass through untouched. However, we capture the response by piping the result of next.handle(req). We check the result to determine the status. We also calculate the duration it took for the server to respond to the request.

Next, we'll need to add the interceptor to our app.module.ts file. However, we'll be creating additional interceptors which will clutter the app.module.ts. To keep the file clean, we'll create a reference for all our interceptors in one file. Inside the http-interceptor's folder, create index.ts and copy the following code:

Next, update app.module.ts as follows:

Now interact with the application as usual. Open your browser console to see the logs. If you are using Chrome, just press F12.

log-interceptor

Fantastic! Isn't it. Now let's setup a local JSON server.

Local JSON-Server

For this section, we are going to create a local database right inside our project. Start by creating a folder called data at the root of the project. Next, create a file called db.json and copy the following code:

Next, open package.json and add the following scripts:

The JSON script is what we'll use to launch the json server. But what is the local script for?

Well, we are going to create a special environment where our application uses the local json server instead of the online one. To do this, we need to make some changes starting from post.service.ts file. Update the file as follows:

Next, open the file environments/environment.ts and update as follows:

We've specified the online version of postsUrl in the default environment file. To specify the local version of postsUrl, we need to create a new environment. Create the file environments/environment.local.ts and copy the following:

We now have the local postsUrl in the environment.local.ts file. We now need to configure our Angular project to recognize our new local environment. Open angular.json and look for the first "configurations" node. Under this node, you'll find "production". Add a comma then copy this:

Next, look for the second "configurations" node which should be under the "serve" node. Add this node:

Don't forget to separate nodes with a comma.

Change ng-http-sui to match your project name in case you named it differently. Otherwise, the command will fail. Now we are ready to launch the application with the new local environment. First, in a new terminal, start the local JSON server like this:

Open the URL localhost:3000/ to confirm the JSON server is running.

json-server

Next, stop the current Angular server and start a new one using this command:

Refresh or open the URL http://localhost:4200/posts in your browser. You should have the following view.

ng-serve-local

Your application has now switched to the local database. This time, any changes you make will be persisted. Go ahead and perform CREATE, UPDATE and DELETE operations.

Interceptors - Caching

Let's quickly create a new post:

create-local

Hit save. You should be redirected to the list page upon successful save.

post-create-local

Let's now update an existing record. You can simply add an exclamation mark to the title.

update-local

When you hit the update button, you should be redirected to the post list page.

post-update-local

Wait a minute, why has the title not changed. Hit the refresh button to confirm.

post-update-refresh

Okay. This confirms the record was updated. For some reason, the old record was being listed instead of the new one. I suspect the problem has to do with caching. Let's write an interceptor to disable caching completely. Create a new file in http-interceptors folder called cache.interceptor.ts. Copy the following code:

Next, you'll need to add this new interceptor to http-interceptors/index.ts:

Next, refresh the post and try updating an existing post. For example, rename the title of the last post to 'Just Another Post'. Hit the update button. You should be redirected to this view:

cache-fix

Awesome! The fix has worked. That's all for this chapter. Feel free to modify the application to your liking. Also, check the following links for more information.

About the Author

Michael Wanyoike

I like keeping it simple. I write clean, readable and modular code. I love learning new technologies that bring efficiencies and increased productivity to my workflow.