npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fastro

v0.3.11

Published

Dependency injection ready. Powered by fastify.

Downloads

5

Readme

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:

  • @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 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:

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