UNPKG

@jeaks03/overseer

Version:

Just another TypeScript Back-End framework

189 lines (146 loc) 7.31 kB
# Overseer Overseer is a Typescript Aspect-Oriented framework for backend which takes inspiration from Spring-boot and Angular. ## Installation Before you begin, make sure your development environment includes Node.js® and an npm package manager. ### Node.js Overseer requires Node.js version 8.x or 10.x. - To check your version, run node -v in a terminal/console window. - To get Node.js, go to nodejs.org. Creating a Overseer project is as simple as: ```bash npx @jeaks03/typescript-base -o ``` The ```npx @jeaks03/typescript-base``` part creates a base for a typescript project and the ```-o``` flag lets the installer know that it is an Overseer framework and makes the proper adjustments. ## Minimal 'Hello World' example *index.ts* ```typescript import { Overseer } from '@jeaks03/overseer-core'; Overseer.serve(module, 8000); ``` *my.controller.ts* ```typescript import { Requisite, Pathway } from '@jeaks03/overseer-core'; @Requisite export class MyController { @Pathway({ path:'/hello' }) sayHello() { return { message: 'hello world!' } } } ``` This example opens a ```http server``` that listens on port ```8000``` and registers a ```GET``` endpoint ```/hello``` that returns the "hello world" message. To start the application run: ```bash npm run dev ``` #### Explaining the magic - The ```Overseer.serve(8000)``` line lets the framework know where the **sources root** is located, and what the port desired port is. - ```@Requisite``` makes transforms the class into an **injectable** and lets the framework find it. More on injectables and this decorator later. - ```@Pathway``` marks the method as a handler for the given path. The method is called when the endpoint is reached. More on this later. ## Documentation Section in which I explain how the framework functions. ### Project Structure For the framework to work correctly it must have it's directory structure as follows: - index.ts -- doesn't matter where it is. Preferably in ```/src``` - resources -- ( directory ) it must be one level above *index.ts* file. So if your main file is ```/src/index.ts``` then the resources directory must be ```/resources/```. - public -- ( directory ) it must be inside the resources directory. ```/resources/public``` In the **resources** directory can be stored any kind of project files you need and access them freely. Inside it is the **public** directory where all the files are visible to the http server. Let's say that you have a file named *index.html* inside and the server open on port *8000*. If you make a request on ```localhost:8000/index.html``` the file will be sent. **Note:** If the file is named ```index.html``` then the file will be available on both ```localhost:8000/index.html``` and ```localhost:8000/``` ### Decorators Documentation details regarding the decorators. #### @Requisite -- and dependency injection This decorator is used to mark the class as an injectable. Yes, Overseer also handles dependency injection in a manner similar to Angular's. In order to inject a requisite it must be a parameter for the constructor. In order to let the framework find the requisites, all files that contain such classes **must** have their name ending in - ```.controller.ts``` - ```.service.ts``` - ```.component.ts``` Example of dependency injection: *my.service.ts* ```typescript import { Requisite } from '@jeaks03/overseer-core'; @Requisite export class MyService { public log(message: string): void { console.log(message); } } ``` *my-other.service.ts* ```typescript import { Requisite } from '@jeaks03/overseer-core'; import MyService from './my.service'; @Requisite export class MyOtherService { constructor(private myService: MyService) {} private onInit(): void { this.myService.log('I got initialized!'); } } ``` #### @Pathway This decorator marks a method as the handler of the given path. It requires an argument of type ```WayDetails``` which has the following attributes: - path -- *string*: the path for the endpoint to map. Default: ```/``` - method -- *string*: http method. Default: ```GET``` - statusCode -- *number*: http status code. Default: ```200``` - produces -- *string[]*: list of content types that can be produced by this handler. Default: ```['application/json']``` - consumes -- *string[]*: list of content types that can be consumed by this handler. Default: ```['application/json', 'multipart/form-data', 'application/x-www-form-urlencoded']``` - guards -- *Guard[]*: list of ```Guard``` implementations. This works just like Angular's guard security. Default: ```[]``` #### @LifecycleEvent This decorator is used on requisites to mark a method as a lifecycle event. These events are triggered at a certain time during their life. It accepts a string as a sort of *event type* to let it know when to trigger the method. These arguments are: - "onInit" -- method is triggered shortly after the instantiation - "afterInit" -- method is triggered after all requisites have been instantiated #### @OnInit Shorthand version of ```@LifecycleEvent('onInit')``` #### @AfterInit Shorthand version of ```@LifecycleEvent('afterInit')``` ### Base classes 101 #### RequisiteManager This class handles and contains all the requisites. An instance of this class can be imported under the name of ```Requisites``` as a ```RestrictedRequisiteManager``` interface. RestrictedRequisiteManager: ```typescript interface RestrictedRequisiteManager { addInstance: (instance, isController?: boolean) => void; find: <T>(clazz: Class<T>) => T; findByName: <T>(className: string) => T; findAll: <T>(clazz: Class<T>) => T[]; } ``` #### Authentication In order to secure your application, you must provide an implementation of this class as a requisite. The default authentication implementation provided is ```NoAuthentication``` which basically behaves as if there is no security. In order to create an instance for any ```Authentication``` implementation you have to pass a ```UserProvider``` to the constructor. `UserProvider` interface is a function that looks like this: `(username: string) => UserDetails | Promise<UserDetails>` Overseer ships with the following implementations: - NoAuthentication - BasicAuthentication - JWTAuthentication Here is an example of how to secure your application using basic auth: ```ts export class SecurityComponent { constructor(private database: DatabasePlaceHolder) { } @OnInit() secureApp() { const auth = new BasicAuthentication((username: string) => this.database.findUser(username)); Requisites.addInstance(auth); } } ``` #### Converter This class can be extended to create converters that understand other content types, and it looks like this: ```ts export class Converter { public getContentType(): string; public canRead(target: string, contentType: string): boolean; public canWrite(target: any, contentType: string): boolean; public doWrite(target: any): string; public doRead(target: string): any; } ``` ### This documentation is a work in progress. More will be added later. ## License [MIT License](https://github.com/paulcosma97/overseer/blob/master/LICENSE)