@ronas-it/angular-common
v18.2.0
Published
Common Angular services for communicating with backend, authentication and user managing.
Keywords
Readme
Ronas IT Angular Common
Common Angular services for communicating with backend, authentication and user managing.
Live demo
In progress...
About the library
Ronas IT Angular Common working with cookies. One of the main advantages of this approach is that cookies can be HTTP-only. It makes them read-protected on the client side, that improves safety against any Cross-site scripting (XSS) attacks. Cookie-based authentication allows using this services in Server-Side Rendering (SSR) applications.
Getting Started
Installation
Install Ronas IT Angular Common:
npm i @ronas-it/angular-common --saveUsage
ApiModule
- Add
ApiModuletoAppModuleimports:
import { ApiModule } from '@ronas-it/angular-common';
import { configuration } from '@configuration';
@NgModule({
imports: [
ApiModule.forRoot({
apiUrl: configuration.api.url
}),
...
],
...
})
export class AppModule { }- Inject
ApiServiceand use it:
import { ApiService } from '@ronas-it/angular-common';
import { Injectable } from '@angular/core';
@Injectable()
export class ProductService {
constructor(
private apiService: ApiService
) { }
public delete(id: number): Observable<void> {
return this.apiService.delete(`/products/${id}`);
}
...
}CookieModule
- Add
CookieModuletoAppModuleimports:
import { CookieModule } from '@ronas-it/angular-common';
@NgModule({
imports: [
CookieModule.forRoot({
defaultOptions: { path: '/', /* other cookie options ... */ }
}),
...
],
...
})
export class AppModule { }- Inject
CookieServiceand use it:
import { BehaviorSubject, Subject } from 'rxjs';
import { CookieService } from '@ronas-it/angular-common';
import { Injectable } from '@angular/core';
@Injectable()
export class CookiePopupFacade {
private isCookiesAccepted$: Subject<boolean>;
constructor(
private cookieService: CookieService
) {
this.isCookiesAccepted$ = new BehaviorSubject(this.cookieService.get('isCookiesAccepted') === 'true');
}
public acceptCookies(): void {
this.isCookiesAccepted$.next(true);
this.cookieService.put('isCookiesAccepted', 'true', { maxAge: 4e10 });
}
...
}- (SSR Only) Add providers for
REQUESTandRESPONSEinjection tokens from@nguniversal/express-engine/tokensinserver.ts:
server.get('*', (req, res) => {
res.render(indexHtml, {
req,
res,
providers: [
{
provide: APP_BASE_HREF,
useValue: req.baseUrl
},
{
provide: REQUEST,
useValue: req
},
{
provide: RESPONSE,
useValue: res
}
]
});
});- (SSR Only) Set
requestTokenandresponseTokenparameters in theCookieModuleconfig:
import { CookieModule } from '@ronas-it/angular-common';
import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';
@NgModule({
imports: [
CookieModule.forRoot({
defaultOptions: { /* ... */ },
requestToken: REQUEST,
responseToken: RESPONSE
}),
...
],
...
})
export class AppModule { }UserModule
Note: This module depends on ApiModule and AuthModule. Please make sure to
install them prior to installing this module.
- Create a
Usermodel and extend it fromAbstractUser:
import { AbstractUser } from '@ronas-it/angular-common';
import { Expose } from 'class-transformer';
export class User extends AbstractUser {
@Expose({ groups: ['main'] })
public id: number;
@Expose({ groups: ['main'] })
public name: string;
@Expose({ groups: ['main'] })
public email: string;
}- Create a
UserServiceand extend it fromCommonUserService:
import { UserService as CommonUserService } from '@ronas-it/angular-common';
@Injectable()
export class UserService extends CommonUserService<User> {
/* Define custom methods or override existing methods here. */
}- Create a
UserModuleand addCommonUserModuleto imports:
import { NgModule } from '@angular/core';
import { User } from './models';
import { UserModule as CommonUserModule } from '@ronas-it/angular-common';
import { UserService } from './user.service';
@NgModule({
imports: [
CommonUserModule.forRoot({
userModel: User,
userService: UserService
}),
...
],
...
})
export class UserModule { }- Inject
UserServiceand use it:
import { Action } from '@ngrx/store';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { AuthService } from '@shared/auth';
import { catchError, filter, mergeMap, switchMap, withLatestFrom } from 'rxjs/operators';
import { HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { User } from '../models';
import { userActions } from './actions';
import { UserService } from '../user.service';
@Injectable()
export class UserEffects {
public refreshProfile$: Observable<Action> = createEffect(
() => this.actions$.pipe(
ofType(userActions.refreshProfile),
withLatestFrom(this.authService.isAuthenticated$),
filter(([_, isAuthenticated]) => isAuthenticated),
switchMap(() => {
return this.userService.refreshProfile()
.pipe(
mergeMap((user: User) => [
userActions.updateProfile({ profile: user }),
userActions.refreshProfileSuccess()
]),
catchError((response: HttpErrorResponse) => of(userActions.refreshProfileFailure({ response })))
);
})
)
);
constructor(
private actions$: Actions,
private authService: AuthService,
private userService: UserService
) { }
}AuthModule
Note: This module depends on ApiModule, CookieModule and UserModule. Please make sure to
install them prior to installing this module.
- Create an
AuthServiceand extend it fromCommonAuthService:
import { AuthService as CommonAuthService } from '@ronas-it/angular-common';
import { Injectable } from '@angular/core';
import { User } from '@shared/user';
@Injectable()
export class AuthService extends CommonAuthService<User> {
/* Define custom methods or override existing methods here. */
}- Create an
AuthModuleand addCommonAuthModuleto imports:
import { AuthModule as CommonAuthModule } from '@ronas-it/angular-common';
import { AuthService } from './auth.service';
import { configuration } from '@configuration';
import { NgModule } from '@angular/core';
@NgModule({
imports: [
CommonAuthModule.forRoot({
unauthorizedRoutes: configuration.api.unauthorized_routes,
authService: AuthService,
// Optionally, you can pass `unauthenticatedRoute` parameter that
// specifies the route to redirect to after logout or when a user is
// not authenticated to view some page. By default it is set to `/login`.
unauthenticatedRoute: '/'
}),
...
],
...
})
export class AuthModule { }- Inject
AuthServiceand use it:
import { Action } from '@ngrx/store';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { authActions } from './actions';
import { AuthService } from '../auth.service';
import { catchError, exhaustMap, map } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
@Injectable()
export class AuthEffects {
public authorize$: Observable<Action> = createEffect(
() => this.actions$.pipe(
ofType(authActions.authorize),
exhaustMap((action) => {
return this.authService
.authorize(action.credentials)
.pipe(
map((response) => authActions.authSuccess({ response })),
catchError((response) => of(authActions.authFailure({ response })))
);
})
)
);
constructor(
private actions$: Actions,
private authService: AuthService
) { }
}API
ApiModule
Config
ApiModule.forRoot(config: ApiConfig)ApiConfig
Name | Type | Required | Description
--- | --- | --- | ---
apiUrl | string | Yes | Endpoint that allows you to access an API
trailingSlash | boolean | No | The need for trailing slash (https://api.your-service.com/login/ for example)
enableArrayKeys | boolean | No | Enabling array keys for http params
fileKeys | Array<string> | No | List of the file keys for http params
ApiService
Field | Type
--- | ---
apiUrl | string
trailingSlash | string
fileKeys | Array<string>
Method | Arguments | Return type
--- | --- | ---
get<T> | endpoint: string, params: any, options: object | Observable<T>
post<T> | endpoint: string, data: any, options: object | Observable<T>
put<T> | endpoint: string, data: any, options: object | Observable<T>
delete<T> | endpoint: string, params: any, options: object | Observable<T>
CookieModule
Config
CookieModule.forRoot(config: CookieConfig)CookieConfig
Name | Type | Required | Description
--- | --- | --- | ---
defaultOptions | CookieOptions | No | Cookie options that will be used if not specified in the put method
requestToken | InjectionToken<Request> | No | Request injection token from @nguniversal/express-engine/tokens for cookies support in SSR
responseToken | InjectionToken<Response> | No | Response injection token from @nguniversal/express-engine/tokens for cookies support in SSR
CookieOptions
Name | Type
--- | ---
maxAge | number
expires | Date
path | string
domain | string
secure | boolean
sameSite | boolean \| 'lax' \| 'strict' \| 'none'
CookieService<TKey extends string = string>
Field | Type
--- | ---
cookieString | string
Method | Arguments | Return type
--- | --- | ---
get | key: TKey | string \| null
getObject | key: TKey | object \| null
getAll | | Record<string, string>
hasKey | key: TKey | boolean
put | key: TKey, value: string, options?: CookieOptions | void
putObject | key: TKey, value: object, options?: CookieOptions | void
remove | key: TKey, options?: CookieOptions | void
removeAll | options?: CookieOptions | void
AuthModule
Config
CommonAuthModule.forRoot(config: AuthConfig)AuthConfig
Name | Type | Required | Description
--- | --- | --- | ---
unauthorizedRoutes | Array<string> | Yes | Routes that don't need authorization (public routes, e.g. login, registration and forgot password pages)
authService | new (...args: Array<any>) => any | Yes | Service that will be used in your app
unauthenticatedRoute | string | No | Route to redirect to after logout or when a user is not authenticated to view some page. By default it is set to /login
disableRedirectAfterUnauthorize | boolean | No | Whether to redirect to unauthenticatedRoute after logout or when a user is not authenticated to view some page. By default it is set to false
authenticatedRoute | string | No | Route to redirect after successful login
loginEndpoint | string | No | Endpoint for login, e.g. /api/token
refreshTokenEndpoint | string | No | Endpoint for refreshing token, e.g. /api/token/refresh
refreshTokenEndpointMethod | 'get' \| 'post' | No | HTTP Method that will be used for calling endpoint to refresh token
isAuthenticatedField | string | No | Field for cookie
rememberField | string | No | Field for cookie
cookiesExpirationDays | number | No | Expiration for authentication cookies when call authorize with remember flag set to true. By default it is set to 365
AuthService<User extends AbstractUser>
Static constant | Type
--- | ---
DEFAULT_LOGIN_ENDPOINT | string
DEFAULT_UNAUTHENTICATED_ROUTE | string
DEFAULT_IS_AUTHENTICATED_FIELD | string
DEFAULT_REFRESH_TOKEN_ENDPOINT | string
DEFAULT_REMEMBER_FIELD | string
DEFAULT_COOKIES_EXPIRATION_DAYS | number
Field | Type
--- | ---
isTokenRefreshing$ | Observable<boolean>
isAuthenticated$ | Observable<boolean>
cookiesExpiresDate | Date
Method | Arguments | Return type
--- | --- | ---
authorize<T> | credentials: AuthCredentials & T, remember: boolean | Observable<AuthResponse<User>>
manuallyAuthorize | authResponse: object, remember: boolean = true | Observable<AuthResponse<User>>
unauthorize | | void
refreshToken | | Observable<HttpResponse<void>>
setIsAuthenticated | remember: boolean | void
resetIsAuthenticated | | void
resetRemember | | void
AuthCredentials
Field | Type | Required
--- | --- | ---
email | string | No
password | string | Yes
AuthResponse<User extends AbstractUser>
Field | Type | Required
--- | --- | ---
user | User | No
UserModule
Config
UserModule.forRoot(config: UserConfig)UserConfig
Name | Type | Required | Description
--- | --- | --- | ---
userModel | new (user: any) => any | Yes | Model (class) for user
userService | new (...args: Array<any>) => any | Yes | Your UserService implementation
profileRelations | Array<string> | No | Relations for getting profile request. For example: /profile?with[]=company&with[]=clients
profileRelationsKey | string | No | with by default
UserService<User extends AbstractUser>
Field | Type
--- | ---
profile$ | Observable<User>
Method | Arguments | Return type
--- | --- | ---
refreshProfile | | Observable<User>
loadProfile | | Observable<User>
updateProfile | user: User | Observable<void>
updatePassword | userPasswords: UserPasswords | Observable<void>
setProfile | user: User | void
patchProfile | user: Partial<User> | void
resetRemember | | void
resetProfile | | void
userToPlain | user: User, options?: ClassTransformOptions | Object
plainToUser | plain: object, options?: ClassTransformOptions | User
AbstractUser
Field | Type | Required
--- | --- | ---
id | number \| string | Yes
Contributing
Contributions to Ronas IT Angular Common are welcome. The contribution guide can be found in the Contributing guide.
License
Ronas IT Angular Common is open-sourced software licensed under the MIT license.
