Skip to content

Commit 250dad1

Browse files
Stefan SchubertStefan Schubert
authored andcommitted
add error handler and dependency injection for
configuration factory
1 parent 7a32742 commit 250dad1

File tree

3 files changed

+142
-2
lines changed

3 files changed

+142
-2
lines changed

src/mustache/api.module.mustache

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{{! Copyright(c) 1995 - 2018 T-Systems Multimedia Solutions GmbH }}
2+
{{! Riesaer Str. 5, 01129 Dresden }}
3+
{{! All rights reserved. }}
4+
import { NgModule, ModuleWithProviders, SkipSelf, Optional } from '@angular/core';
5+
import { Configuration } from './configuration';
6+
{{#useHttpClient}}import { HttpClient } from '@angular/common/http';{{/useHttpClient}}
7+
{{^useHttpClient}}import { Http } from '@angular/http';{{/useHttpClient}}
8+
9+
{{#apiInfo}}
10+
{{#apis}}
11+
import { {{classname}} } from './{{importPath}}';
12+
{{/apis}}
13+
{{/apiInfo}}
14+
15+
@NgModule({
16+
imports: [],
17+
declarations: [],
18+
exports: [],
19+
providers: [
20+
{{#apiInfo}}{{#apis}}{{classname}}{{#hasMore}},
21+
{{/hasMore}}{{/apis}}{{/apiInfo}} ]
22+
})
23+
export class ApiModule {
24+
public static forRoot(configurationFactory: (...args: any[]) => Configuration, deps?: any[]): ModuleWithProviders {
25+
return {
26+
ngModule: ApiModule,
27+
providers: [ { provide: Configuration, useFactory: configurationFactory, deps } ]
28+
};
29+
}
30+
31+
constructor( @Optional() @SkipSelf() parentModule: ApiModule,
32+
@Optional() http: {{#useHttpClient}}HttpClient{{/useHttpClient}}{{^useHttpClient}}Http{{/useHttpClient}}) {
33+
if (parentModule) {
34+
throw new Error('ApiModule is already loaded. Import in your base AppModule only.');
35+
}
36+
if (!http) {
37+
throw new Error('You need to import the {{#useHttpClient}}HttpClientModule{{/useHttpClient}}{{^useHttpClient}}HttpModule{{/useHttpClient}} in your AppModule! \n' +
38+
'See also https://github.com/angular/angular/issues/20575');
39+
}
40+
}
41+
}

src/mustache/api.service.mustache

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import { Observable } from 'rxjs/Observab
2323
{{/useRxJS6}}
2424
{{#useRxJS6}}
2525
import { Observable } from 'rxjs';
26+
import { catchError } from 'rxjs/operators';
2627
{{/useRxJS6}}
2728
{{^useHttpClient}}
2829
import '../rxjs-operators';
@@ -311,7 +312,7 @@ export class {{classname}} {
311312

312313
{{/hasFormParams}}
313314
{{#useHttpClient}}
314-
return this.httpClient.{{httpMethod}}{{^isResponseFile}}<{{#returnType}}{{{returnType}}}{{#isResponseTypeFile}}|undefined{{/isResponseTypeFile}}{{/returnType}}{{^returnType}}any{{/returnType}}>{{/isResponseFile}}(`${this.configuration.basePath}{{{path}}}`,{{#isBodyAllowed}}
315+
const handle = this.httpClient.{{httpMethod}}{{^isResponseFile}}<{{#returnType}}{{{returnType}}}{{#isResponseTypeFile}}|undefined{{/isResponseTypeFile}}{{/returnType}}{{^returnType}}any{{/returnType}}>{{/isResponseFile}}(`${this.configuration.basePath}{{{path}}}`,{{#isBodyAllowed}}
315316
{{#bodyParam}}{{paramName}}{{/bodyParam}}{{^bodyParam}}{{#hasFormParams}}convertFormParamsToString ? formParams.toString() : formParams{{/hasFormParams}}{{^hasFormParams}}null{{/hasFormParams}}{{/bodyParam}},{{/isBodyAllowed}}
316317
{
317318
{{#hasQueryParams}}
@@ -326,6 +327,10 @@ export class {{classname}} {
326327
reportProgress: reportProgress
327328
}
328329
);
330+
if(typeof this.configuration.errorHandler === 'function') {
331+
return handle.pipe(catchError(err => this.configuration.errorHandler(err)));
332+
}
333+
return handle;
329334
{{/useHttpClient}}
330335
{{^useHttpClient}}
331336
let requestOptions: RequestOptionsArgs = new RequestOptions({
@@ -350,7 +355,11 @@ export class {{classname}} {
350355
requestOptions = (<any>Object).assign(requestOptions, extraHttpRequestParams);
351356
}
352357

353-
return this.http.request(`${this.configuration.basePath}{{{path}}}`, requestOptions);
358+
const handle = this.http.request(`${this.configuration.basePath}{{{path}}}`, requestOptions);
359+
if(typeof this.configuration.errorHandler === 'function') {
360+
return handle.catch(err => this.configuration.errorHandler(err));
361+
}
362+
return handle;
354363
{{/useHttpClient}}
355364
}
356365

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
{{! Copyright(c) 1995 - 2018 T-Systems Multimedia Solutions GmbH }}
2+
{{! Riesaer Str. 5, 01129 Dresden }}
3+
{{! All rights reserved. }}
4+
{{^useRxJS6}}
5+
import { Observable } from 'rxjs/Observable';
6+
{{/useRxJS6}}
7+
{{#useRxJS6}}
8+
import { Observable } from 'rxjs';
9+
{{/useRxJS6}}
10+
11+
export interface ConfigurationParameters {
12+
apiKeys?: {[ key: string ]: string};
13+
username?: string;
14+
password?: string;
15+
accessToken?: string | (() => string);
16+
errorHandler?: (err: any) => Observable<never>;
17+
basePath?: string;
18+
withCredentials?: boolean;
19+
}
20+
21+
export class Configuration {
22+
apiKeys?: {[ key: string ]: string};
23+
username?: string;
24+
password?: string;
25+
accessToken?: string | (() => string);
26+
basePath?: string;
27+
withCredentials?: boolean;
28+
29+
constructor(configurationParameters: ConfigurationParameters = {}) {
30+
this.apiKeys = configurationParameters.apiKeys;
31+
this.username = configurationParameters.username;
32+
this.password = configurationParameters.password;
33+
this.accessToken = configurationParameters.accessToken;
34+
this.basePath = configurationParameters.basePath;
35+
this.withCredentials = configurationParameters.withCredentials;
36+
}
37+
38+
/**
39+
* Select the correct content-type to use for a request.
40+
* Uses {@link Configuration#isJsonMime} to determine the correct content-type.
41+
* If no content type is found return the first found type if the contentTypes is not empty
42+
* @param contentTypes - the array of content types that are available for selection
43+
* @returns the selected content-type or <code>undefined</code> if no selection could be made.
44+
*/
45+
public selectHeaderContentType (contentTypes: string[]): string | undefined {
46+
if (contentTypes.length === 0) {
47+
return undefined;
48+
}
49+
50+
let type = contentTypes.find(x => this.isJsonMime(x));
51+
if (type === undefined) {
52+
return contentTypes[0];
53+
}
54+
return type;
55+
}
56+
57+
/**
58+
* Select the correct accept content-type to use for a request.
59+
* Uses {@link Configuration#isJsonMime} to determine the correct accept content-type.
60+
* If no content type is found return the first found type if the contentTypes is not empty
61+
* @param accepts - the array of content types that are available for selection.
62+
* @returns the selected content-type or <code>undefined</code> if no selection could be made.
63+
*/
64+
public selectHeaderAccept(accepts: string[]): string | undefined {
65+
if (accepts.length === 0) {
66+
return undefined;
67+
}
68+
69+
let type = accepts.find(x => this.isJsonMime(x));
70+
if (type === undefined) {
71+
return accepts[0];
72+
}
73+
return type;
74+
}
75+
76+
/**
77+
* Check if the given MIME is a JSON MIME.
78+
* JSON MIME examples:
79+
* application/json
80+
* application/json; charset=UTF8
81+
* APPLICATION/JSON
82+
* application/vnd.company+json
83+
* @param mime - MIME (Multipurpose Internet Mail Extensions)
84+
* @return True if the given MIME is JSON, false otherwise.
85+
*/
86+
public isJsonMime(mime: string): boolean {
87+
const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i');
88+
return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
89+
}
90+
}

0 commit comments

Comments
 (0)