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

bonfire-rest

v0.2.2

Published

![header](https://user-images.githubusercontent.com/48491140/202872887-a486ff15-48d7-4b8b-951d-e07a58a3de0e.png)

Downloads

4

Readme

header

bonfire-rest

A REST framework for building backend applications in Node. It is lightweight, easy to learn.

Built on express and type-chef-di

Installation

tsconfig.json

{
  "emitDecoratorMetadata": true,
  "experimentalDecorators": true
}

table of contents

Table of contents generated with markdown-toc

npm install bonfire-rest

Example of usage

  1. controller class
import { Controller, Param, Body, Get, Post, Put, Delete } from 'bonfire-rest';

@Controller()
export class UserController {
  @Get('/users')
  getAll() {
    return 'This action returns all users';
  }

  @Get('/users/:id')
  getOne(@Param('id') id: number) {
    return 'This action returns user #' + id;
  }

  @Post('/users')
  post(@Body() user: any) {
    return 'Saving user...';
  }

  @Put('/users/:id')
  put(@Param('id') id: number, @Body() user: any) {
    return 'Updating a user...';
  }

  @Delete('/users/:id')
  remove(@Param('id') id: number) {
    return 'Removing user...';
  }
}

This class will register routes specified in method decorators.

  1. Create a file app.ts
import { ServerBuilder } from "bonfire-rest";

async function main() {
  const port = Env.asNumber("PORT", 3000); // "Env" converts environment variables to differetnt types (envName, defaultValue)


  const app = express()
  const server = await ServerBuilder.build({ // setup and retun an express server
    controllers: [UserController],
    globalPipes: [ValidationPipe], // ValidationPipe will validate the request Body
    server: app, // optional, if no server provided it will create one
    globalMiddlewares: [LogMiddleware], // use thies middlewares before all actions
    openapi: { // openapi documentation, swagger ui
      spec: {info: {title: "test project", version: "1", description: "this is the test project decription"}, openapi: "3.0.0"}, // additional general informations
      swaggerUi: "/", // specify swagger ui route
      apiDocs: "docs" // specify openapi raw json route
    },
    assetFolders: [{root: "/assets", path: path.join(__dirname, "static")}] // static serve folders
  });

  server.listen(port, () => {
    console.log(`⚡️[server]: Server is running at http://localhost:${port}`);
  });
}

main();

Prefix routes:

  • Prefix all controllers routes: If you want to prefix all your routes, e.g. /api you can use globalPrefix: "api" option

  • Prefix controller with base route: You can prefix all specific controller's actions with base route:

@Controller("/users")
export class UserController {
  // ...
}

Inject endpoint parameters

Inject route parameters

You can use @Param("...") decorator to inject parameters in your controller actions:

@Get("/users/:id")
getOne(@Param("id") id: string) { 
}

If you want to inject all parameters use @Params().

Inject query parameters

To inject all query parameters, use @Query() decorator

To inject specific query parameter, use @QueryParam("...") decorator:

@Get("/users")
getUsers(@QueryParam("limit") limit: number, @Query() allQueryParam: any) {
}

Inject request body

To inject request body, use @Body decorator:

@Post("/users")
saveUser(@Body() user: User) {
}

To inject request body param, use @BodyParam("...") decorator

@Post("/users")
saveUser(@Body() user: User, @BodyParam("name") name: string) {
}

Inject request header parameters

To inject request header parameter, use @Header("...") decorator. To inject all request header parameter, use @Headers() decorator.

@Post("/users")
saveUser(@Header("authorization") token: string) {
}
@Post("/users")
saveUser(@Headers() allHeader: any) {
}

Inject request

@Post("/users")
saveUser(@Req() req: Request) {
}

Inject response

@Post("/users")
saveUser(@Res() res: Response) {
}

Pipes

Pipes can modify the value e.g. @Param, @Header, @Query.. You can chain them.

export class UpperCasePipe implements IPipe<string> {
  pipe(value: string): any {
    return value?.toUpperCase();
  }
}

@Controller( "ddd")
export class UserController {
    constructor(private readonly foo: FooService) {}

    @Get('/test')
    async getUsers(
      @Req() req: Request,
      @Res() res: Response,
      @QueryParam('name', [UpperCasePipe]) query: any,
    ) {
       return query // if query name got John_Wick the pipe will transformed to JOHN_WICK
    }
    ...

Middlewares

you can specify action middlewares with @BeforeMiddleware and @AfterMiddleware

  • @BeforeMiddleware runs before action
  • @AfterMiddleware runs after action
@Injectable()
export class LogMiddleware1 implements IMiddleware {
  constructor(private readonly stringFactory: StringFactory) { // you can use the DI
  }
  handle(req: express.Request, res: express.Response, next: Function) {
    console.log(`${LogMiddleware2.name} : before middleware`)
    next()
  }
}


@Injectable()
export class LogMiddleware2 implements IMiddleware {
  constructor(private readonly stringFactory: StringFactory) { // you can use the DI
  }
  handle(req: express.Request, res: express.Response, next: Function) {
    console.log(`${LogMiddleware3.name} : after middleware`)
    next()
  }
}

// ...
    @BeforeMiddleware(LogMiddleware1)
    @AfterMiddleware(LogMiddleware2, LogMiddleware2) // use as many you want, can be new instance
    @Get('/users')
    getTest(){
        return {user: "test"}
    }

Validation

for the request validation you can use class-validator

import {IsEmail, IsString} from "bonfire-rest";
import {IUser} from "../interfaces/user.interface";

export class UserCreateDto implements IUser {
  @IsString()
  username: string

  @IsString()
  password: string

  @IsEmail()
  email: string;

  @IsString()
  password2:string
}


@Controller("users")
export class UsersController {
  constructor(private readonly userService: UserService) {
  }

  @Get()
  get(){
    return UserModel.find({})
  }

  @Post()
  create(@Body() user: UserCreateDto) {
    if (user.password !== user.password2){
      throw new Error("Password is not the same.")
    }
    return this.userService.create(user);
  }


}

If the request body does not match with the class validation class it will throw back an error with the problematic fields

OpenAPI

Openapi doc and swagger is built in

    const server = await ServerBuilder.build({
        controllers: [UsersController],
        openapi: {
            swaggerUi: "api-docs", // swager ui route
            apiDocs: "docs", // raw json doc route
            spec: {info: {title: "test project", version: "1", description: "this is the test project decription"}, openapi: "3.0.0"}, // additional general informations
        }
    });

it will automatically add the routes, return types, request body etc. based on class validator classes.

  @Post()
  create(@Body() user: UserCreateDto): UserCreteResultDto {
  
  }

you can directly specify the result with a class validator claas:


  @ApiDocs({
    resultType: UserDto,
    summary: "custom summary",
    description: "this is my description",
    tags: ["user"]
  }) // and more..
  @Post()
  create(@Body() user: any): any {
  
  }

Environment variables

An easy to use helper for process.env variables

Env.asString(name, defaultValue) // string
Env.asNumber(name, defaultValue) // number
Env.asFloat(name, defaultValue) // number
Env.asArray(name, defaultValue) // string[]
Env.asArrayOfString(name, defaultValue) // string[] 
Env.asArrayOfNumber(name, defaultValue) // number[] 
Env.asArrayOfFloat(name, defaultValue) // number[] 

Error handling

We provide a helper class for creating http errors: HttpError you can throw built in http errors like BadRequestError, UnauthorizedError, ForbiddenError, InternalServerError, NotImplementedError

    @Get('/users')
    getTest() {
        throw new HttpError(404, "my message", {some: "details"})
        throw new NotImplementedError('my message') // provide proper status code, and status code description.
        throw new BadRequestError('my message') // provide proper status code, and status code description.
    }

Or create your own, just extend the HttpError class

DI container

This framework is built on type-chef-di. Visit the repo and learn more about it.