-
Notifications
You must be signed in to change notification settings - Fork 5
Application
Phat Nguyen edited this page Dec 31, 2024
·
8 revisions
# Application
APP_ENV_APPLICATION_NAME
APP_ENV_APPLICATION_TIMEZONE
APP_ENV_APPLICATION_SECRET
APP_ENV_APPLICATION_ROLES
APP_ENV_LOGGER_FOLDER_PATH
APP_ENV_DATASOURCE_NAME
APP_ENV_APPLICATION_DS_MIGRATION
APP_ENV_APPLICATION_DS_AUTHORIZE
# Server
APP_ENV_SERVER_HOST
APP_ENV_SERVER_PORT
APP_ENV_SERVER_BASE_PATH
# PostgreSQL
APP_ENV_POSTGRES_HOST
APP_ENV_POSTGRES_PORT
APP_ENV_POSTGRES_USERNAME
APP_ENV_POSTGRES_PASSWORD
APP_ENV_POSTGRES_DATABASEIn Lb-infra we can extends from 2 kind of classes:
-
BaseApplication: This abstract class is very basic which extends fromLoopback 4 -
DefaultRestApplication: This is a class that implementsBaseApplicationclass.
---
title: Application Layer
---
classDiagram
note for BootMixin "Loopback4"
note for MyApplication "This class can be define by your own"
BootMixin <|-- BaseApplication: extends
BaseApplication <|-- DefaultRestApplication: extends
Application <|.. BaseApplication : implements
BaseApplication<|-- MyApplication : extends
DefaultRestApplication<|-- MyApplication : extends
class BootMixin{ }
class Application{
<<interface>>
+ models: Set~string~
+ staticConfigure() void
+ getProjectRoot() void
+ preConfigure() void
+ postConfigure() void
}
class BaseApplication {
<<Abstract>>
# logger: ApplicationLogger
+ models: Set~string~
+ staticConfigure()* void
+ getProjectRoot()* void
+ validateEnv()* EnvironmentResult
+ declareModels()* void
+ preConfigure()* void
+ postConfigure()* void
}
class DefaultRestApplication {
<<Abstract>>
# applicationRoles: string[]
+ DefaultRestApplication(opt) void
+ getApplicationRoles () string[]
+ validateEnv() EnvironmentResult
+ declareModels() Set~string~
+ configMigration() void
+ preConfigure() void
}
class MyApplication { }
Base models which extends default models: Base Application Models
Instead of create models by hand we have:
-
defineUser(): return User model. -
defineRole(): return Role model. -
definePermission(): return Permission model. -
definePermissionMapping(): return PermissionMapping model. -
defineUserRole(): return UserRole model extendsPrincipalMixinwith principal class is Role.
- You can define models based on 5 function defined above.
- You can reuse the models which implemented from 5 those above.
// An example of using one of 5 function defined models before.
// user-role.model.ts which implemented defineUserRole()
const BaseUserRole = defineUserRole();
@model({
settings: {
postgresql: {
schema: 'public',
table: 'UserRole',
},
hiddenProperties: ['createdAt', 'modifiedAt'],
},
})
export class UserRole extends BaseUserRole {
constructor(data?: Partial<UserRole>) {
super(data);
}
}Read more: https://loopback.io/doc/en/lb4/Mixin.html
Read more: https://loopback.io/doc/en/lb4/DataSource.html
Read more: https://loopback.io/doc/en/lb4/Repository.html
Read more: https://loopback.io/doc/en/lb4/Service.html
Example creating service
export class MyService extends BaseService {
constructor(
@inject('<injection_key>') private instance: InjectionableClass,
// More injections
) {
super({ scope: MyService.name });
}
// extends methods
}import { DefaultRestApplication } from '@lb/infra';
class MyApplication extends DefaultRestApplication {
constructor(serverOptions: ApplicationConfig = {}) {
super({ serverOptions });
}
configureRepositories() {
this.logger.info('[configureRepositories] Initializing application repositories...');
this.repository(RepositoryClass)
...
}
configureServices() {
this.logger.info('[configureServices] Iniializing application services...');
this.service(ServiceClass);
...
}
configureSecurity() {
this.logger.info('[configureSecurity] Initializing application security...');
// Security - Authentication
this.bind<string>(AuthenticateKeys.APPLICATION_SECRET).to(App.SECRET);
this.bind<IAuthenticateTokenOptions>(AuthenticateKeys.TOKEN_OPTIONS).to({
tokenSecret: Authentication.ACCESS_TOKEN_SECRET,
tokenExpiresIn: Authentication.ACCESS_TOKEN_EXPIRES_IN,
refreshSecret: Authentication.REFRESH_TOKEN_SECRET,
refreshExpiresIn: Authentication.REFRESH_TOKEN_EXPIRES_IN,
});
this.component(AuthenticateComponent);
// Security - Authorization
this.bind(AuthorizerKeys.AUTHORIZE_DATASOURCE).toInjectable(PostgresDataSource);
this.component(AuthorizeComponent);
this.bind(AuthorizerKeys.ALWAYS_ALLOW_ROLES).to([FullAuthorizationRoles.SUPER_ADMIN, FullAuthorizationRoles.ADMIN]);
this.bind(AuthorizerKeys.CONFIGURE_OPTIONS).to({
confPath: path.resolve(__dirname, 'authorize_model.conf'),
useCache: false,
});
}
staticConfigure(): void {
this.static('/', path.join(__dirname, '../public'));
}
getProjectRoot(): string {
return __dirname;
}
configureMiddlewares() {
this.logger.info('[configureMiddlewares] Initializing application middlewares...');
}
preConfigure(): void {
super.preConfigure();
// Datasources
this.dataSource(PostgresHistoryDataSource);
// Middlewares
this.configureMiddlewares();
// Repositories
this.configureRepositories();
// Services
this.configureServices();
// Security
this.configureSecurity();
// Saga
SagaHelper.getInstance();
}
postConfigure(): void {
// Explorer
this.configure(RestExplorerBindings.COMPONENT).to({
path: '/explorer',
indexTitle: 'API Explorer',
});
this.component(RestExplorerComponent);
}
}
//Run application
const serverProps = {
port: +(process.env.APP_ENV_SERVER_PORT ?? 3000),
host: process.env.APP_ENV_SERVER_HOST,
basePath: process.env.APP_ENV_SERVER_BASE_PATH,
};
export const beConfigs = {
rest: {
...serverProps,
gracePeriodForClose: 5000,
openApiSpec: {
endpointMapping: {
'/openapi.json': { version: '3.0.0', format: 'json' },
'/openapi.yaml': { version: '3.0.0', format: 'yaml' },
},
servers: [{ url: process.env.APP_ENV_APPLICATION_EXPLORER_URL }],
},
cors: {
origin: '*',
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
preflightContinue: false,
optionsSuccessStatus: 204,
maxAge: 86400,
credentials: true,
},
requestBodyParser: {
json: { limit: '10mb' },
},
},
};
const runApplication = async () => {
const app = new MyApplication(beConfigs);
applicationContext.bind(BindingKeys.APPLICATION_INSTANCE).to(app);
logger.info(' Getting ready to start up %s Application...', applicationName);
await app.boot();
await app.start();
const logFolder = path.resolve(__dirname, process.env.APP_ENV_LOGGER_FOLDER_PATH ?? '').toString();
const { url } = app.restServer;
logger.info(' %s Server is now running...', applicationName);
logger.info(' Server URL: %s', url);
logger.info(' Log folder: %s', logFolder);
return app;
};APP_ENV_APPLICATION_NAME: log label
# Should configure
APP_ENV_LOGGER_FOLDER_PATH: output log folder
# Extra configure (Optional)
APP_ENV_LOGGER_DGRAM_HOST: forwared IP Address
APP_ENV_LOGGER_DGRAM_PORT: forwared Port
APP_ENV_LOGGER_DGRAM_LABEL: forwared log label
APP_ENV_LOGGER_DGRAM_LEVELS: levels allowed to send to forwared destinationExample env configs:
APP_ENV_APPLICATION_NAME=app_name
APP_ENV_LOGGER_FOLDER_PATH=./logs
APP_ENV_LOGGER_DGRAM_HOST=0.0.0.0
APP_ENV_LOGGER_DGRAM_PORT=11111
APP_ENV_LOGGER_DGRAM_LABEL=app_name
APP_ENV_LOGGER_DGRAM_LEVELS=error,emergDefault Log Levels:
error: 1 - red
alert: 1 - red
emerg: 1 - red
warn: 2 - yellow
info: 3 - green
http: 4 - magenta
verbose: 5 - gray
debug: 6 - blue
silly: 7 - gray
Minimal Technology Vietnam
Minimal Technology Vietnam