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

decorators-express

v1.1.15

Published

Usual decorator for express

Downloads

401

Readme

Express decorator

a module to build TypeScript application with Express decorators

Install

npm i -S decorators-express

How to use

Import AppRouter instance in your file app.ts

import express from 'express';
import { AppRouter } from 'decorators-express';
import './controllers/UserController';

const app = express();

const PORT = process.env.PORT || 3000;

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.use(AppRouter.getInstance());

app.listen(PORT, ()=>{
console.log(`server is listening on ${PORT} port`);
})

Declare a class and mark it with @Controller('your path')

import {NextFunction, Request, Response} from 'express';
import {Controller, Get, Res, Param, Post, Req, Patch, Delete, Guard, Use} from 'decorators-express';


@Controller('/user')
export class UserController {
    @Get('/')
    get(@Res() res: Response) {
        res.status(200).json([
            {name: 'john'},
            {name: 'walter'},
        ]);
    }

    @Post('new')
    @Guard(AuthGuard)
    @Use(ValidationMiddleware)
    createOne(@Res() res: Response) {
        res.status(201).json({name: 'john'});
    }

    @Patch(':name')
    updateOne(@Res() res: Response, @Param('name') name: string) {
        const users = [
            {name: 'john'},
            {name: 'walter'},
        ]

        const user = users.find(u => u.name === name)
        res.status(200).json(user);
    }

    @Delete(':name')
    deleteOne(@Res() res: Response, @Param('name') name: string) {
        const users = [
            {name: 'john'},
            {name: 'walter'},
        ]

        const user = users.find(u => u.name === name)
        const usersUpdated = users.filter(u => u.name !== name)
        res.status(200).json(user);
    }
}


function AuthGuard(req: Request, res: Response) {
    // some logic, like if is auth ....
    return true;
}


function ValidationMiddleware(req: Request, res: Response, next: NextFunction) {
    // some logic, like body validation ....
    next()
}

Don't forget to import all your class in your root file app.ts

import './controllers/UserController';

Use @Controller to register express route for class.

Use @Get/@Delete/@Post/@Put/@Patch/@Head/@Options to register sub-route path on a method like:

@Get('all')
getUser(){
}

All parameters that are injected as parameters on each method can be injected in any order of your choice

Inject request parameters with @Param/@Query/@Body For @Param/@Query you need to indicate the name or the propriety that you need like:

getUser(@Param('id') id: string){
    res.status(200)
}

For Body this you indicate an array of proprieties that you need like:

getUser(@Body(['name', 'phone']) body: {[key:string]: any} ){
    res.status(200)
}

This array of proprieties are optional, so if you need all the body you can do:

getUser(@Body() body: {[key:string]: any} ){
    res.status(200)
}

Inject Response From express with @Res

getUser(@Res res: Response){
    res.status(200)
}

Inject Request From express with @Req

getUser(@Req req: Request){
    const headers = req['headers']
}

Inject Next From express with @Next


getUser(@Next next: NextFunction){
    next()
}

Middleware

To Inject middleware you need to use the @Use decorator and pass as argument a function that math to the type RequestHandler like:

@Controller('/user')
export class UserController {

    @Post('new')
    @Use(ValidationMiddleware)
    createOne(@Res() res: Response) {
        res.status(201).json({name: 'john'});
    }
}

function ValidationMiddleware(req: Request, res: Response, next: NextFunction) {
    // some logic, like body validation ....
    next()
}

A middleware can be used on the entire controller like:

@Controller('/user')
@Use(ValidationMiddleware)
export class UserController {

    @Post('new')
    createOne(@Res() res: Response) {
        res.status(201).json({name: 'john'});
    }
}

function ValidationMiddleware(req: Request, res: Response, next: NextFunction) {
    // some logic, like body validation ....
    next()
}

So in this case the middleware will be executed on each method of the controller the order of the execution will be global middleware before and unit middleware after. You can also set multiple middlewares on the controller or per method like:

@Controller('/user')
export class UserController {

    @Post('new')
    @Use(Middleware1)
    @Use(Middleware2)
    @Use(Middleware3)
    createOne(@Res() res: Response) {
        res.status(201).json({name: 'john'});
    }
}

@Controller('/post')
@Use(Middleware1)
@Use(Middleware2)
@Use(Middleware3)
export class PostController {

    @Post('new')
    createOne(@Res() res: Response) {
        res.status(201).json({name: 'Sunday post'});
    }
}

The order of execution when you set multiple middleware is from the top.

Guard

To Inject guard you need to use the @Guard decorator and pass as argument a function that math to the type (req: Request, res: Response)=> boolean like:

@Controller('/user')
export class UserController {

    @Post('new')
    @Guard(AuthGuard)
    createOne(@Res() res: Response) {
        res.status(201).json({name: 'john'});
    }
}

function AuthGuard(req: Request, res: Response) {
    // some logic, like if is auth ....
    return true;
}

If guard function return false it will send status 403

You can also use @Guard on the controller itself like:

@Controller('/user')
@Guard(AuthGuard)
export class UserController {

    @Post('new')
    createOne(@Res() res: Response) {
        res.status(201).json({name: 'john'});
    }
}

So in this case the guard will protect each method of the controller.

Upload files

you can upload one or many files using the decorator @Upload Upload are handle via the package busboy, unlike multer, busboy process to upload via stream, actually busboy is the most efficient package to upload file from a client. After upload we save all files uploaded in the disk via "fs.createWriteStream", it's also the most efficient way to write data on the disk.

    @Post('/')
    @Upload({  name: 'file', directory: `${path.join(__dirname, '..', 'upload')}` })
    get(@Res() res: Response) {
        res.status(200).json([
            {name: 'john'},
            {name: 'walter'},
        ]);
    }

@Upload receive two arguments. The first one is "name", it must match to the propriety where you assign the file(s) on the formData that you sent from the client. If from the client you set formData.append("file", "your file") so you need to set { "name": "file"} in the @Upload. If from the client you set formData.append("props", "your file") so you need to set { "name": "props"} in the @Upload. The second one is "directory", it must match to the path of the directory where you want to save your file(s), like {directory: ${path.join(__dirname, '..', 'upload')}}

@Upload support many files