I'm following the NestJS docs for creating an EventEmitter (Doc Link.
When I running my code I'm getting an error :
"[Nest] 129586 - 16/06/2021, 20:43:31 [ExceptionsHandler] this.eventEmitter.emit is not a function"
This is what my code looks like:
import { EventEmitter2 } from "#nestjs/event-emitter";
#EntityRepository(Auth)
export class AuthRepository extends Repository{
constructor(private eventEmitter: EventEmitter2) {
super();
}
private logger = new Logger(AuthRepository.name);
async createUser(authDao: SignUpDto): Promise {
const { password, username, role, email, dateOfBirth, fname, lname } = authDao;
let user = await this.findOne({ username });
if (user) {
throw new ForbiddenException("Username already taken");
}
user = this.create({ password, username, role });
await this.save(user).catch(e => this.logger.error(e));
this.eventEmitter.emit("user.created", {
fname, lname, dateOfBirth, email
});
};
}
I'm not sure what I'm missing here.
Nest will not do any DI on TypeORM Repository classes. This is because these classes have other dependencies necessary to them by TypeORM, such as entity managers, and connections. Injecting the EventEmitter is something that should be done in a regular NestJS Provider, and not a TypeO Repo class
One thing I would mention is that you want the line where you declare your class to look like this:
export class AuthRepository extends Repository<Auth> {
as shown here: https://docs.nestjs.com/techniques/database#custom-repository
The reason that the event emitter is not being injected properly is because Nest is already injecting other things into the constructor of a Repository subclass, so the signature doesn't match.
More importantly, this would be potentially considered a bad design, because the Repository should only be concerned with persistence operations on the entities. You might want to refactor this, and create a Service (Provider), and then inject both the eventEmitter and your repository into it. Then, in that service, you can call the createUser method on the repository instance, and follow it up with emitting the event.
Related
My first goal is to avoid repeating myself. I am creating a Node.js express server. I want to create several class controllers each with their own route, and all with the exact same CRUD functionality: GET a single record, GET all the records, UPDATE a single record, DELETE a record, POST a new record for each data object in my database, but I want to be able to extend these controllers to add additional functionality on top of these.
My second goal is to use dependency injection to use a database service in these controllers.
The problems are the TypeScript compiler gets upset when I inject it in the base class constructor. It now wants me to add it to the subclass constructor,
// THE BASE CLASS
import { inject } from "inversify";
import db from "../db";
export default class Controller {
protected _db: db;
public path: string;
public router = Router();
constructor(path: string, #inject(db) databbase: db) {
this._db = databbase;
this.path = path; // path for my special record
this.initializeRoutes();
}
public initializeRoutes(): void {
this.router.get(this.path + '/:id', this.getRecordById);
}
getRecordById = async (req: Request, res: Response): Promise<boolean> => {
const { rows } = await this._db.query('SELECT * FROM issues WHERE id = $1', [req.params.id]);
res.send(rows.pop());
return Promise.resolve(true);
}
}
// THE SUBCLASS
import { inject } from "inversify";
import db from "../db";
import Controller from "./Controller";
export default class SubController extends Controller {
constructor(path: string, #inject(db) _db: db) { // <-- Do I have to inject it here, as well?
super(path, _db);
}
// I will add additional methods here, unique to my SubController
}
then when I need to use that class, it now wants me to fill in the second argument, the db part of the sub-class constructor.
In the documentation they give an example which implies I don't even need to use the #inject keyword, but that doesn't make sense to me. Ultimately, I have to put something in that constructor, don't I? When I finally go new IssueController('/path', [#inject db something here]), won't I need to put something in where #inject is?
My Questions
Do I need to use #inject in both the base class and the sub-class?
What do I insert when I need to call new?
Ultimately, it seems like I'm doing this wrong. Can you point me in the right direction?
In a controller, I add the user object with a guard, inject some service and call that service to get some response. I have removed a lot of code for brevity.
#Controller()
#UseGuards(AuthGuard())
export class UserController() {
constructor(private readonly userService: UsersService) {
}
#Get(':id')
async findOne(#Param('id') id) {
return await this.userService.findOne(id);
}
}
Since I have the AuthGuard, I now know the user is logged in before entering :id route.
In the service I would do something like
#Injectable()
export class UsersService {
async findOne(id: number): Promise<User> {
return await this.usersRepository.findOne({where: {id: id}});
}
}
But of course we want to have some checks that the logged in user has access to the user it is querying. The question is now how do I get the current logged in user. I can send it as a parameter from the controller, but since a lot of the backend would need security checked on the current user, I'm not sure that is a good idea.
#Get(':id')
async findOne(#Param('id') id, #Req() req: any) {
return await this.userService.findOne(id, req.user);
}
Ideally, which doesn't work, I would be able to get it in the UserService:
async findOne(id: number, #Req req: any): Promise<User> {
if (id === req.user.id || req.user.roles.contains('ADMIN')) {
return await this.userRepository.findOne({where: {id: id}});
}
}
Or perhaps through injection in the UserService constructor
constructor(#Inject(REQUEST_OBJECT) private readonly req: any) {}
So, is there a better way to send the user object through the backend than always sending the request object in each function call?
Update March 2019
Since version v6, you can now inject the request object into a request-scoped provider:
import { REQUEST } from '#nestjs/core';
import { Request } from 'express';
#Injectable({ scope: Scope.REQUEST })
export class UsersService {
constructor(#Inject(REQUEST) private readonly request: Request) {}
}
Outdated answer
It's not possible to inject the user (or request) directly into the service. Nest.js does not yet support request-scoped providers. This might change with version 6. Until then, a service does not know anything about a request.
Logged in user
You can create a custom decorator #User. Using a decorator is preferable over injecting the request object because then a lot of nest's advantages get lost (like interceptors and exception filters).
export const User = createParamDecorator((data, req) => {
return req.user;
});
And then use it like this:
#UseGuards(AuthGuard())
#Get(':id')
async findOne(#Param('id') id, #User() user) {
return await this.userService.findOne(id, user);
}
Roles
You can create a RolesGuard that makes sure the logged in user has the required roles. For details, see this answer.
#Injectable({ scope: Scope.REQUEST }) worked for me, but I had a lot of problems when need inject on anothers services.
Exist a another alternative:
https://github.com/abonifacio/nestjs-request-context
For while its ok.
#Injectable({ scope: Scope.REQUEST }) worked for me, but I had a lot
of problems when need inject on anothers services.
Exist a another alternative:
https://github.com/abonifacio/nestjs-request-context
For while its ok.
Inject(REQUEST) doesn't work with any passport strategy due to its global state - issue. https://github.com/abonifacio/nestjs-request-context works fine.
I am implementing Login Authentication in my reactjs aplication following the tutorial https://auth0.com/blog/adding-authentication-to-your-react-flux-app//
I have written a class call the AuthService and inside the AuthService I have a function call Login as shown below
import LoginActions from './LoginAction';
const URL_LOGIN = 'loginurl';
class AuthService {
login(username, password) {
// do something
}
}
Now, I am calling this Login method in my Login Component as shown below
//this function is to save data to the API
loginUser = (user) => {
// Here, we call an external AuthService.
Auth.login(user.username, user.password)
.catch(function(err) {
console.log("Error logging in", err);
console.log(err);
});
Everythin works well but when I submit data, I get the error
TypeError: WEBPACK_IMPORTED_MODULE_4__authentication_AuthService.a.login(...) is undefined
When I console log at the login method of the AuthService class, I see the returned data. I have looked around for a fast solution to this error but I have not gotten it. Any help on this will be appreciate.
I do not want to bring this action to the component as I am also going to use it in other areas of my application.
Also,I am a newbie to Reactjs as this is my first Authentication I am doing here.
Add the static keyword before the login method in the AuthService class.
I was waiting for djfdev to see an answer as in his comment:
You’ve defined login as an instance method, but are calling it like a static method. Either add the static keyword before the function name, or create an instance of Auth before calling login on it.
But it seems he's not providing an answer. What he meant that you can define a static method like:
static login(username, password) {
Or call login method in an instance like:
const auth = new Auth
auth.login(user.username, user.password)
Further, I hope you're exporting the class like:
export default AuthService
And importing it like:
import Auth from '...'
From my comment on the OP:
You’ve defined login as an instance method, but are calling it like a static method. Either add the static keyword before the function name, or create an instance of Auth before calling login on it.
So your two options are to, A) use the static keyword to define your method on the class itself:
import LoginActions from './LoginAction';
const URL_LOGIN = 'loginurl';
class AuthService {
static login(username, password) {
// do something
}
}
Or B) create an instance of Auth before calling the login method:
loginUser = (user) => {
// Here, we call an external AuthService.
new AuthService().login(user.username, user.password)
.catch(function(err) {
console.log("Error logging in", err);
console.log(err);
});
See the MDN docs for static
I solved this problem by adding static to the login method as advice above and removing the catch from it.
I am writing automated tests for a webshop using Visual studio Code, webdriverIO and javascript/nodeJS
Everything works fine, but I can't seem to get vs code to autocomplete my methods (I am using a page object model, pageobjects which contain methods are called in tests).
This is my login pageobject with a method to login a user (just an example, actual pageobject contains many more methods) :
class LoginPage{
login(username, password) {
browser.setValue('#ShopLoginForm_Login', username)
browser.setValue('#ShopLoginForm_Password', password)
browser.click('button=Login')
}
}
module.exports = { LoginPage };
This is how I call it in the testfile:
describe('login test', function() {
const LoginPage = require('../../pages/loginPage').LoginPage;
loginPage = new LoginPage
const Menu = require('../../pages/menu').Menu;
menu = new Menu
it('should be able to login with valid credentials', function () {
browser.url(url)
menu.gotoLoginPage()
loginPage.login(username, password)
});
});
Every time I want to call a method in a test, it does not autocomplete the methods name, forcing me to write it out full, leading to many unneccesary typo's. Other types of methods, like webdriverIO browser.click, are autocompleted just fine.
I have tried the same code in webstorm, and there autocomplete does work.
Does anyone know what I can do to get VS code to autocomplete my methods?
pity that no-one was able to answer. I eventually found the answer myself. I will post it here for reference
in my imports:
const LoginPage = require('../../pages/loginPage').LoginPage;
loginPage = new LoginPage
I am forgetting to declare the new instance of the class. The right way should have been;
const LoginPage = require('../../pages/loginPage').LoginPage;
var loginPage = new LoginPage
An alternative way would have been to make my methods static, which removes the need for instantiating the class altogether
I struggled to use auto-suggest in vscode with webdriverio.
This links helped me.
https://webdriver.io/docs/autocompletion.html
https://webdriver.io/docs/pageobjects.html
You answer is right. instanciate the page.
In the official doc, they export class with 'new'
export default new LoginPage()
I am currently learning ES6. While I was playing with the new features, I got stuck at one point. How to call a class method.
So let's say I have a class in one file like below:
class Auth {
checkUserSignedIn() {
//check user signed in
}
signupUser(account) {
//signup user
}
loginUser(account) {
//login user
}
getCurentUser() {
//Current User
}
}
module.exports = Auth;
and then in some other file, let's say a controller I would like to call these functions.
const Auth = require('./auth');
class Controller {
signupUserUsingEmailAndPass(user) {
Auth.signupUser(account);
}
loginUserUsingEmailAndPass(account) {
Auth.loginUser(account);
}
isUserSignedIn() {
checkUserSignedIn();
}
}
module.exports = Controller;
But this doesn't work at all. I guess there is something I am not understanding correctly. Any suggestion/advice?
Methods defined in a class require an instance of that class, i.e. a new Auth somewhere.
Your controller should be defined has
class Controller {
constructor(auth) {
this.auth = auth;
}
}
This approach over the require('myclass') allows for you to inject different implementations of your Auth class.
Should you not desire an instance of Auth for those methods, declare them as static. More on that here
You need to either instatiate the Auth
const authorization = new Auth();
Possibly inside the file containing the Auth class, and just export the instance.
export const authorization = new Auth();
Or, if You want this methods available outside. You can make the methods static. Just add static keyword before the method name during method creation.
You can read more about static methods here
Javascript classes don't work quite like the module pattern (that it seems) you're used to. When you export `Auth, you're exporting the class definition but you still need to instantiate it.
let auth = new Auth()
auth.signupUserUsingEmailAndPass() // or any other function you define
In javascript, a class is useful when you want to populate it with data or some sort of state. If you don't want or need that then you can use a module.