README
Common information
This micro-framework created to help implement NodeJS backend applications with TypeScript without pain. The main idea is to provide several abstractions and tools to increase development speed and use popular used technologies as built-in features powered by TypeScript and also add ability for extension without losing flexibility. We use ExpressJS as core technology.
Table of contents
Installation
npm i @scythe/core
or yarn add @scythe/core
Usage
To create application you can use ScytheApplicationBuilder
(see below for more information).
import { ScytheApplicationBuilder } from '@scythe/core';
export const testApp = new ScytheApplicationBuilder().build();
This module will export instance of ScytheApplication
(see below for more information) all you need to do is to call start
method.
Let's make it more complex and create endpoint to get sample string. Logic part that contain routing, docs and middleware definitions called controller. Controller is abstract class with TypeScript decorators for storing metadata upon which routing, OpenAPI documentation, middlewares logic etc are generated.
import { controller, get, summary, description, response } from '@scythe/core';
@controller('/test', 'Test')
export abstract class TestController {
@get()
@summary('Test')
@description('Test description')
@response(200, 'string')
public testGet() {
return 'sample string';
}
}
And update main application file to
import { ScytheApplicationBuilder } from '@scythe/core';
import { TestController } from './TestController';
export const testApp = new ScytheApplicationBuilder().addController(TestController).build();
This will create express server on 3030 port with 2 endpoints:
- GET /test - which will return sample string
- GET /swagger - which will render swagger docks by metadata from decorators
To add more endpoints just define more methods with decorators (to see all available decorators keep reading).
Built-in features
.env
All .env variables will be available throught proces.env[VARIABLE_NAME]
.
This particular module use only one variable is:
PORT = 3030 //defines your server port
Scythe Application Builder
This tool helps you to build Scythe Application (you can also use ScytheApplication
class itself). Base example was provided in usage section.
ScytheApplicationBuilder
methods:
Available .setConfig(config: IConfig): ScytheApplicationBuilder
Sets config for the application. Available fields:
withoutServer?: boolean
- if sets to true, application will be started without express servervalidateRequests?: boolean
- sets validation for requests according to open API schema (see more in OpenAPI validation section)validateResponse?: boolean
- sets validation for responses according to open API schema (see more in OpenAPI validation section)hydrateOpenAPIModels?: boolean
- enables hydration by OpenAPI docksopenAPIInfo?: InfoObject
- info object for OpenAPI docsopenAPIDocksEndpoint?: string
- endpoint to open api docs UI generated from metadata
Default config is:
validateResponse: true
validateRequests: true
.setLogPath(path: string): ScytheApplicationBuilder
Sets path to application log file. Default path is ./logs/application.log
.addRouter(url: PathParams, router: IBuiltRouter): ScytheApplicationBuilder
Adds router created by ScytheRouterBuilder
, which will be mounted on url
passed in params
.addModule(module): ScytheApplicationBuilder
Adds custom module to your application (more about modules see in https://www.npmjs.com/package/@scythe/types
.addAdditionalMiddleware(middleware: RequestHandler): ScytheApplicationBuilder
Adds additional middleware into middlewares poll. Accept ordinary express middleware as param
.addJob(schedule: string, job: TJobHandler): ScytheApplicationBuilder
Schedule a job to be executed by timetable. Params:
- schedule: string - CRON schedule string
- job: Function - function to be executed
.addController(Controller: any, basePath?: string): ScytheApplicationBuilder
Adds controller to current application to be mounted on basePath.
Controller is abstract class decorated with @controller decorator (see more in decorators section)
.build(): ScytheApplication
Builds ScytheApplication
based on provided info
Scythe Application
Base application class which contains almost all necessary logic.
ScytheApplication
methods
Available constructor(config: IConfig, logPath: string, additionalMiddlewares: RequestHandler[] = [])
Inits application with provided params:
config
withoutServer?: boolean
- if sets to true, application will be started without express servervalidateRequests?: boolean
- sets validation for requests according to open API schema (see more in OpenAPI validation section)validateResponse?: boolean
- sets validation for responses according to open API schema (see more in OpenAPI validation section)hydrateOpenAPIModels?: boolean
- enables hydration by OpenAPI docksopenAPIInfo?: InfoObject
- info object for OpenAPI docsopenAPIDocksEndpoint?: string
- endpoint to open api docs UI generated from metadata
logPath
Path to application log file
additionalMiddlewares
Array of express middlewares to be applied
.addRouter(url: PathParams, router: IBuiltRouter): void
Adds router created by ScytheRouterBuilder
, which will be mounted on url
passed in params
.addModule(module): void
Adds custom module to your application (more about modules see in https://www.npmjs.com/package/@scythe/types
.start(): void
Starts an application running all modules and creating express servers if needs to
.addJob(schedule: string, job: TJobHandler): void
Schedule a job to be executed by timetable. Params:
- schedule: string - CRON schedule string
- job: Function - function to be executed
.registerController(Controller: any, basePath?: string): void
Adds controller to current application to be mounted on basePath.
Controller is abstract class decorated with @controller
or @webSocketController
decorator (see more in decorators section)
.stop(): void
Stops application destroying connections and stopping jobs and modules
.getOpenAPIDocs(): OpenAPIObject
Return generated open API docs
Routing
Decorators
This framework provides amount of decorators to create controller to simplify working with routing/docs/validation ets.
Available decorators:
@controller(path: string, tag?: string): ClassDecorator
Sets decorated class as controller. All methods inside will be mounted on path from params. If tag param is passed, all endpoints will have this open API tag by default
@baseSecurity(securitySchema: string): ClassDecorator
Sets base security schema for controller. Accept name of open API defined security schema
@commonMiddlewares(...middlewares: RequestHandler[]): ClassDecorator
Sets common middlewares to be executed before each method logic in controller
@method(method: string, path: string = '/'): MethodDecorator
Binds http method to class method. If class method decorated with it, it will be treated as endpoint by passed path
@get(path: string = '/'): MethodDecorator
Alias for get method
@put(path: string = '/'): MethodDecorator
Alias for put method
@del(path: string = '/'): MethodDecorator
Alias for delete method
@post(path: string = '/'): MethodDecorator
Alias for post method
@patch(path: string = '/'): MethodDecorator
Alias for patch method
@middlewares(...middlewares: RequestHandler[]): MethodDecorator
Sets middlewares to be executed before method logic in controller
@tag(tag: string): MethodDecorator
Sets open API tag
@summary(summary: string): MethodDecorator
Sets Open API summary
@description(description: string): MethodDecorator
Sets Open API description
@response(responseCode: number, type: string | INewable, isArray: boolean = false): MethodDecorator
Sets Open API response by path as Open API schema reference with selected response status code
@defaultResponses(...responses: EDefaultResponse[]): MethodDecorator
Sets predefined responses. Can be:
- EDefaultResponse.NotFound
- EDefaultResponse.NoContent
- EDefaultResponse.Unauthorized
- EDefaultResponse.Forbidden
- EDefaultResponse.ValidationError
@parameters(...parameters: ParameterObject[]): MethodDecorator
Sets Open API parameters
@headerParameter(name: string, schema: string, required: boolean = true): MethodDecorator
Sets Open API header parameter by its schema reference name
@security(name: string): MethodDecorator
Sets Open API security schema by its name
@deprecated(): MethodDecorator
Mark endpoint as deprecated
Scythe Router Builder
Builder for express routing implementation, it provides extended version of express router by adding methods to write open API docs.
Should be used only if controllers do not cover your case.
Usage:
import { ScytheRouterBuilder } from '@scythe/core';
const builder = new ScytheRouterBuilder();
builder
.useNamespace('/yourPath')
.useOpenAPIDocs({
get: {
tags: ['Your Tags'],
summary: 'Summary',
description: 'Descrition',
consumes: ['application/json'],
produces: ['application/json'],
parameters: [{ name: 'filter', description: 'filter', required: false, type: 'string', in: 'query' }],
responses: {
'200': {
description: 'description',
type: 'array',
items: {
$ref: '#/definitions/swagerSchemaName'
}
}
}
}
})
.buildNamespace()
.get(yourMiddlewaresGoesHere);
export const awesomeRouter = builder.buildRouter();
Available methods:
.useNamespace(namespace: string): ScytheRouterBuilder
Define route namespace (ex. /users
, /users/:id
)
.useOpenAPIDocs(specs: PathItemObject): ScytheRouterBuilder
Sets OpenAPI docs for your namespace
.setOpenAPIComponents(schema)
Sets OpenAPI definitions for your router
.buildNamespace()
Builds namespace and return express router route instance, where you can add any request methods
.buildRouter()
Builds router to be passed into ScytheApplication
or ScytheApplicationBuilder
Open API
This framework provides full set of types of Open API v3, so it'll be easy for you to implement all definitions.
Open API Components Builder
This builder helps you create Open API definition to pass into controller or router builder
Available methods:
.useOpenAPISchemas(schemas: TOpenAPISchemas): OpenAPIComponentsBuilder
Sets Open API schemas according to Open API v3
.useOpenAPIResponses(responses: TOpenAPIResponses): OpenAPIComponentsBuilder
Sets Open API responses according to Open API v3
.useOpenAPIParameters(parameters: TOpenAPIParameters): OpenAPIComponentsBuilder
Sets Open API parameters according to Open API v3
.useOpenAPIExamples(examples: TOpenAPIExamples): OpenAPIComponentsBuilder
Sets Open API examples according to Open API v3
.useOpenAPIRequestBodies(requestBodies: TOpenAPIRequestBodies): OpenAPIComponentsBuilder
Sets Open API request bodies according to Open API v3
.useOpenAPIHeaders(headers: TOpenAPIHeaders): OpenAPIComponentsBuilder
Sets Open API headers according to Open API v3
.useOpenAPISecuritySchemas(securitySchemas: TOpenAPISecuritySchemas): OpenAPIComponentsBuilder
Sets Open API security schemas according to Open API v3
.useOpenAPILinks(links: TOpenAPILinks): OpenAPIComponentsBuilder
Sets Open API links according to Open API v3
.useOpenAPICallbacks(callbacks: TOpenAPICallbacks): OpenAPIComponentsBuilder
Sets Open API callbacks according to Open API v3
.buildComponents()
Builds all components to be passed into @registerComponents decorator or into router builder
Open API Helpers
This part provides amount of function helpers to ease Open API components writing
Available helpers:
getQueryParam(name: string, schema: SchemaObject | ReferenceObject, required: boolean = true)
Generates Open API query param component
Example:
{
name: 'test', in: 'query', schema: { $ref: '#/components/schemas/test' }, required: true}
createRefContent(schemaName: string, isArray: boolean = false)
Creates Open API json content based on schema.
Example:
{
content: { 'application/json': { schema: { $ref: '#/components/schemas/test' } } }}
createSchemaContent(schema: SchemaObject)
Same as createRefContent
only take Open API schema object
getRefObject(name: string, type: EComponentTypes = EComponentTypes.Schemas)
Generates Open API ref object by passed type. Available types:
- EComponentTypes.Schemas
- EComponentTypes.RequestBodies
- EComponentTypes.Responses
- EComponentTypes.Parameters
- EComponentTypes.Examples
- EComponentTypes.Headers
- EComponentTypes.SecuritySchemas
- EComponentTypes.Links
- EComponentTypes.Callbacks
Example:
{
$ref: '#/componens/headers/TestHeader'}
createValidationError(dataPath: string, message: string)
Return object representation of Open API validation error object (same object returns by Open API Validator)
Example:
{
error: { message: 'Validation error', details: [{ dataPath: '.body.test', message: 'should be string' }] }}
Open API Validator
If pass
validateResponse: true
validateRequests: true
into your application, all your responses/requests will be validated according to your Open API definitions.