mkdir first_micro_project
cd first_micro_project
npm init -y
npm i --save @micro.ts/[email protected]
npm i --save @hapi/hapi
npm i --save-dev typescript
npm i --save-dev @types/node
# Create folders
mkdir config
mkdir src
mkdir src/controllers
mkdir src/services
# Create initial files
touch tsconfig.json
touch src/main.ts
touch src/Startup.ts
You should end up with this folder structure
.
├── config
├── package.json
├── package-lock.json
├── src
│ ├── controllers
│ ├── main.ts
│ ├── services
│ └── Startup.ts
└── tsconfig.json
{
"compilerOptions": {
"alwaysStrict": true,
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"module": "CommonJS",
"noImplicitAny": true,
"outDir": "./build",
"removeComments": false,
"rootDir": "./src",
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"strictPropertyInitialization": true,
"target": "ES2018"
}
}
import { Container, AppBuilder, BaseConfiguration } from '@micro.ts/core';
import { Startup } from './Startup';
async function main(): Promise<void> {
const appBuilder: AppBuilder = new AppBuilder(
Container.get<BaseConfiguration>(BaseConfiguration)
).useStartup(Startup);
await appBuilder.start();
}
main().catch((error) => {
process.exit(1);
});
import { OptionsBuilder, StartupBase } from '@micro.ts/core';
import '@micro.ts/core/brokers/http/hapi';
export class Startup extends StartupBase {
/*
* Use this methods for inializiations before the brokers are initialized
*/
public async beforeStart(): Promise<void> {
console.log('Before start called');
}
/*
* This method gets called after the brokers are initialized
*/
public async afterStart(): Promise<void> {
console.log('After start called!');
}
/*
* Application setup builder
**/
public configureServer(builder: OptionsBuilder): void {
builder.setBasePath('api'); // all routes are prefixed with /api
builder.setLogRequests(true); // log all requests
builder.useHapiBroker((b) => b.withConfig({ port: 8080 })); // Serve endpoints on port 8080 using Hapi
}
}
import { Get, JsonController } from '@micro.ts/core';
@JsonController('first') // Controller path
export class HelloController {
@Get('') // Request verb (Get, Post, Put, Patch, Delete)
public getHello(): string { // Handler
return 'Hello, World!';
}
}
//--- imports
import { HelloController } from './controllers/FirstController';
//---
//---
// Add this line at the end of configureServer() method
builder.addControllers(HelloController);
//---
tsc && node build/main.js
Injects all request headers as an object
@Get('')
public get(@Headers() headers: Record<string, string | string[]>): void {
console.log(headers);
}
Injects a single header
@Get('')
public get(
@Header('Authorization', { required: true }) token: string
): void {
console.log(token);
}
Injects request body from post/put/patch requests
@Post('')
public get(
@Body() body: Record<string, string>
): void {
console.log(body);
}
Injects a single key from request body from post/put/patch requests
@Post('')
public get(
@BodyParam(id) id: string
): void {
console.log(id);
}
Injects the querystring parsed as an object
@Get('')
public get(
@Query() query: {id: string, search: string}
): void {
console.log(query);
}
Injects a single query parameter
@Get('')
public get(
@QueryParam(id) id: string
): void {
console.log(id);
}
Injects a route parameter
@Get(':id/:name')
public get(
@Param('id') id: string,
@Param('name') name: string,
): void {
console.log(id, name);
}
Injects all route parameters as an object
@Get(':id/:name')
public get(
@Params() params: {id: string, name: string},
): void {
console.log(params);
}
Injects request verb
@Get('')
public get(
@Method() method: string
): void {
console.log(string);
}
Injects the raw broker request object
@Get('')
public get<T>(
@RawRequest() request: T
): void {
console.log(request);
}
Injects the broker handling the request
@Get('')
public get(
@Broker() broker: IBroker
): void {
console.log(broker);
}
Injects the broker connection (in case of http brokers injects the server instance)
@Get('')
public get<T>(
@Connection() connection: T
): void {
console.log(connection);
}
Middlewares modify the Action object which is the request/response container that gets passed around in a request cycle Middlewares are classified into BeforeMiddlewares and AfterMiddlewars They can be places around the handler, around the controller or in application level
@BeforeMiddlewares([(action: Action) => {
action.request.headers['x-test'] = 'test';
return action;
}]);
@Get('')
public getHello(@Header('x-test') test_header: string): void {
console.log(test_header);
}
@AfterMiddlewares([(action: Action) => {
action.reponse.headers['Content-Type'] = 'text/html';
return action;
}]);
@Get('')
public getHello(): void {
return '<div>Hello</div>'
}
@BeforeMiddlewares([(action: Action) => {
action.request.headers['x-test'] = 'test';
return action;
}]);
@JsonController()
export class TestController{
@Get('')
public getHello(@Header('x-test') test_header: string): void {
console.log(test_header);
}
}
@AfterMiddlewares([(action: Action) => {
action.reponse.headers['Content-Type'] = 'text/html';
return action;
}]);
@JsonController("test")
export class TestController{
@Get('')
public getHello(): void {
return '<div>Hello</div>'
}
}
// src/Startup.ts
public configureServer(builder: OptionsBuilder): void {
builder.setBasePath('api'); // all routes are prefixed with /api
builder.setLogRequests(true); // log all requests
builder.addBeforeMiddlewares((action: Action) => {
action.request.headers['x-test'] = 'test';
return action;
});
builder.addAfterMiddlewares((action: Action) => {
action.reponse.headers['Content-Type'] = 'text/html';
return action;
});
builder.useHapiBroker((b) => b.withConfig({ port: 8080 })); // Serve endpoints on port 8080 using Hapi
}
Middlewares can be a function or a class constructor implementing the IMiddleware interface
type AppMiddleware = Class<IMiddleware> | MiddlewareFunction;
interface IMiddleware {
do(action: Action, def?: BaseRouteDefinition, controller?: any, broker?: IBroker, send?: (data: any) => Action): Action | Promise<Action>;
}
type MiddlewareFunction = (action: Action, def?: BaseRouteDefinition, controller?: any, broker?: IBroker, send?: (data: any) => Action) => Action | Promise<Action>;
type Class<T = any> = {
new (...args: any[]): T;
};