INTRODUCTION
Application program interface(API) is a set of routines, protocols, and tools for building software applications. It specifies how software components should interact. A good API makes it easier to develop a program by providing all the building blocks. A programmer then puts the block together.
WHAT IS REST API?
REST is any interface between systems using HTTP to obtain data and generate operations on those data in all possible formats, such as XML and JSON. Developers do not need to need to install libraries or additional software in order to take advantage of REST API design.
HISTORY OF REST API
In 1999, most developers had to deal with SOAP—Simple Object Access Protocol— to integrate APIs. And the “simple” part of that acronym is not to be taken literally. To make a call, they had to hand-write an XML document with an RPC call in the body. From there, they had to specify the endpoint and POST their SOAP envelope to that specified endpoint.
SOAP was notorious for being complex to build, complex to use, and near-impossible to debug. And the alternative, CORBA, was even worse. The problem was that there was no standard for how APIs should be designed and used. Back then, APIs were not designed to be accessible, they were only designed to be flexible.
But a small group of expert developers recognized the true potential of web APIs. Thanks to this small group, led by Roy Fielding, REST was coined and the API landscape changed forever.
In 2000, Roy Fielding and his colleagues had one objective: create a standard so that any server could talk to any other server in the world. Roy Fielding gave the disorganized internet world the gift of a common language through which their software could communicate.
RESTFUL WEBSERVICES FOR ANGULAR 2
The Angular HTTP client communicates with the server using a familiar HTTP request/response protocol. The Http client is one of a family of services in the Angular HTTP library. When importing from the @angular/HTTP module, SystemJS knows how to load services from the Angular HTTP library because the systemjs.config.js file maps to that module name. The HttpModule is necessary for making HTTP calls.
Observable
Think of an Observable as a stream of events published by some source. To listen for events in this stream, subscribe to the Observable. These subscriptions specify the actions to take when the web request produces a success event or a fail event (with the error in the payload).
- The observable’s map callback moves to the success parameter and its catch callback to the fail parameter in this pattern.
- The errorHandler forwards an error message as a failed promise instead of a failed observable.
RxJS library
- RxJS (“Reactive Extensions”) is a 3rd party library, endorsed by Angular, that implements the asynchronous observable pattern.
- RxJS npm package loaded via system.js because observables are used widely in Angular applications.
- The app needs it when working with the HTTP client. Additionally, you must take a critical extra step to make RxJS observables usable.
- The RxJS library is large. Size matters when building a production application and deploying it to mobile devices. You should include only necessary features.
- Accordingly, Angular exposes a stripped down version of Observable in the rxjs/Observable module that lacks most of the operators such as the map method.
- You could add every RxJS operator with a single import statement. While that is the easiest thing to do, you’d pay a penalty in extended launch time and application size because the full library is so big.
- Since this app only uses a few operators, it’s better to import each Observable operator and static class method, one-by-one, for a custom Observable implementation tuned precisely to the app’s requirements. Put the import statements in one app/rxjs-operators.ts file.
Below is the HTTP signature as is in Angular 2 source:
/**
* Performs any type of http request. First argument is required, and can either be a url or
* a {@link Request} instance. If the first argument is a url, an optional {@link RequestOptions}
* object can be provided as the 2nd argument. The options object will be merged with the values
* of {@link BaseRequestOptions} before performing the request.
*/
request(url: string | Request, options?: RequestOptionsArgs): Observable;
/**
* Performs a request with `get` http method.
*/
get(url: string, options?: RequestOptionsArgs): Observable;
/**
* Performs a request with `post` http method.
*/
post(url: string, body: any, options?: RequestOptionsArgs): Observable;
/**
* Performs a request with `put` http method.
*/
put(url: string, body: any, options?: RequestOptionsArgs): Observable;
/**
* Performs a request with `delete` http method.
*/
delete(url: string, options?: RequestOptionsArgs): Observable;
/**
* Performs a request with `patch` http method.
*/
patch(url: string, body: any, options?: RequestOptionsArgs): Observable;
/**
* Performs a request with `head` http method.
*/
head(url: string, options?: RequestOptionsArgs): Observable;
Each method takes in a url and a payload as the case may be and returns a generic observable response type.
The service class has the following structure:
/* * * ./app/comments/services/comment.service.ts * * */
// Imports
import { Injectable } from ‘@angular/core’;
import { Http, Response, Headers, RequestOptions } from ‘@angular/http’;
import { Comment } from ‘../model/comment’;
import {Observable} from ‘rxjs/Rx’;// Import RxJs required methods
import ‘rxjs/add/operator/map’;
import ‘rxjs/add/operator/catch’;@Injectable()
export class CommentService {
// Resolve HTTP using the constructor
constructor (private http: Http) {}
// private instance variable to hold base url
private commentsUrl = ‘http://localhost:3000/api/comments’;}
We are importing the required libraries for our service to behave as expected. The observable about has also been imported and ready for use. The
map
and catch
observable operators which will help us manipulate data and handle errors respectively has also been imported. Then we inject HTTP
in the constructor and keep a reference to the base url of our API.// Fetch all existing comments
getComments() : Observable<Comment[]> {// …using get request
return this.http.get(this.commentsUrl)
// …and calling .json() on the response to return data
.map((res:Response) => res.json())
//…errors if any
.catch((error:any) => Observable.throw(error.json().error || ‘Server error’));}
Using the
http
instance we already have on the class, we call it’s get
method passing in the base url because that is the endpoint where we can find a list of comments.
We are maintaining strictness by ensuring that the service instance methods always return an observable of type
Comment
:/* * * ./app/comments/model/comment.ts * * */
export class Comment {
constructor(
public id: Date,
public author: string,
public text:string
){}
}
With the map operator, we call the
.json
method on the response because the actual response is not a collection of data but a JSON string.
It is always advisable to handle errors so we can use the catch operator to return another subscribable observable but this time a failed one.
The rest of the code has the above structure but different HTTP methods and arguments:
// Add a new comment
addComment (body: Object): Observable<Comment[]> {
let bodyString = JSON.stringify(body); // Stringify payload
let headers = new Headers({ ‘Content-Type’: ‘application/json’ }); // … Set content type to JSON
let options = new RequestOptions({ headers: headers }); // Create a request optionreturn this.http.post(this.commentsUrl, body, options) // …using post request
.map((res:Response) => res.json()) // …and calling .json() on the response to return data
.catch((error:any) => Observable.throw(error.json().error || ‘Server error’)); //…errors if any
}// Update a comment
updateComment (body: Object): Observable<Comment[]> {
let bodyString = JSON.stringify(body); // Stringify payload
let headers = new Headers({ ‘Content-Type’: ‘application/json’ }); // … Set content type to JSON
let options = new RequestOptions({ headers: headers }); // Create a request optionreturn this.http.put(`${this.commentsUrl}/${body[‘id’]}`, body, options) // …using put request
.map((res:Response) => res.json()) // …and calling .json() on the response to return data
.catch((error:any) => Observable.throw(error.json().error || ‘Server error’)); //…errors if any
}// Delete a comment
removeComment (id:string): Observable<Comment[]> {
return this.http.delete(`${this.commentsUrl}/${id}`) // …using put request
.map((res:Response) => res.json()) // …and calling .json() on the response to return data
.catch((error:any) => Observable.throw(error.json().error || ‘Server error’)); //…errors if any
}
The above makes a
post
, put
and delete
request, converts response to JSON and catches error if any.
Observables are not as mouthful as it seemed in the beginning. What’s is just left to do is subscribe to the observable and bind the data as they are emitted to the views.