fastro
v0.3.11
Published
Dependency injection ready. Powered by fastify.
Downloads
5
Maintainers
Readme
Fastro Core
Simple, clean, fast & scalable. Dependency injection ready.
Main tech stack: fastify, typeorm & typescript.
Getting Started
You can clone this getting-started codes here: https://github.com/fastrojs/fastro-template.git
Install typescript
npm i typescript @types/node -D
Install fastro
npm i fastro
Very Basic Folder Structure:
.
├── src
│ ├── hello.controller.ts
│ └── main.ts
├── package.json
├── server.config.js
└── tsconfig.json
Create configuration file:
Server configuration:
// file server.config.js
module.exports = {
app: {
host: '0.0.0.0',
port: 3000
},
database: {
name: 'default',
type: 'mysql',
port: 3306,
host: 'localhost',
username: 'root',
password: 'root',
database: 'test',
synchronize: true,
logging: false
}
}
Typescript configuration:
// file tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"target": "es6",
"strict": true,
"noImplicitAny": false,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"jsx": "react",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"strictPropertyInitialization": false
}
}
Create controller and route:
You can make a controller by create *.controller.ts
file and use @Controller
decorator. Then do not forget to inject a route decorator --for example @Get
.
// file hello.controller.ts
import { Controller, Get } from 'fastro'
import { FastifyReply, FastifyRequest } from 'fastify'
import { Http2ServerResponse } from 'http2'
@Controller()
export class HelloController {
@Get()
sayHello (request: FastifyRequest, reply: FastifyReply<Http2ServerResponse>): any {
reply.send('hello')
}
}
You can add prefix and other options on @Controller
decorator. Check this for detail options: https://www.fastify.io/docs/latest/Plugins/#plugin-options
If @Controller
decorator have no options, default value is:
{ prefix: '/' }
Available route decorator:
@Get
@Post
@Delete
@Head
@Patch
@Put
@Options
You can also add options to route decorator. Check this for detail: https://www.fastify.io/docs/latest/Routes/#options
If @Get
route decorator have no options, default value is:
{ url: '/' }
Create server:
// file main.ts
import { createServer, start } from 'fastro'
createServer()
.then(server => {
start(server)
})
You can pass fastify server options on createServer
function.
createServer({ logger: true })
Check this for other options: https://www.fastify.io/docs/latest/Server/
Run server:
Build ts
files
npx tsc
Run compiled script
NODE_ENV=production node dist/main.js
Check package.json
for better way to run the app.
After create controller, route and start server, you can access end point via http://localhost:3000/
Dependency Injection
You can see this basic dependency injection codes here: https://github.com/fastrojs/fastro-template/tree/di
Create Service
// file hello.service.ts
import { Service } from 'fastro'
@Service()
export class HelloService {
public sayHello (): string {
return 'Hello'
}
}
Inject service to controller
// file hello.controller.ts
import { Controller, Get, InjectService, Hook } from 'fastro'
import { FastifyReply, FastifyRequest } from 'fastify'
import { Http2ServerResponse } from 'http2'
import { HelloService } from './hello.service'
@Controller()
export class HelloController {
@InjectService(HelloService)
service: HelloService
@Get()
sayHello (request: FastifyRequest, reply: FastifyReply<Http2ServerResponse>): void {
const hello = this.service.sayHello()
reply.send(hello)
}
}
After create a controller, you can access end point via http://localhost:3000/
Create Entity
// file user.entity.ts
import { Entity, Column, Index } from 'typeorm'
import { BasicEntity } from 'fastro'
@Entity()
export class User extends BasicEntity {
@Column({ unique: true })
email: string
@Column({ unique: true })
username?: string
@Column()
password?: string
}
- Entity is database table abstraction.
BasicEntity
is class that defineid
,createdAt
, andupdatedAt
fields.
Use entity on service
To connect with database entity, all service class must extends BasicService
.
// file hello.service.ts
import { Service, BasicService } from 'fastro'
import { User } from './user.entity'
@Service()
export class HelloService extends BasicService {
public sayHello (): string {
return 'Hello'
}
public async getAllUser (): Promise<User[]> {
try {
return this.repo(User).find({
select: ['username', 'email']
})
} catch (error) {
throw this.err('GET_ALL_USER_ERROR', error)
}
}
}
Now you can use getAllUser
function on controller.
import { Controller, Get, InjectService, Hook } from 'fastro'
import { FastifyReply, FastifyRequest } from 'fastify'
import { Http2ServerResponse } from 'http2'
import { HelloService } from './hello.service'
@Controller()
export class HelloController {
@InjectService(HelloService)
service: HelloService
@Get()
sayHello (request: FastifyRequest, reply: FastifyReply<Http2ServerResponse>): void {
const hello = this.service.sayHello()
reply.send(hello)
}
@Get({ url: '/user' })
async getUser (request: FastifyRequest, reply: FastifyReply<Http2ServerResponse>): Promise<void> {
const user = await this.service.getAllUser()
reply.send(user)
}
}
After add getUser
route, you can access end point via http://localhost:3000/user
Create Controller Hooks
Hooks allow you to listen to specific events in the application or request/response lifecycle. You can add hook just using @Hook
decorator and *.controller.ts
file.
Check this for detail: https://www.fastify.io/docs/latest/Hooks/#requestreply-hooks
// file hello.controller.ts
import { Controller, Get, InjectService, Hook } from 'fastro'
import { FastifyReply, FastifyRequest } from 'fastify'
import { Http2ServerResponse } from 'http2'
import { HelloService } from './hello.service'
@Controller()
export class HelloController {
@InjectService(HelloService)
service: HelloService
@Get()
sayHello (request: FastifyRequest, reply: FastifyReply<Http2ServerResponse>): void {
const hello = this.service.sayHello()
reply.send(hello)
}
@Get({ url: '/user' })
async getUser (request: FastifyRequest, reply: FastifyReply<Http2ServerResponse>): Promise<void> {
const user = await this.service.getAllUser()
reply.send(user)
}
@Hook('onRequest')
async myHook (request: FastifyRequest, reply: FastifyReply<Http2ServerResponse>): Promise<void> {
// This hook will always be executed after the shared `onRequest` hooks
// Check this for detail: https://www.fastify.io/docs/latest/Hooks/#scope
console.log('request', request.headers)
}
}
Create Gateway
You can see this gateway example code here: https://github.com/fastrojs/fastro-template/tree/gateway
The gateway is used to put multiple controllers in one class, so you can access via one prefix and add fastify hook
for all injected controllers.
You can create a gateway using @Gateway
decorator on *.gateway.ts
file.
You can create gateway hook using @GatewayHook
decorator.
// web.gateway.ts
import { Gateway, InjectController, GatewayHook } from 'fastro'
import { HelloController } from './hello.controller'
import { FastifyRequest, FastifyReply } from 'fastify'
@Gateway({ prefix: 'web' })
export class WebGateway {
@InjectController(HelloController)
helloController: HelloController
@GatewayHook('onRequest')
async myHook (request: FastifyRequest): Promise<void> {
// This hook will always be executed
// after the shared `onRequest` hooks
}
}
After gateway creation, you can access url endpoint via:
- http://localhost:3000/web/
- http://localhost:3000/web/user
Please note that if you put a controller on a gateway, you can not access controller initial end point directly. You can access it via gateway prefix only.
You can add prefix and other options on @Gateway
decorator. Check this for detail options: https://www.fastify.io/docs/latest/Plugins/#plugin-options
If @Gateway
decorator have no options, default value is:
{ prefix: '/' }
Create Plugin
You can create new plugin by just copy and modify support.plugin.ts
file. No need fastify-plugin
package again. Server will load and register it automatically.
// support.plugin.ts
import { FastifyInstance } from 'fastify'
export const plugin = function (fastify: FastifyInstance, opts: any, next: Function): void {
fastify.decorate('someSupport', () => 'hugs')
next()
}
Test
You can see basic test example codes here: https://github.com/fastrojs/fastro-template/tree/test
Install jest
& ts-jest
:
npm i jest @types/jest ts-jest -D
Create jest config:
// file jest.config.js
module.exports = {
modulePathIgnorePatterns: ['<rootDir>/dist/'],
globals: {
'ts-jest': {
tsConfig: 'tsconfig.json'
}
},
preset: 'ts-jest',
testEnvironment: 'node',
}
Make folder __test__
and create *.spec.ts
file in it.
// hello.controller.spec.ts
import { FastifyInstance } from 'fastify'
import { createServer } from 'fastro'
let server: FastifyInstance
beforeAll(async () => {
server = await createServer()
})
afterAll(() => {
server.close()
})
describe('simple test', () => {
test('/', async done => {
const result = await server.inject({
url: '/',
method: 'GET'
})
// console.log(result.payload)
expect(result.payload).toContain('hello')
done()
})
})
Run test:
npm test
Check __test__
folder for another test example.
Fastro Fullstack
You can check react fastro fullstack web template here: https://github.com/fastrojs/fastro-web
Acknowledgements
This project is powered by:
License
- Licensed under MIT.