1

I created one service for handling all http request. It is working perfectly. But I want to know is there any fault in my approach and also want to know other good approaches like observable?

request.service.js

import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { of } from 'rxjs/observable/of'; import { catchError, map, tap } from 'rxjs/operators'; import { MessageService } from './message.service'; const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' }) }; interface IRequestOption { url: string; cxfgroup: string; endpoint: string; data: object; } interface IRequestBody { option: IRequestOption; log: string; error: string; } class HTTP { private messageService: MessageService; constructor(http, messageService, url: string, body: object, log: string, error: string) { this.callHTTP(http, url, body, log, error); this.messageService = messageService; } callHTTP(http, url, body, log, error) { return http.post(url, body, httpOptions).toPromise() .then(this.extractData) .catch(this.handleErrorPromise); } private extractData(res: Response) { // let body = res.json(); // return body['data'] || {}; return res || {}; } private handleErrorPromise(error: Response | any) { console.error(error.message || error); return Promise.reject(error.message || error); } } class RequestFactory { private baseURL = 'https://app.domain.com/cxf/'; /** * CXF ENPOINTS */ private endpoints: any = { "auth": { "getcustomerkeys": "auth/getcustomerkeys" } }; call(http, messageService, options: IRequestOption, log: string, error: string) { let url: string = options.url ? options.url : this.baseURL; if (this.endpoints.hasOwnProperty(options['cxfgroup'])) { url += this.endpoints[options.cxfgroup][options.endpoint]; } return new HTTP(http, messageService, url, options.data, log, error); } } @Injectable() export class RequestService { constructor(private http: HttpClient, private messageService: MessageService) { } post(request: IRequestBody) { let requestFactory = new RequestFactory(); requestFactory.call(this.http, this.messageService, request.option, request.log, request.error); } } 

I'm calling this "post" method using the following code. Here I want to set a promise once the request complete i want to show some message.

this.requestService.post({ option: { url: '', cxfgroup: 'auth', endpoint: 'getcustomerkeys', data: { userid: '[email protected]' } }, log: 'login initiated!', error: 'customerKeyError' }); 
1
  • 1
    Have a look at this answer Commented Dec 7, 2017 at 7:23

2 Answers 2

2

HTTP Service

Here is an observable based approach we're using in our projects:

import { Injectable } from '@angular/core'; import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; @Injectable() export class HttpService { constructor(private http: HttpClient) {} /** * Invoke function should be able to handle any HTTP request based on the @params */ invoke(params): Observable<any> { if (params) { const method = params.method.toLowerCase(); const { url, path, body, headers, query } = params; const requestURL = `${url}/${path}`; let request; let requestParams = new HttpParams(); let requestHeaders = new HttpHeaders(); /** * DEFAULT HEADERS */ requestHeaders = requestHeaders.set('Content-Type', 'application/json'); /** * CUSTOM HEADERS */ if (headers) { for (const key in headers) { if (headers.hasOwnProperty(key)) { requestHeaders = requestHeaders.append(key, headers[key]); } } } /** * CUSTOM REQUEST QUERY (?key=value) */ if (query) { for (const key in query) { if (query.hasOwnProperty(key)) { requestParams = requestParams.append(key, query[key]); } } } const requestOptions = { headers: requestHeaders, params: requestParams, }; /** * HANDLE GET, POST etc. REQUESTS */ if (method === 'get') { request = this.http[method](requestURL, requestOptions); } else if (method === 'post' || method === 'put') { request = this.http[method]( requestURL, JSON.stringify(body), requestOptions, ); } else if (method === 'delete') { request = this.http.request(method, requestURL, { ...requestOptions, body: JSON.stringify(body), }); } else { console.error('Unknown request method.'); } /** * RETURN API REQUEST */ return request; } } } 

Usage example in services

Which is very simple to use in your service, so it's gonna look like this:

constructor(private http: HttpService) {} makeRequest() { return this.http.invoke({ method: 'POST', // method like POST, GET etc. url: 'http://blabla', // base URL path: 'makeReq', // API endpoint body: ..., // body for POST or PUT requests headers: {headerName: 'HeaderValue'} // headers you need to add to your request query: {query: 'queryValue'} // URL query to be added (eg. ?query=queryValue) }); } 

Please note that body, headers and query are optional.

Usage example in components

And finally, you need to subscribe to an Observable in your components to make the request:

this.yourServiceName.makeRequest().subscribe( success => { // handle success }, error => { // handle error } ); 

Error Handling

To handle errors we can use HttpInterceptor so it's gonna look something like this:

import { Injectable } from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpErrorResponse, HTTP_INTERCEPTORS, } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { _throw } from 'rxjs/observable/throw'; import 'rxjs/add/operator/catch'; @Injectable() export class ErrorInterceptor implements HttpInterceptor { intercept( req: HttpRequest<any>, next: HttpHandler, ): Observable<HttpEvent<any>> { return next.handle(req).catch(errorReponse => { let error: string; if (errorReponse instanceof HttpErrorResponse) { error = errorReponse.error; const { status, statusText, message } = errorReponse; const errMsg = `HTTP ERROR: ${status} - ${statusText}\n${message}\n\nBACKEND RESPONSE: `; console.error(errMsg, error); } else { error = null; } return _throw(error); }); } } export const ErrorHttpInterceptor = { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true, }; 

HttpInterceptor will apply some middleware functionality to all HTTP calls made with HttpClient provider. Please note it won't work with Http provider as it's deprecated in the latest releases. And don't forget to include the interceptor in @NgModule:

@NgModule({ providers: [ErrorHttpInterceptor] }) 

A similar approach can be used to inject Authorization token etc.

Sign up to request clarification or add additional context in comments.

Comments

1

Sorry Libu, it's all more "simple" than your code. You don't need create class and class and class. Futhermore the best approach it's always return an Observable.Really there are no advantage to use promise instead of of observable. If you return an observable you can "chain" (using switchMap), "group" (using fork), etc

@Injectable() export class RequestService { private baseURL = 'https://app.domain.com/cxf/'; constructor(private http: HttpClient) post(request: IRequestBody) { let url: string = options.url ? options.url : this.baseURL; if (this.endpoints.hasOwnProperty(options['cxfgroup'])) { url += this.endpoints[options.cxfgroup][options.endpoint]; } let requestFactory = new RequestFactory(); this.http.post(url,this.messageService, request.option) .do(console.log(request.log)) //when the request sucesfully //show in console .catch(console.log(request.error)); //if fail, show in console the error } } 

5 Comments

Thanks for response. Sorry, But I have different methods like the post, get etc.. So anyway I need to separate that code.
@Libu Mathew, in your code I can't see the different methods :(
Yes. But I need all these cases. That's why I separated code.
you can make a "request" instead of "post" or add a "get" method in the Service
Yes I did like that.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.