4.0.2 • Published 12 months ago

@bakku/platform v4.0.2

Weekly downloads
-
License
MIT
Repository
-
Last release
12 months ago

1 Install & Use

1.1 Install

npm: npm install @bakku/platform yarn: yarn install @bakku/platform

1.2 Use

refer Sample Project

startServer

startServer(
  appOptions?: TypeServerOptions,
  createExpressApp?: () => Express,
  ssl?: https.ServerOptions
)
nametyperequireddefaultdescription
appOptionsTypeServerOptionsNOinput information for setting app
createExpressApp() => ExpressNOcreateAppcustom create express instance, base on that for create APIs. Default createApp function in platform
sslhttps.ServerOptionsNOcase use directive SSL for server

TypeServerOptions:

nametyperequireddefaultdescription
hoststringNOhost which server will be used, should be 0.0.0.0
portnumberNO8080port which server will be used
apiPrefixstringNOprefix for all API => https://domain/[prefix]/[controller.paht]/[controller.apiPath]
loggerlog objectNOconsolecustom logging
appHandlersExRequestHandler[]NOArray handler for express application, EX: CORS, userMiddleware...
staticHandlerskey: string: ExRequestHandlerExRequestHandler[]NOstatic handlers, often use for static file
documentOptionsTypeDocumentHandlersNOconfig for display APIs document
documentOptionsTypeDocumentHandlersNOconfig for display APIs document
errorHandlerOptionsTypeErrorHandlersNOHandle error default
bodyJsonSettingbodyParser.OptionsJsonNOconfig for parse json data in express: express.json(..)
appSettingskey: string: anyNOconfig for app use any setting. EX: convert date format, json...

Example:

  const options: TypeServerOptions = {
    apiPrefix: 'api', // => all your APis will be have prefix : /api/...
    logger: global.applicationContexts.logger,

    documentOptions: {
      docPath: 'doc', // => API document page
    },
  };
  startServer(options);

2 Detail

2.1 Controller

@Controller({
  name: string | symbol,
  path: string,
  description?: string
})

EX:

@Controller({
  name: 'HomeController',
  path: 'home',
})
export class HomeController {
 ....
}

2.2 API methods

CommonType

@API(option: { type: TypeRequestMethod; path: string; description?: string; bodyContentType?: string; }): define any API

Note: TypeRequestMethod: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'all'

DetailType:

@Get(path: string, description?: string): define Get API

@Delete(path: string, description?: string): define Delete API

@Post(path: string, description?: string, bodyContentType?: string): define Post API

@Put(path: string, description?: string, bodyContentType?: string): define Put API

@Patch(path: string, description?: string, bodyContentType?: string): define Patch API

@UseAll(path: string, description?: string, bodyContentType?: string): define UseAll API

2.3 Middleware

2.3.1 @Middleware(ExRequestHandler | ExRequestHandler[]): define middleware for each API

Note: ExRequestHandler is RequestHandler - (req, res, next) : void EX:

const requireLoggedInMiddleWare = async ( req: ExRequest, _res: ExResponse, next: ExNextFunction) => {
  let user;
  // check user from header token
  //....
  if (!user) throw new Error('You need to login first!');
  req.user = user;
  next();
};

@Controller({
  name: 'HomeController',
  path: 'home',
})
export class HomeController {
  @Get('user')
  @Middleware(requireLoggedInMiddleWare)
  doSomething(@Req() req: ExRequest) {
    return req.user;
  }
}

2.3.2 @MiddlewareCustom( () => ExRequestHandler): define middleware for each API

const customRequireAdminInMiddleWare =() => {
  // get roles
  const adminRoles = ...// do somethings.
  return async ( req: ExRequest, \_res: ExResponse, next: ExNextFunction) => {
    let user;
    // check user from header token
    //....
    if (!user || !user.role || !adminRole.includes(user.role)) throw new Error('You are not allow process this feature!');
    req.user = user;
    next();
  }
};

@Controller({
name: 'HomeController',
path: 'home',
})
export class HomeController {
  @Get('admin')
  @MiddlewareCustom(customRequireAdminInMiddleWare)
  doSomething(@Req() req: ExRequest) {
    return req.user;
  }
}

2.4 Data from request

2.4.1 Data from header @Headers()

@Controller({
name: 'HomeController',
path: 'home',
})
export class HomeController {
  @Get('admin')
  doSomething(
    @Headers() headers: any,
  ) {
    return {headers};
  }
}

2.4.2 Data from queries @Queries()

@Controller({
name: 'HomeController',
path: 'home',
})
export class HomeController {
  @Post('test')
  doSomething(
    @Queries() queries: any,
  ) {
    return {queries};
  }
}

2.4.3 Data from params @Params()

@Controller({
name: 'HomeController',
path: 'home',
})
export class HomeController {
  @Post('test')
  doSomething(
    @Params() params: any,
  ) {
    return {params};
  }
}

2.4.4 Data from body

@Body()

@Controller({
name: 'HomeController',
path: 'home',
})
export class HomeController {
  @Post('test')
  doSomething(
    @Body() body: any,
  ) {
    return {body};
  }
}

2.4.5 get all request

@Req()

@Controller({
name: 'HomeController',
path: 'home',
})
export class HomeController {
  @Post('test')
  doSomething(
    @Req() req: ExRequest,
  ) {
    console.log(req.header, req.body, ...)
    return {ok: true};
  }
}

2.4.5 get all response

@Res()

@Controller({
name: 'HomeController',
path: 'home',
})
export class HomeController {
  @Post('test')
  doSomething(
    @Res() res: ExResponse,
  ) {
    console.log(res.header,, ...)
    return {ok: true};
  }
}

2.4 Data for response

In normal when request success, the response will received the returned data from controller method and use it as body data.

I Error case:

  Response:
    header:
      status: statusCode
    body:
      error: {
        status: statusCode,
        code: errorCode, //base on requirement
        message: errorMessage //base on requirement
      }

3. Validation

refer @bakku/validation

Validation base on schema when getting data from request.

3.1 Use schema for any data

For validation auto run, pass the corresponding validation schema.

EX:

const HeaderSecretDataSchema: IObjectSchema = {
  type: 'object',
  validation: { isRequired: true },
  properties: {
    'apikey': StringRequireSchema,
  },
};

@Controller({
name: 'HomeController',
path: 'home',
})
export class HomeController {
  @Get('admin')
  doSomething(
    @Headers(HeaderSecretDataSchema) headers: any,
  ) {
    // header.apikey will be validate as required, if not it will throw error
    return {headers};
  }
}

=====================
=> response:
  header: 400
  body: {
    error: {
      status: 400,
      code: ...
      message: 'headers.apikey' are required
    }
  }

Note: the same for other data:

@Body(schema) body: any

@Queries(schema) body: any

@Params(schema) body: any

3.2 Use class with DI

@DI(options: IDataPropertyInjectedParams)

IDataPropertyInjectedParams is extends data from ISchemaGeneral of @bakku/validation with:

options.sample // sample data for displaying in document api

options.description //// description data for displaying in document api

3.2.1 Common data

@DataProperty - require data

@DataPropertyOptional - not require data

EX:

class CreateAccountRequestBodyDto {
  @DataProperty({ validation: { format: 'isEmail' } })
  email: string;

  @DataProperty({ validation: { format: new RegExp('^(?=.*?[0-9])(?=.*[!@#$%^&*])(?=.*[a-z])(?=.*[A-Z]).{8,}$') } })
  password: string;
}

//==> Result:
....
@Body() body: CreateAccountRequestBodyDto,
...

3.2.2 Data is enum

@DataEnumProperty -

@DataEnumPropertyOptional

EX:

enum AccountType {
  USER = 'USER',
  MANAGER = 'MANAGER',
}

class CreateAccountRequestBodyDto {
  ...
  @DataEnumProperty({ enumData: getEnumData(AccountType) })
  accountType: AccountType;
  ...
}

//==> Result:
....
@Body() body: CreateAccountRequestBodyDto,
...

3.2.3 Data is array

@DataArrayProperty -

@DataArrayPropertyOptional

EX:

class Person {
  @DataProperty()
  name:
}
const  StringSchema: IStringSchema = { type: 'string' };
class RequestBodyDto {
  ...
  @DataArrayProperty({ itemSchema: { propertyType: Person } })
  listPerson: Person[];

  @DataArrayProperty({ itemSchema: StringSchema })
  listMessages: string[];
  ...
}

//==> Result:
....
@Body() body: RequestBodyDto,
...

3.2.5 Data is file upload

@DataFileProperty -

@DataFilePropertyOptional

4 Special cases

4.1 Self handle app error:

  const options: TypeServerOptions = {
    apiPrefix: 'api',
    errorHandlerOptions: {
      isSelfHandleError: true,
    },
  };
  const { app } = startServer(options);
  routeAppError(app, options);

4.2 Using swagger document API.

using with swagger-ui-express

Note: because default handle error will force all APIs which is defined after start server is not found APIs. So for prevent it, and define API for swagger, should use combine with custom handle error above.

  ....
  import swaggerUi from 'swagger-ui-express';
  ....
  const options: TypeServerOptions = {
    apiPrefix: 'api',
    errorHandlerOptions: {
      isSelfHandleError: true,
    },
  };
  const { app, apiData } = startServer(options);
  const swaggerJson = convertToSwaggerJson(apiData);
  app.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerJson));
  routeAppError(app, options);
  ...

4.3 Custom data response.

4.0.2

12 months ago

4.0.1

1 year ago

4.0.0

1 year ago

3.6.15

2 years ago

3.6.14

2 years ago

3.6.13

2 years ago

3.6.12

2 years ago

3.6.11

2 years ago

3.6.10

2 years ago

3.6.6

2 years ago

3.6.5

2 years ago

3.6.4

2 years ago

3.6.3

2 years ago

3.6.8

2 years ago

3.6.7

2 years ago

3.4.0

2 years ago

3.6.2

2 years ago

3.6.1

2 years ago

3.6.0

2 years ago

3.5.1

2 years ago

3.5.0

2 years ago

3.3.1

2 years ago

3.3.0

2 years ago

3.2.0

2 years ago

3.0.24

2 years ago

3.0.21

2 years ago

3.0.22

2 years ago

3.0.20

2 years ago

3.0.18

2 years ago

3.0.19

2 years ago

3.0.9

2 years ago

3.0.12

2 years ago

3.0.4

2 years ago

3.0.13

2 years ago

3.0.10

2 years ago

3.0.11

2 years ago

3.0.1

2 years ago

3.0.16

2 years ago

3.0.8

2 years ago

3.0.17

2 years ago

3.0.7

2 years ago

3.0.14

2 years ago

3.0.6

2 years ago

3.0.15

2 years ago

3.0.5

2 years ago

3.0.0

2 years ago

1.0.7

2 years ago

1.0.6

2 years ago

1.0.5

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago