Giter Club home page Giter Club logo

node-decorators's People

Contributors

battistaar avatar bbuhler avatar fetis avatar freemanlam avatar fum36205 avatar leodinas-hao avatar leonadler avatar marceloaplanalp avatar nassero avatar nathanlepori avatar scopsy avatar serhiisol avatar typicalfence avatar vikaskandari avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-decorators's Issues

Express route middlewares as a class

It will be nice to have a possibility to set route middleware as a class which implements an interface.

export interface MiddlewareInterface {
    use(): void;
}

Route param on controller route

const router: Router = Router();

Would it be better to have a parameter for the option "mergeParams"?

const router: Router = Router({ mergeParams: true }); 

because i found trouble to have a controller like this

@Injectable()
@Controller('/:id/abc')
export default class Abc {}

where req.params.id === undefined on any method

decorators notation

Decorators - function. In JS all function write in lowercase. Why method/parameter/property names decorator is start from capital symbol?
p.s. Class decorators need to start from capital, because class first symbol - capital. Also this notation help other developer to know - what is class decorator and what is method/property/parameter decorator

Example:

@Injectable() // capital, because class decorator
class SomeClass{
@someProperty() public readonly myInjection; // start from lowercase, because this is property

@someMethod() // start from lowercase, because this is method
public method(@someParameter() myParameter: any){}  // start from lowercase, because this is parameter
}

A way to pass parameters to Middlewares ?

Im looking for passing parameters to a middleware.

maybe a code example would be more self explaining

  @Get('/hello', [
    new ValidationMiddleware({
      rules: [], // rules for the current route
    }),
  ])
  hello(
    @Response() res: express.Response,
    @Query('word') word: string,
  ) {
 
}

i there a way to do somthing like that ?
I want to have a way to changes settings on my middleware on every routes.

Not finding @body

I'm not able to find the parameters that I pass inside the Body as json in postman.

image

Auto dependency injection

Nice to have inject dependencies to Controllers by using external decorators.
For example:

@Injectable()
class MyService {

}

@Controller('/')
@Injectable()
class Controller {
  constructor(@Inject() myService: MyService) {}
}

Is it possible to attach an instance of a controller to the express app?

I personally don't really care much about the DI of node-decorators and would like to inject my dependencies manually like so:

@Controller("/hello")
export class HelloController {
    private someThing: any ;

    constructor(dependency: any) {
        this.someThing = dependency;
    }

    @Get("/world")
    async create(@Res() response: Response) {
        return response.send(this.someThing.foo());
    }
}

attachControllers(app, [ new HelloController({ foo: () => ({yay: 42 })) ]);

If you really don't want to support such a thing, then some guidance on how I can achieve this using the DI package would be appreciated.

Mongoose pre-save

Thanks for this project, solves my main issue with the mongoose/typescript combination.

Just wondering how I can add a pre-save hook, I can't get it to work like this and I'm not sure how else to do it:

export type UserType = UserClass & mongoose.Document
export type UserModel = mongoose.Model<UserType>

export const User = model<UserType>({ provide: UserClass })
export const UserSchema = schema({ provide: UserClass })

UserSchema.pre('save', async function (next) {

})

DI doesn't work incorrectly

Mongoose provides different context to the model, so regular DI doesn't work properly. Need to find a way to provide deps properly

Is the project dead?

Hi! First of all, thanks for the work, simply amazing! I've using it on my personal projects and I am think to use it on company's projects too. But I am afraid that there is no recent updates, so I really would like to know if you guys pretend to continue this project. If you do, I'll be more than happy to contribute 😄

Decorators in multiple files

Hi, i was trying to create a server with express and the node-decorators module starting from your example, i noticed that if a second http endpoint is created in another file it is not found and i get the 404 error.
I hope I managed to explain myself well.

This is my index.ts and entrypoint file:


import express, { Express, Request } from 'express';
import { Response, Params, Controller, Get, attachControllers } from '@decorators/express';
import { Injectable } from '@decorators/di';

@Controller('/')
@Injectable()
class UsersController {

  // constructor(userService: UserService) {}

  @Get('/users/:id')
  getData(@Response() res:any, @Params('id') id: string) {
    // res.send(this.userService.findById(id));
    console.log(typeof(res));
    res.send("Ciao");
  }
}

let app: Express = express();

attachControllers(app, [UsersController]);

app.listen(3000);

This is my second file where there is another endpoint:

import express, { Express, Request } from 'express';
import { Response, Params, Controller, Get, attachControllers } from '@decorators/express';
import { Injectable } from '@decorators/di';

@Controller('/')
@Injectable()
class UsersController {

  // constructor(userService: UserService) {}

  @Get('/hello/')
  getData(@Response() res:any) {
    // res.send(this.userService.findById(id));
    console.log(typeof(res));
    res.send("hello");
  }
}

Controller is not assignable to parameter of type 'SocketClass'

Hello,

I use your library in my project and everything works but I receive type errors.

controller class:

import { Inject, Injectable } from '@decorators/di';
import { Ack, Args, Controller, Event } from '@decorators/socket/src';

import { logger } from '../../../logger';
import { StateService } from '../../../state/service';

@Injectable()
@Controller('/')
export class DoorController {
  constructor(@Inject(StateService) private stateService: StateService) { }

  @Event('api/door')
  getDoor(@Args() message, @Ack() callback) {
    logger.debug(`api/door: ${message.groupAddress}`);
    callback(this.stateService.getDoorOpener(message.groupAddress));
  }
}

Error:

src\api\door\controller\index.ts(12,4): error TS2345: Argument of type 'DoorController' is not assignable to parameter of type 'SocketClass'.
  Property '__socket_meta__' is missing in type 'DoorController'.

In my index.ts I attach all controllers.

Any ideas how to fix this issue?

BR Jakob

Async controller handles swallow errors

Seems like if I create async controller function any thrown error will result in a swallowed exception and won't be caught by the global error middleware unless I explicitly wrap it in try/catch block.

@Controller('/users', [ AuthMiddleware ])
export class UserController {
    @Get('/:id')
    async getUser(@Request() req: Request @Response() res: IAppResponse) {
        throw new Error('Error occurred');

        res.send('Hello World');
    }
}

Possible solution would be in express.ts file under routeHandler function

    const handler = controller[methodName].apply(controller, args);

      if (handler instanceof Promise || handler instanceof global.Promise) {
        handler.catch(e => {
          next(e);
        });
      } else {
        return handler;
      }

We test for instance of promise and then catch possible errors and pass them to the global error middleware.

global.Promise used to support user custom promise libraries.

What do you think ?

Decorators + InversifyJS

Hello, I'm trying to use your express decorators with inversifyjs.

The problem that i face off is in attachControllers method.

So, I have the service class with registered in intersifyjs container, plus I have controller which looks like this

import { Controller, Get } from '@decorators/express';
import { Container } from 'inversify';
...
import { GoogleCloudDataStorageService } from '../services/GoogleCloudDataStorageService';
import { TYPES } from '../types';

declare var app: any;

@Controller('/car')
export class CarController {
    @Get('/:id')
    public async getCarAction(req: RequestInterface, res: ResponseInterface) {
        const googleCloudDataStoreService = (app.get('container') as Container).get<GoogleCloudDataStorageService>(TYPES.GoogleCloudDataStorageService);

        const result = await googleCloudDataStoreService.sayHello();

        return res.status(HttpStatus.OK).json({
            message: result,
        });
    }
}

In my app.ts file I'm registering controller like this

...dependecies
import { attachControllers } from '@decorators/express';
import { CarController } from './controllers/CarController';

...

const apiRouter = express.Router();
attachControllers(app, [CarController]);

Then I get the error from inversify container

Missing required @injectable annotation in: GoogleCloudDataStorageService.

However if I write example route like this

app.use('/api/v2', async (req, res) => {
    try {
        const googleCloudDataStoreService = container.get<GoogleCloudDataStorageService>(TYPES.GoogleCloudDataStorageService);
        const result = await googleCloudDataStoreService.sayHello();

        return res.json({ a: result });
    } catch (error) {
        console.error(error);
    }
});

And remove attaching controllers function - this route will works normal.

Solution

After few hours of monkey clicking i found that your @decorators/express somehow rewrites the reflect-metadata which I'm using for inversifyjs and clears the metadata for my classes.

So the solution is to replace importing reflect-metadata, on the beginning of the project, with your @decorators/express.
Maybe you could add some checking for it? Or maybe there's better solution to do it?

Thank you.

Wrong RecursiveProviderError

Hi, the DI module throws RecursiveProviderError when there is no recursion.
For example in the following dep tree, trying to resolve ModA it says: DI recursive dependency: ModA => ModB => ModD => Config => ModC => Config.
di

The problem is at line 26 of container.ts, you push every provider in the same array. Creating a new array each step (simulating a tree structure) should solve the problem.

The following code works for me.

 private static resolveProvider(provider: StoreProvider, requesters: StoreProvider[] = []): any {
    if (provider.value) {
      return provider.value;
    }

    const _requesters = requesters.concat([provider]);

    const deps = provider
      .deps.map((dep: Dependency) => {
        const requesterProvider: StoreProvider =
          _requesters.find((requester: StoreProvider) => requester.id === dep.id);

        if (requesterProvider) {
          throw new RecursiveProviderError(_requesters, requesterProvider);
        }

        const depService: StoreProvider = Store.findProvider(dep.id);

        if (!depService && !dep.optional) {
          throw new MissingProviderError(provider, dep);
        }

        if (!depService && dep.optional) {
          return null;
        }

        return this.resolveProvider(depService, _requesters);
      });

    provider.value = provider.factory ?
      provider.factory(...deps) : new provider.type(...deps);

    return provider.value;
  }

If you prefer i can submit a PR.

I was waiting for a good node DI for years, great work!

@decorators/socket with @decorators/express

I am bit confused , how do i implement socket io decorators with express decorators i have the following code can you please provide some examples to implement socket and express decorators

import { LandingController } from "@controllers/LandingController";
import { MessageController } from "@controllers/MessageController";

import { attachControllers as ExpressAttachControllers } from "@decorators/express";
import { attachControllers as SocketAttachControllers } from "@decorators/socket";

import express from "express";
import { Server } from "socket.io";

const ExpressApp = express();
const ExpressControllers = [LandingController];
const SocketControllers = [MessageController];
ExpressAttachControllers(ExpressApp, ExpressControllers);


const server = ExpressApp.listen(3000);



const io = new Server(server);


SocketAttachControllers(io, SocketControllers);

It throws following error

MissingProviderError:
        In order to get DI working, you have to provide Injectable.
        DI attempt for MessageController.

[Suggestion] allow attaching controllers to a router

What do you think about adding the ability to attach controllers not only to the app but to Express Router as well?

This is useful when you want to create a namespace for your controllers, ie:

/v1/api

we can allow passing a router instance or app instance to the current attachControllers method. Since both use the .use method to attach endpoints.
This works just fine so maybe just:

const apiRouter = express.Router();
app.use('/v1/api', apiRouter);

attachControllers(apiRouter as any, [
    ...APP_CONTROLLERS
]);

[Suggestion] adding swagger decorators

Recently found about swagger decorators made by nestjs framework.
https://docs.nestjs.com/recipes/swagger

IMO it provides a very clean API for annotating SwaggerAPI.

I think the main issue is the discovery of all the controller endpoints, and then attaching all the relevant metadata to construct the swagger definitions.

What do you think? Took a quick look at nestjs implementation, and I think the implementation here will be pretty similar.

Question, __meta__ is missing error? what?

[ts]
Argument of type '(typeof TodosController)[]' is not assignable to parameter of type '(Injectable | ExpressClass)[]'.
Type 'typeof TodosController' is not assignable to type 'Injectable | ExpressClass'.
Type 'typeof TodosController' is not assignable to type 'ExpressClass'.
Property 'meta' is missing in type 'typeof TodosController'.

just followed docs

@decorators/mongoose - @Model doesn't work with options

Firstly, Thanks for sharing this brilliant idea & your efforts putting this together.

After spent whole afternoon today, I could't get options provided in @Model work in the generated mongoose schema. It seems to me that @Model decorator doesn't work properly at the moment when setting SchemaTypeOpts. What I assume is because the following reasons:

  1. SchemaTypeOpts has not been properly parsed into meta.options. Please look into the following line from decorators/model.ts
mongooseMeta.options.push(key, options[key]);
# suggest to replace with following
mongooseMeta.options.push([key, options[key]]);
  1. Incorrect value/option being used in buildSchema function for setting schema options. Refer to the following in mongoose.ts
meta.options.forEach((option: string) => {
  schema.set(option, classInstance[option]);
});
# suggest to replace with following
meta.options.forEach(([name, opt]: [string, any]) => {
  schema.set(name, opt);
});

Thanks for your anticipated help on this.

[express] Injectable Service not found

Hi, sorry for my noob question, but I'm trying to add DI follow the example in the DOC, but my userService is not found, this is the example code:

import {
  Response, Params, Controller, Get,
  attachControllers, Middleware,
} from '@decorators/express';
import { Injectable } from '@decorators/di';

@Injectable()
@Controller('/')
class UsersController {

  constructor(userService: UserService) {}

  @Get('/users/:id')
  getData(@Response() res: any, @Params('id') id: string) {
    res.send(userService.findById(id));  // **PROBLEM: userService not FOUND!!!**
  }
}

@Injectable()
class UserService{
  findById(id: string) {

  }
}

I can't find the right solution.

Create Injectable from object not class

It is possible to create injectable object without decorating a class ? I want to inject RestClient that is installed using NPM.
I want to do something like this

Container.register(RestClient, new RestClient("http://example.com"))
and then

@Injectable() export class SomeDao(){ constructor(private restClient: RestClient){} }

[Question] How to register response handler?

I'm able to register an error handler as follows. It works fine.

@Injectable()
class ErrorHandler implements ErrorMiddleware {
    public use(error: Error, request: Request, response: Response, next: NextFunction) {
        console.log('ErrorHandler.use()');
        response.status(500).send(error.message);
    }
}

Similarly, is there any provision for injection of response handler to process a response?

It should get invoked with the handler registered using @Next in a controller method. All the routes should return through a common response handler.

Thanks in anticipation!

Socket and Ack are swapping

Hello
I've got a problem with swapping between @Socket() and @Ack in socket decorators.
Socket is sometimes Ack and Ack becomes socket. Having function like this:

    @Event(MESSAGE)  
    async onMessage(@Args() msg, @Socket() socket, @Ack() ack) {  
        console.log('type of socket: ', typeof socket);    
        console.log('type of ack: ', typeof ack);    
    } 

Sending message, I'm getting an output

type of socket:  object 
type of ack:  function 
type of socket:  function 
type of ack:  object 
type of socket:  object 
type of ack:  function 
type of socket:  function  
type of ack:  object 

Fix mongoose README example

Hello,

in readme of mongoose, you see here :

export let TestModel = model(TestModelClass);

I think it's mistake. This should be :

export let AnimalModel = Animal.model(Animal);

and you not specify how import AbstractModel form node-decorators/playground/mongoose/abstract.model.ts:

import AbstractModel from ???? 

Regards,

Passing injectable from dependency to dependent package

I have two packages, "core" and "api". Core is api's dependency.

Core exposes an injection token that is meant to be used by the api.

Now, the issue is that since both packages depend on "@decorators/di", npm creates two separate instances of the package - one in node_modules insode api, the other one inside core. Therefore, api's DI container is unable to make use of core's injectables.

Is there a way to make the two "talk" to each other, even a hacky one?

Rename Request, Response Decorators to Req and Res

Hello,

this is not a issue but a feature request , i am using express decorators in my project but one thing is really a big frustrating for me is i cannot typecast Request decorator variable as express Request type ,i also don't want it to set Any as well, so to solve this problem i have to do code something like below

import { Body, Controller, Post, Request as Req, Response as Res } from "@decorators/express";
import { Request, Response } from "express";

  @Post("/detail")
    async detail(@Req() req: Request, @Res() res: Response) {
      res.send("works");
    }

as you can see i have to put little extra time for the imports to rename Request to Req and Response to Res, i really do not like to use ANY if there is a type available for param. also in NEST.js framework they have named Request to Req and Response to Res.

Unable to resolve signature of method decorator for @Get

When implementing the provided code example for the Express decorators:

@Controller('/')
class UsersController {
  @Get('/users/:id')  // <<< ERROR HERE
  getData(@Response() res, @Params('id') id: string) {

  }
}

I get the following error in my IDE:

[ts]
Unable to resolve signature of method decorator when called as an expression.
  Supplied parameters do not match any signature of call target.

Issue may apply to other Route directives as well.

TypeScript version: ^2.1.6
@decorators/express: 1.2.0

In order to get DI working, you have to provide Injectable.

default

This is my code,but the dependency injection is failed.

Error info

MissingProviderError: 
        In order to get DI working, you have to provide Injectable.
        DI attempt for UserService and dependency [object Object].
      
    at provider.deps.map (/Users/lavyun/Code/毕业设计项目/server/node_modules/_@[email protected]@@decorators/di/src/container.ts:81:17)
    at Array.map (<anonymous>)
    at Function.resolveProvider (/Users/lavyun/Code/毕业设计项目/server/node_modules/_@[email protected]@@decorators/di/src/containe0:13)
    at provider.deps.map (/Users/lavyun/Code/毕业设计项目/server/node_modules/_@[email protected]@@decorators/di/src/container.ts:88:21)
    at Array.map (<anonymous>)
    at Function.resolveProvider (/Users/lavyun/Code/毕业设计项目/server/node_modules/_@[email protected]@@decorators/di/src/containe0:13)
    at Function.get (/Users/lavyun/Code/毕业设计项目/server/node_modules/_@[email protected]@@decorators/di/src/container.ts:51:17)
    at registerController (/Users/lavyun/Code/毕业设计项目/server/node_modules/_@[email protected]@@decorators/express/src/exprts:32:46)
    at controllers.forEach (/Users/lavyun/Code/毕业设计项目/server/node_modules/_@[email protected]@@decorators/express/src/exps:19:45)
    at Array.forEach (<anonymous>)

socket: Global Middleware is not a constructor

Hello
When I'm using your quick example from socket decorators I'm getting an error:

/node_modules/@decorators/socket/src/middleware.js:23
            instance = new middleware();
                       ^

TypeError: middleware is not a constructor

How to deal with it ?
What is more, when there is no @Injectable() above controller, I'm getting:


/node_modules/@decorators/di/src/container.js:33
            throw new errors_1.MissingProviderError(injectable);
            ^

MissingProviderError: 
        In order to get DI working, you have to provide Injectable.
        DI attempt for MessageController.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.