15.2.0 • Published 1 year ago

@ronas-it/angular-common v15.2.0

Weekly downloads
34
License
-
Repository
-
Last release
1 year ago

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 --save

Usage

ApiModule

  1. Add ApiModule to AppModule imports:
import { ApiModule } from '@ronas-it/angular-common';
import { configuration } from '@configuration';

@NgModule({
  imports: [
    ApiModule.forRoot({
      apiUrl: configuration.api.url
    }),
    ...
  ],
  ...
})
export class AppModule { }
  1. Inject ApiService and 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

  1. Add CookieModule to AppModule imports:
import { CookieModule } from '@ronas-it/angular-common';

@NgModule({
  imports: [
    CookieModule.forRoot({
      defaultOptions: { path: '/', /* other cookie options ... */ }
    }),
    ...
  ],
  ...
})
export class AppModule { }
  1. Inject CookieService and 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 });
  }

  ...
}
  1. (SSR Only) Add providers for REQUEST and RESPONSE injection tokens from @nguniversal/express-engine/tokens in server.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
      }
    ]
  });
});
  1. (SSR Only) Set requestToken and responseToken parameters in the CookieModule config:
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.

  1. Create a User model and extend it from AbstractUser:
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;
}
  1. Create a UserService and extend it from CommonUserService:
import { UserService as CommonUserService } from '@ronas-it/angular-common';

@Injectable()
export class UserService extends CommonUserService<User> {
  /* Define custom methods or override existing methods here. */
}
  1. Create a UserModule and add CommonUserModule to 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 { }
  1. Inject UserService and 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.

  1. Create an AuthService and extend it from CommonAuthService:
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. */
}
  1. Create an AuthModule and add CommonAuthModule to 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 { }
  1. Inject AuthService and 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
NameTypeRequiredDescription
apiUrlstringYesEndpoint that allows you to access an API
trailingSlashbooleanNoThe need for trailing slash (https://api.your-service.com/login/ for example)
enableArrayKeysbooleanNoEnabling array keys for http params
fileKeysArray<string>NoList of the file keys for http params

ApiService

FieldType
apiUrlstring
trailingSlashstring
fileKeysArray<string>
MethodArgumentsReturn type
get<T>endpoint: string, params: any, options: objectObservable<T>
post<T>endpoint: string, data: any, options: objectObservable<T>
put<T>endpoint: string, data: any, options: objectObservable<T>
delete<T>endpoint: string, params: any, options: objectObservable<T>

CookieModule

Config

CookieModule.forRoot(config: CookieConfig)
CookieConfig
NameTypeRequiredDescription
defaultOptionsCookieOptionsNoCookie options that will be used if not specified in the put method
requestTokenInjectionToken<Request>NoRequest injection token from @nguniversal/express-engine/tokens for cookies support in SSR
responseTokenInjectionToken<Response>NoResponse injection token from @nguniversal/express-engine/tokens for cookies support in SSR
CookieOptions
NameType
maxAgenumber
expiresDate
pathstring
domainstring
secureboolean
sameSiteboolean \| 'lax' \| 'strict' \| 'none'

CookieService\

FieldType
cookieStringstring
MethodArgumentsReturn type
getkey: TKeystring \| null
getObjectkey: TKeyobject \| null
getAllRecord<string, string>
hasKeykey: TKeyboolean
putkey: TKey, value: string, options?: CookieOptionsvoid
putObjectkey: TKey, value: object, options?: CookieOptionsvoid
removekey: TKey, options?: CookieOptionsvoid
removeAlloptions?: CookieOptionsvoid

AuthModule

Config

CommonAuthModule.forRoot(config: AuthConfig)
AuthConfig
NameTypeRequiredDescription
unauthorizedRoutesArray<string>YesRoutes that don't need authorization (public routes, e.g. login, registration and forgot password pages)
authServicenew (...args: Array<any>) => anyYesService that will be used in your app
unauthenticatedRoutestringNoRoute to redirect to after logout or when a user is not authenticated to view some page. By default it is set to /login
disableRedirectAfterUnauthorizebooleanNoWhether to redirect to unauthenticatedRoute after logout or when a user is not authenticated to view some page. By default it is set to false
authenticatedRoutestringNoRoute to redirect after successful login
loginEndpointstringNoEndpoint for login, e.g. /api/token
refreshTokenEndpointstringNoEndpoint for refreshing token, e.g. /api/token/refresh
refreshTokenEndpointMethod'get' \| 'post'NoHTTP Method that will be used for calling endpoint to refresh token
isAuthenticatedFieldstringNoField for cookie
rememberFieldstringNoField for cookie
cookiesExpirationDaysnumberNoExpiration for authentication cookies when call authorize with remember flag set to true. By default it is set to 365

AuthService\

Static constantType
DEFAULT_LOGIN_ENDPOINTstring
DEFAULT_UNAUTHENTICATED_ROUTEstring
DEFAULT_IS_AUTHENTICATED_FIELDstring
DEFAULT_REFRESH_TOKEN_ENDPOINTstring
DEFAULT_REMEMBER_FIELDstring
DEFAULT_COOKIES_EXPIRATION_DAYSnumber
FieldType
isTokenRefreshing$Observable<boolean>
isAuthenticated$Observable<boolean>
cookiesExpiresDateDate
MethodArgumentsReturn type
authorize<T>credentials: AuthCredentials & T, remember: booleanObservable<AuthResponse<User>>
manuallyAuthorizeauthResponse: object, remember: boolean = trueObservable<AuthResponse<User>>
unauthorizevoid
refreshTokenObservable<HttpResponse<void>>
setIsAuthenticatedremember: booleanvoid
resetIsAuthenticatedvoid
resetRemembervoid

AuthCredentials

FieldTypeRequired
emailstringNo
passwordstringYes

AuthResponse\

FieldTypeRequired
userUserNo

UserModule

Config

UserModule.forRoot(config: UserConfig)
UserConfig
NameTypeRequiredDescription
userModelnew (user: any) => anyYesModel (class) for user
userServicenew (...args: Array<any>) => anyYesYour UserService implementation
profileRelationsArray<string>NoRelations for getting profile request. For example: /profile?with[]=company&with[]=clients
profileRelationsKeystringNowith by default

UserService\

FieldType
profile$Observable<User>
MethodArgumentsReturn type
refreshProfileObservable<User>
loadProfileObservable<User>
updateProfileuser: UserObservable<void>
updatePassworduserPasswords: UserPasswordsObservable<void>
setProfileuser: Uservoid
patchProfileuser: Partial<User>void
resetRemembervoid
resetProfilevoid
userToPlainuser: User, options?: ClassTransformOptionsObject
plainToUserplain: object, options?: ClassTransformOptionsUser

AbstractUser

FieldTypeRequired
idnumber \| stringYes

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.

15.2.0

1 year ago

15.1.0

1 year ago

14.3.0

1 year ago

15.0.4

1 year ago

15.0.5

1 year ago

14.2.0

2 years ago

13.3.5

2 years ago

14.0.0

2 years ago

14.0.1

2 years ago

14.0.2

2 years ago

14.0.3

2 years ago

14.0.4

2 years ago

14.0.5

2 years ago

14.0.6

2 years ago

14.0.7

2 years ago

13.3.1

2 years ago

13.3.0

2 years ago

13.2.3

2 years ago

1.0.38

2 years ago

1.0.37

3 years ago

1.0.36

3 years ago

1.0.35

3 years ago

1.0.34

3 years ago

1.0.33

3 years ago

1.0.32

3 years ago

1.0.31

3 years ago

1.0.30

3 years ago

1.0.29

3 years ago

1.0.28

3 years ago

1.0.27

4 years ago

1.0.26

4 years ago

1.0.25

4 years ago

1.0.24

4 years ago

1.0.23

4 years ago

1.0.22

4 years ago

1.0.21

4 years ago

1.0.19

4 years ago

1.0.20

4 years ago

1.0.18

4 years ago

1.0.17

4 years ago

1.0.16

4 years ago

1.0.15

4 years ago

1.0.14

4 years ago

1.0.13

4 years ago

1.0.12

4 years ago

1.0.11

4 years ago

1.0.11-rc.0

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago

1.0.8

4 years ago

1.0.7

4 years ago

1.0.6

4 years ago

1.0.5

4 years ago

1.0.10

4 years ago

0.0.5

4 years ago

0.0.4

4 years ago

0.0.2

4 years ago