Skip to content

Commit

Permalink
refactor(ngx-api-utils): refactor the NgxApiModule and remove `forR…
Browse files Browse the repository at this point in the history
…oot` as it breaks

The error shown is:
```
ERROR in Error during template compile of AppModule
  Function calls are not supported in decorators but NgxApiUtilsModule was called.
```

refs angular/angular#23609 ng-packagr/ng-packagr#767
  • Loading branch information
smoke committed Jul 19, 2018
1 parent 7539d00 commit 276f50a
Show file tree
Hide file tree
Showing 14 changed files with 111 additions and 132 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { NgxApiUtilsModule } from 'ngx-api-utils';

@NgModule({
...
imports: [NgxApiUtilsModule.forRoot(),...]
imports: [NgxApiUtilsModule,...]
...
})
export class AppModule { }
Expand All @@ -50,7 +50,7 @@ The package consists of couple of main services and a module that you would use:
- or even better - have your own implementation of any interceptor you need - to handle errors, transform results or anything you would the same way you would do for Angular's `HttpClient`, just provide it like the defaults are provided with `API_HTTP_INTERCEPTORS` injection token e.g. `{provide: API_HTTP_INTERCEPTORS, useClass: YourCoolInterceptor, multi: true}` to line up with the rest of the default provided [`API_HTTP_INTERCEPTORS`](https://github.com/ngx-api-utils/ngx-api-utils/blob/master/packages/ngx-api-utils/src/lib/ngx-api-utils.module.ts#API_HTTP_INTERCEPTORS)
- [`ApiAuthGuardService`](https://github.com/ngx-api-utils/ngx-api-utils/blob/master/packages/ngx-api-utils/src/lib/api-auth-guard/api-auth-guard.service.ts) that is a perfectly sane option of you just have public and private part that needs to be protected based on `AuthTokenService` validity and you want a bit more
- you can of course configure it with urls for `API_AUTH_GUARD_URL_FOR_AUTHENTICATED` and `API_AUTH_GUARD_URL_FOR_AUTHENTICATION`, also a RegExp for `API_AUTH_GUARD_PUBLIC_ONLY_ROUTES`
- [`NgxApiUtilsModule`](https://github.com/ngx-api-utils/ngx-api-utils/blob/master/packages/ngx-api-utils/src/lib/ngx-api-utils.module.ts) that allows you to easy and handy way to configure the sane defaults services listed above through using `NgxApiUtilsModule#forRoot` method and just passing couple of options
- [`NgxApiUtilsModule`](https://github.com/ngx-api-utils/ngx-api-utils/blob/master/packages/ngx-api-utils/src/lib/ngx-api-utils.module.ts) that provides a default set of interceptors for `API_HTTP_INTERCEPTORS` used by the `ApiHttpService` which you can configure through providing your own values for the relevant injection tokens

For more details, please check:

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { InjectionToken } from '@angular/core';

export const API_AUTH_GUARD_URL_FOR_AUTHENTICATED = new InjectionToken<string>('API_AUTH_GUARD_URL_FOR_AUTHENTICATED');
export const API_AUTH_GUARD_URL_FOR_AUTHENTICATED = new InjectionToken<string>('API_AUTH_GUARD_URL_FOR_AUTHENTICATED', {
providedIn: 'root',
factory: () => '/'
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { InjectionToken } from '@angular/core';

export const API_AUTH_GUARD_URL_FOR_AUTHENTICATION = new InjectionToken<string>('API_AUTH_GUARD_URL_FOR_AUTHENTICATION');
export const API_AUTH_GUARD_URL_FOR_AUTHENTICATION = new InjectionToken<string>('API_AUTH_GUARD_URL_FOR_AUTHENTICATION', {
providedIn: 'root',
factory: () => '/login'
});
5 changes: 4 additions & 1 deletion packages/ngx-api-utils/src/lib/api-http/api-http-base-url.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { InjectionToken } from '@angular/core';

export const API_HTTP_BASE_URL = new InjectionToken<string>('API_HTTP_BASE_URL');
export const API_HTTP_BASE_URL = new InjectionToken<string>('API_HTTP_BASE_URL', {
providedIn: 'root',
factory: () => '/api'
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@ import { HttpHeaders } from '@angular/common/http';
export type ApiHttpDefaultHeadersStruct = HttpHeaders | string | { [name: string]: string | string[]; };

export const API_HTTP_DEFAULT_HEADERS =
new InjectionToken<ApiHttpDefaultHeadersStruct>('API_HTTP_DEFAULT_HEADERS');
new InjectionToken<ApiHttpDefaultHeadersStruct>('API_HTTP_DEFAULT_HEADERS', {
providedIn: 'root',
factory: () => ({
'accept': 'application/json, */*'
})
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import { AuthTokenService } from '../../../auth-token/public_api';
import { API_HTTP_AUTHORIZATION_HEADER_NAME } from '../../api-http-authorization-header-name';
import { API_HTTP_AUTHORIZATION_HEADER_TOKEN_TYPE_PREFIX } from '../../api-http-authorization-header-token-type-prefix';

@Injectable()
@Injectable({
providedIn: 'root'
})
export class ApiAuthorizationHeaderInterceptor implements HttpInterceptor {

constructor(
@Inject(API_HTTP_AUTHORIZATION_HEADER_NAME) private apiHttpAuthorizationHeaderName: string,
@Inject(API_HTTP_AUTHORIZATION_HEADER_TOKEN_TYPE_PREFIX) private apiHttpAuthorizationHeaderTokenTypePrefix: string,
@Inject(API_HTTP_AUTHORIZATION_HEADER_NAME) public apiHttpAuthorizationHeaderName: string,
@Inject(API_HTTP_AUTHORIZATION_HEADER_TOKEN_TYPE_PREFIX) public apiHttpAuthorizationHeaderTokenTypePrefix: string,
private authTokenService: AuthTokenService
) {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/c
import { Observable } from 'rxjs';
import { API_HTTP_BASE_URL } from '../../api-http-base-url';

@Injectable()
@Injectable({
providedIn: 'root'
})
export class ApiBaseUrlInterceptor implements HttpInterceptor {
constructor(
@Inject(API_HTTP_BASE_URL) private apiHttpBaseUrl: string
@Inject(API_HTTP_BASE_URL) public apiHttpBaseUrl: string
) {
// trim the last / e.g. `//localhost:3000/api/` -> `//localhost:3000/api`
this.apiHttpBaseUrl = apiHttpBaseUrl.replace(/\/+$/, '');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { HttpRequest, HttpHandler, HttpEvent, HttpHeaders, HttpInterceptor } fro
import { Observable } from 'rxjs';
import { ApiHttpDefaultHeadersStruct, API_HTTP_DEFAULT_HEADERS } from '../../api-http-default-headers';

@Injectable()
@Injectable({
providedIn: 'root'
})
export class ApiDefaultHeadersInterceptor implements HttpInterceptor {
private defaultHeaders: HttpHeaders;
defaultHeaders: HttpHeaders;

constructor(
@Optional() @Inject(API_HTTP_DEFAULT_HEADERS) apiHttpDefaultHeaders?: ApiHttpDefaultHeadersStruct
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { InjectionToken } from '@angular/core';

export const AUTH_TOKEN_AUTO_REMOVE = new InjectionToken<string>('AUTH_TOKEN_AUTO_REMOVE');
export const AUTH_TOKEN_AUTO_REMOVE = new InjectionToken<boolean>('AUTH_TOKEN_AUTO_REMOVE', {
providedIn: 'root',
factory: () => true
});
5 changes: 4 additions & 1 deletion packages/ngx-api-utils/src/lib/auth-token/auth-token-name.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import { InjectionToken } from '@angular/core';

export const AUTH_TOKEN_NAME = new InjectionToken<string>('AUTH_TOKEN_NAME');
export const AUTH_TOKEN_NAME = new InjectionToken<string>('AUTH_TOKEN_NAME', {
providedIn: 'root',
factory: () => 'id_token'
});
119 changes: 15 additions & 104 deletions packages/ngx-api-utils/src/lib/ngx-api-utils.module.ts
Original file line number Diff line number Diff line change
@@ -1,117 +1,28 @@
import { NgModule, Optional, SkipSelf, ModuleWithProviders, InjectionToken } from '@angular/core';
import { HttpHeaders, HttpClientModule, HttpInterceptor } from '@angular/common/http';
import { AUTH_TOKEN_NAME, AUTH_TOKEN_AUTO_REMOVE } from './auth-token/public_api';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import {
API_HTTP_BASE_URL,
API_HTTP_DEFAULT_HEADERS,
API_HTTP_AUTHORIZATION_HEADER_NAME,
API_HTTP_AUTHORIZATION_HEADER_TOKEN_TYPE_PREFIX,
API_HTTP_INTERCEPTORS_INJECTION_TOKEN,
API_HTTP_INTERCEPTORS,
ApiBaseUrlInterceptor,
ApiDefaultHeadersInterceptor,
ApiAuthorizationHeaderInterceptor
} from './api-http/public_api';
import {
API_AUTH_GUARD_PUBLIC_ONLY_ROUTES,
API_AUTH_GUARD_URL_FOR_AUTHENTICATED,
API_AUTH_GUARD_URL_FOR_AUTHENTICATION
} from './api-auth-guard/public_api';

@NgModule({
imports: [
HttpClientModule
],
declarations: [],
exports: []
})
export class NgxApiUtilsModule {
static forRoot(
config?: {
baseUrl?: string,
authTokenName?: string,
authTokenAutoRemove?: boolean,
defaultHeaders?: HttpHeaders | string | { [name: string]: string | string[]; },
authorizationHeaderName?: string,
authorizationHeaderTokenTypePrefix?: string,
interceptorsInjectionToken?: InjectionToken<InjectionToken<HttpInterceptor[]>>,
authGuardPublicOnlyRoutes?: RegExp,
authGuardUrlForAuthenticated?: string,
authGuardUrlForAuthentication?: string
exports: [],
providers: [
{
provide: API_HTTP_INTERCEPTORS, useExisting: ApiBaseUrlInterceptor, multi: true
},
{
provide: API_HTTP_INTERCEPTORS, useExisting: ApiDefaultHeadersInterceptor, multi: true
},
{
provide: API_HTTP_INTERCEPTORS, useExisting: ApiAuthorizationHeaderInterceptor, multi: true
}
): ModuleWithProviders {
config = {
baseUrl: '/api',
defaultHeaders: {
'accept': 'application/json, */*'
},
authTokenName: 'id_token',
authorizationHeaderName: 'Authorization',
authorizationHeaderTokenTypePrefix: 'Bearer ',
authGuardUrlForAuthenticated: '/',
authGuardUrlForAuthentication: '/login',
...config,
};
return {
ngModule: NgxApiUtilsModule,
providers: [
{
provide: AUTH_TOKEN_NAME,
useValue: config.authTokenName
},
{
provide: AUTH_TOKEN_AUTO_REMOVE,
useValue: config.authTokenAutoRemove
},
{
provide: API_HTTP_BASE_URL,
useValue: config.baseUrl
},
{
provide: API_HTTP_DEFAULT_HEADERS,
useValue: config.defaultHeaders
},
{
provide: API_HTTP_AUTHORIZATION_HEADER_NAME,
useValue: config.authorizationHeaderName
},
{
provide: API_HTTP_AUTHORIZATION_HEADER_TOKEN_TYPE_PREFIX,
useValue: config.authorizationHeaderTokenTypePrefix
},
{
provide: API_HTTP_INTERCEPTORS_INJECTION_TOKEN,
useValue: config.interceptorsInjectionToken || API_HTTP_INTERCEPTORS
},
{
provide: API_HTTP_INTERCEPTORS, useClass: ApiBaseUrlInterceptor, multi: true
},
{
provide: API_HTTP_INTERCEPTORS, useClass: ApiDefaultHeadersInterceptor, multi: true
},
{
provide: API_HTTP_INTERCEPTORS, useClass: ApiAuthorizationHeaderInterceptor, multi: true
},
{
provide: API_AUTH_GUARD_PUBLIC_ONLY_ROUTES, useValue: config.authGuardPublicOnlyRoutes
},
{
provide: API_AUTH_GUARD_URL_FOR_AUTHENTICATED, useValue: config.authGuardUrlForAuthenticated
},
{
provide: API_AUTH_GUARD_URL_FOR_AUTHENTICATION, useValue: config.authGuardUrlForAuthentication
}
]
};
}

constructor(
@Optional() @SkipSelf() parentModule?: NgxApiUtilsModule,
) {
// throw in case someone wrongly imports this module twice
if (parentModule) {
throw new Error(
'NgxApiUtilsModule is already loaded. Import it in the AppModule only');
}
}
}
]
})
export class NgxApiUtilsModule {}
29 changes: 26 additions & 3 deletions packages/ngx-api-utils/src/lib/ngx-api-utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { TestBed, inject } from '@angular/core/testing';
import { NgxApiUtilsModule, AuthTokenService, ApiHttpService, TokenPayload } from '../public_api';
import { Polly } from '@pollyjs/core';
import { TokenDecoder } from './auth-token/public_api';
import { TokenDecoder, AUTH_TOKEN_NAME } from './auth-token/public_api';
import { ApiErrorsInterceptor } from './api-http/interceptors/api-errors/api-errors.interceptor';
import { API_HTTP_INTERCEPTORS } from './api-http/public_api';
import {
API_HTTP_INTERCEPTORS,
API_HTTP_BASE_URL,
API_HTTP_DEFAULT_HEADERS,
API_HTTP_AUTHORIZATION_HEADER_NAME
} from './api-http/public_api';
import { HttpErrorResponse } from '@angular/common/http';

describe('ngx-api-utils package', () => {
Expand All @@ -21,7 +26,25 @@ describe('ngx-api-utils package', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
NgxApiUtilsModule.forRoot(apiUtilsConfig)
NgxApiUtilsModule
],
providers: [
{
provide: API_HTTP_BASE_URL,
useValue: apiUtilsConfig.baseUrl
},
{
provide: AUTH_TOKEN_NAME,
useValue: apiUtilsConfig.authTokenName
},
{
provide: API_HTTP_DEFAULT_HEADERS,
useValue: apiUtilsConfig.defaultHeaders
},
{
provide: API_HTTP_AUTHORIZATION_HEADER_NAME,
useValue: apiUtilsConfig.authorizationHeaderName
}
]
});
polly = new Polly('ngx-api-utils');
Expand Down
11 changes: 2 additions & 9 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NgxApiUtilsModule } from 'ngx-api-utils';
import { CoreModule } from './core/core.module';

@NgModule({
Expand All @@ -13,16 +12,10 @@ import { CoreModule } from './core/core.module';
imports: [
BrowserModule,
AppRoutingModule,
NgxApiUtilsModule.forRoot({
baseUrl: '//localhost:3000',
authTokenAutoRemove: true,
authGuardPublicOnlyRoutes: /^\/(customer\/auth)([\/#?].*)?$/,
authGuardUrlForAuthenticated: '/customer/',
authGuardUrlForAuthentication: '/customer/auth/sign-in'
}),
CoreModule.forRoot()
],
providers: [],
providers: [
],
bootstrap: [AppComponent]
})
export class AppModule { }
28 changes: 27 additions & 1 deletion src/app/core/core.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { NgModule, Optional, SkipSelf } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ModuleWithProviders } from '@angular/compiler/src/core';
import { TokenDecoder } from 'ngx-api-utils';
import {
TokenDecoder,
NgxApiUtilsModule,
API_HTTP_BASE_URL,
API_AUTH_GUARD_PUBLIC_ONLY_ROUTES,
API_AUTH_GUARD_URL_FOR_AUTHENTICATION,
API_AUTH_GUARD_URL_FOR_AUTHENTICATED
} from 'ngx-api-utils';
import { JwtTokenDecoderService } from './fake-api/jwt-token-decoder/jwt-token-decoder.service';

export const publicOnlyRoutesRegexp = /^\/(customer\/auth)([\/#?].*)?$/;

@NgModule({
imports: [
CommonModule
Expand All @@ -21,6 +30,23 @@ export class CoreModule {
return {
ngModule: CoreModule,
providers: [
NgxApiUtilsModule,
{
provide: API_HTTP_BASE_URL,
useValue: '//localhost:3000'
},
{
provide: API_AUTH_GUARD_PUBLIC_ONLY_ROUTES,
useValue: publicOnlyRoutesRegexp
},
{
provide: API_AUTH_GUARD_URL_FOR_AUTHENTICATED,
useValue: '/customer/'
},
{
provide: API_AUTH_GUARD_URL_FOR_AUTHENTICATION,
useValue: '/customer/'
},
{
provide: TokenDecoder,
useClass: JwtTokenDecoderService
Expand Down

0 comments on commit 276f50a

Please sign in to comment.