Last active
April 3, 2017 15:52
-
-
Save wmeints/d51efe1867066818e5d28b6dd610ae28 to your computer and use it in GitHub Desktop.
Short demo of how you can wrap standard HTTP behavior by adding additional operations on the observables it produces.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ApiRequestOptions } from './api-request-options.service'; | |
import { Http, Response, RequestOptions, ResponseContentType } from '@angular/http'; | |
import 'rxjs/add/observable/zip'; | |
import 'rxjs/add/operator/map'; | |
import { Observable } from 'rxjs/Rx'; | |
import { Injectable } from '@angular/core'; | |
import { Router } from '@angular/router'; | |
@Injectable() | |
export class ApiClient { | |
// PLease note, the API request options service is a helper that we introduced | |
// to generate absolute URLs based on settings in the client. | |
// I did not include it here for brevity. | |
constructor(private router: Router, private http: Http, private requestOptions: ApiRequestOptions) { | |
} | |
get<TResponse>(path: string, queryStringParams?: any): Observable<TResponse> { | |
let self = this; | |
return Observable.zip( | |
this.requestOptions.absoluteUrlFor(path, queryStringParams), | |
this.requestOptions.authorizedRequestOptions() | |
).flatMap(requestOpts => { | |
let [url, options] = requestOpts; | |
return self.http.get(url, options); | |
}).catch(response => { | |
if (response.status === 401) { | |
self.router.navigate(['/login']); | |
} | |
return response; | |
}).map((response: Response) => <TResponse>response.json()); | |
} | |
post<TResponse>(path: string, body: any): Observable<TResponse> { | |
let self = this; | |
return Observable.zip( | |
this.requestOptions.absoluteUrlFor(path), | |
this.requestOptions.authorizedRequestOptions() | |
).flatMap(requestOpts => { | |
let [url, options] = requestOpts; | |
return self.http.post(url, body, options); | |
}).catch(response => { | |
if (response.status === 401) { | |
self.router.navigate(['/login']); | |
} | |
return response; | |
}).map((response: Response) => <TResponse>response.json()); | |
} | |
put<TResponse>(path: string, body: any): Observable<TResponse> { | |
let self = this; | |
return Observable.zip( | |
this.requestOptions.absoluteUrlFor(path), | |
this.requestOptions.authorizedRequestOptions() | |
).flatMap(requestOpts => { | |
let [url, options] = requestOpts; | |
return self.http.put(url, body, options); | |
}).catch(response => { | |
if (response.status === 401) { | |
self.router.navigate(['/login']); | |
} | |
return response; | |
}).map((response: Response) => { | |
if (response.status === 200) { | |
return <TResponse>response.json(); | |
} else { | |
return null; | |
} | |
}); | |
} | |
delete(path: string): Observable<Response> { | |
let self = this; | |
return Observable.zip( | |
this.requestOptions.absoluteUrlFor(path), | |
this.requestOptions.authorizedRequestOptions() | |
).flatMap(requestOpts => { | |
let [url, options] = requestOpts; | |
return self.http.delete(url, options); | |
}).catch(response => { | |
if (response.status === 401) { | |
self.router.navigate(['/login']); | |
} | |
return response; | |
}); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Injectable } from '@angular/core'; | |
import { ApplicationSettings } from './applicationsettings.service'; | |
import { Observable } from 'rxjs/Rx'; | |
import { AuthenticationService } from '../authentication/authentication.service'; | |
import { Headers, RequestOptions } from '@angular/http'; | |
/** | |
* Converts the parameters map into a query string for the request | |
* @param parameters The parameters map to convert | |
* @returns The querystring for the HTTP request | |
*/ | |
function asQueryString(parameters: any): string { | |
let queryStringParameters = []; | |
for (let key in parameters) { | |
if (parameters.hasOwnProperty(key) && parameters[key] !== undefined && parameters[key] !== null) { | |
queryStringParameters.push(`${encodeURI(key)}=${encodeURI(parameters[key])}`); | |
} | |
} | |
return queryStringParameters.join('&'); | |
} | |
/** | |
* This service can be used to generate options for API requests | |
*/ | |
@Injectable() | |
export class ApiRequestOptions { | |
/** | |
* Initializes a new instance of ApiRequestOptions | |
* @param settings Application settings to use | |
* @param authenticationService Authentication service for obtaining access tokens | |
*/ | |
constructor(private settings: ApplicationSettings, private authenticationService: AuthenticationService) { | |
} | |
/** | |
* Generates an absolute URL for a request | |
* @param path Path for the API endpoint to invoke | |
* @param queryStringParams Querystring parameters to send | |
*/ | |
absoluteUrlFor(path: string, queryStringParams?: any): Observable<string> { | |
let self = this; | |
return Observable.fromPromise(this.settings.get()).map(settings => { | |
let absoluteUrl = settings.prescreeningApi.serviceUrl + path; | |
if (queryStringParams) { | |
absoluteUrl = absoluteUrl + '?' + asQueryString(queryStringParams); | |
} | |
return absoluteUrl; | |
}); | |
} | |
/** | |
* Generates authorized request options | |
* @returns {Observable<R>} An observable with the necessary request options | |
*/ | |
authorizedRequestOptions() { | |
return this.authenticationService.getUser().map(user => { | |
let headers = new Headers({ | |
'Authorization': `Bearer ${user.access_token}` | |
}); | |
return new RequestOptions({ headers: headers }); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment