Using Promises to Make HTTP Requests in Angular
Promises in ECMAScript are very much identical to the promises we make in our daily life.
We will be looking out how Angular handle promises.
Before Getting Started with Typescript promise let’s understand JavaScript Promise:
JavaScript Promise
A promise is an object that may produce a single value some time in the future: either a resolved value or a reason that it’s not resolved (e.g., a network error occurred). A promise may be in one of 3 possible states: fulfilled, rejected, or pending.
Below are some example:
Promise.resolve(promise); | Returns promise (only if promise.constructor == Promise ) |
Promise.resolve(thenable); | Make a new promise from the thenable. A thenable is promise-like in as far as it has a then() method. |
Promise.resolve(obj); | Make a promise that fulfills to obj . in this situation. |
Benefits of Promises:
- Improves Code Readability
- Better handling of asynchronous operations
- Better flow of control definition in asynchronous logic
- Better Error Handling
Practical Example of JavaScript Promises
We will be using promise constructor.
const promise = new Promise(function(resolve, reject){
//do something
});
You can see that in the above code, a promise constructor takes in one argument (a callback function) and the callback function takes in two arguments (resolve and reject) before performing the operation inside the callback function. If the operation went successfully it resolves but if not perform successfully it rejects.
Below is a full promise example:
var promise = new Promise(function(resolve, reject) {
const x = "Favour";
const y = "Vivian"
if(x === y) {
resolve();
} else {
reject();
}
});
promise.
then(function () {
console.log('Success, You are Favour');
}).
catch(function () {
console.log('Some error has occured');
});
// Output: Success, You are Favour
Promises can be consumed by registering functions using .then and .catch methods.
then(): then() method takes two functions as parameters and it is invoked when a promise is either resolved or rejected.
You can see that the first function is executed if promise is resolved and a result is received and the Second function is executed if the promise is rejected and an error is received. It is optional and there is a better way to handle error using .catch() method just as shown below.
var promise = new Promise(function(resolve, reject) {
reject('Promise Rejected')
})
promise
.then(function(successMessage) {
console.log(successMessage);
})
.catch(function(errorMessage) {
//error handler function is invoked
console.log(errorMessage);
});
// Output: Promise Rejected
Always remember that promises has four state.
- fulfilled: Action related to the promise succeeded
- rejected: Action related to the promise failed
- pending: Promise is still pending i.e not fulfilled or rejected yet
- settled: Promise has fulfilled or rejected
we are going to look at how to use Promises in Angular to manage the HTTP response asynchronously. We will start by creating an angular app. To achieve this, we will be creating small ul to display the names of all the characters in Harry-potter movie Api.
TypeScript Promise example
Navigate to the folder where you want to create your project file. Open a command window and run the command shown below.
ng new Harry-potter --routing=false --style=scss
The command above creates a new Angular application. The option to create the routing module is set to false and style files extension is set to scss.
We are going to use bootstrap. Run the code to install bootstrap:
cd Harry-potter
npm install bootstrap --save
Add the following import definition in styles.scss file.
@import "~bootstrap/dist/css/bootstrap.css";
Accessing the API
The Harry Potter API returns spell routes, character routes, house, and sorting hat routes in JSON format.
All routes need to be prefixed with https://www.potterapi.com/v1/
Setting up the project
Open your Angular project in your favorite text editor and then go to app.module.ts file and import HttpClientModule service. Then also register it inside the imports
array.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { HttpClientModule } from "@angular/common/http";
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Next, go to the app.component.ts file. Here we will write the core logic to make the HTTP GET request and manage the response using the ES6 Promise in Angular.
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
Movie;
key = "key=$2a$10$LFXn2jsUKz6/3u.fmKm.q..l0sFiMaumBuLI8rwQ28g2QmLPa55Em"
apiUrl = `https://www.potterapi.com/v1/characters?${this.key}`;
constructor(private httpClient: HttpClient){}
ngOnInit(){
this.fetchData();
}
}
You simply import HttpClient
and you can now inject HttpClient
in a component and use it to send API requests.
We also import and implement OnInit
, so we can use the ngOnInit()
life-cycle method. Next, we declare the apiUrl
variable that holds our data endpoint and we define a fetchData() method and call it from ngOnInit().
fetchData(){
const promise = this.httpClient.get(this.apiUrl).toPromise();
console.log(promise);
}
We can send a GET HTTP request using the get()
method which returns an RxJS Observable but we can get a JavaScript Promise by using the toPromise()
method of Observable
as shown above.
We will call the get()
method with our API URL and we call the toPromise()
method to get a promise from the returned promise.
The API request will not be sent until we call the then()
method of the promise as follows:
promise.then((data)=>{
this.Movie = JSON.stringify(data)
console.log(JSON.stringify(data));
}).catch((error)=>{
console.log("Promise rejected with " + JSON.stringify(error));
});
The full code is show below:
import { Component, OnInit } from "@angular/core";
import { HttpClient } from '@angular/common/http';
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit{
Movie;
key = "key=$2a$10$LFXn2jsUKz6/3u.fmKm.q..l0sFiMaumBuLI8rwQ28g2QmLPa55Em"
apiUrl = `https://www.potterapi.com/v1/characters?${this.key}`;
constructor(private httpClient: HttpClient){}
ngOnInit(){
this.fetchData();
}
fetchData(){
const promise = this.httpClient.get(this.apiUrl).toPromise();
console.log(promise);
promise.then((data)=>{
this.Movie = JSON.stringify(data)
console.log(JSON.stringify(data));
}).catch((error)=>{
console.log("Promise rejected with " + JSON.stringify(error));
});
}
}
Then html code look like this. Open app.component.html and write the code below.
<div style="background: black; color:#fff;
width:100%; height:100vh;">
<div *ngIf="characters">
<div *ngFor="let character of characters ">
<p style="color: #fff">{{character.name}}</p>
</div>
</div>
</div>
We showed the characters names using *ngFor
Angular loop inside the HTML Div element.
Conclusion
Finally, we have completed the Angular Promises tutorial with an example. We were able to understand Javascript promises, the benefit of using promises and how to use TypeScript promises to manage HTTP requests in an Angular app. I hope you find this tutorial helpful.
Get the full code from Codesandbox