0.3.11 • Published 4 years ago

fastro v0.3.11

Weekly downloads
2
License
MIT
Repository
github
Last release
4 years ago

build js-standard-style

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:

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 define id, createdAt, and updatedAt 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:

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.
0.3.11

4 years ago

0.3.10

4 years ago

0.3.9

4 years ago

0.3.8

4 years ago

0.3.7

4 years ago

0.3.6

4 years ago

0.3.5

4 years ago

0.3.4

4 years ago

0.3.3

4 years ago

0.3.2

4 years ago

0.3.0

4 years ago

0.2.3

4 years ago

0.2.2

4 years ago

0.2.5

4 years ago

0.2.4

4 years ago

0.2.1

4 years ago

0.2.0

4 years ago

0.1.7

4 years ago

0.1.6

4 years ago

0.1.2

4 years ago

0.1.1

4 years ago

0.1.0

4 years ago