Why can't I access `userService` variable after express instance running in Nodejs - node.js

I was trying to create an endpoint in node.js, more specifically in express
but I am not sure why I can't access userService variable when requesting from a client.
I've gotten Cannot read property 'userService' of undefined, but when i move ServicesFactory.getInstance().getUserService() inside the signUp function it works?!
I am guessing that node.js garbage collects it due to it's not being used until the user make a request.
export class UserApi implements WebEndpoint {
router: Router
userService = ServicesFactory.getInstance().getUserService()
constructor() {
this.router = Router()
this.router.post('/signup', this.signUp)
}
signUp(req: Request, res: Response): void {
const user: User = req.body
this.userService.signUp(user)
res.send("Successfully registered")
}
}

I found the problem, so basically I am a noob.
consider this example
class a {
constructor() {
this.a1 = 'hello';
}
greet(){
const greeting = `${this.a1} dude!`;
console.log(greeting);
};
}
class b {
b1 = new a();
constructor() {
this.b1.greet.call();
}
}
new b();
Now it wouldn't run, because b class called greet method with a new context, the same with express when you provide a function as a handler on an Express endpoint it will be called with a new set of context (read:this) that's why this.userService in my code above won't work because there is no userService property in the context provided by Express.
The solution is simple. Arrow function.
signUp = (req: Request, res: Response): void => {
const user: User = req.body
this.userService.signUp(user)
res.send("Successfully registered")
}
Now the function will inherit it's class's context.You can refer to this for more detail answer.

Related

Dependecy Injection using Class into Express

I'm using Express into a TypeScript project and I have the following situation
This is my route file
...
import findAllUsersFactory from "src/factory/FindAllUsers";
routes.get("/users", findAllUsersFactory().handle);
...
This is the factory where I do a sequence of injections
const findAllUsersFactory = () => {
const findAllUserRepository = new PrismaUsersRepository();
const findAllUsersBusiness = new FindAllUsersBusiness(findAllUserRepository);
const findAllUsersController = new FindAllUsersController(findAllUsersBusiness);
return findAllUsersController;
};
This is my Controller
class FindAllUsersController {
constructor(private findUserBusiness: FindAllUsersBusiness) { }
async handle(request: Request, response: Response) {
const allUsers = await this.findUserBusiness.execute();
return response.status(200).send({ allUsers });
}
}
And finally my Business
class FindAllUsersBusiness {
constructor(private usersRepository: IUsersRepository) {}
async execute() {
return this.usersRepository.findAll();
}
}
The problem is that I'm getting an error "Cannot read property 'execute' of undefined" because the findUserBusiness into handle function is undefined. And what I can't understand is that if I change my route to
routes.get("/users", (request, response) => {
findAllUsersFactory().handle(request, response);
});
it works
I've tried to log the functions, but I can say why findUserBusiness is undefined since it came from the constructor, and since the handle functions came from an instance of FindAllUsersController it should have it "defined"
You need to make some adjustments in order to adapt your factory to the way router.get expects its parameters.
const findAllUsersFactory = (req, res) => {
const findAllUserRepository = new PrismaUsersRepository();
const findAllUsersBusiness = new FindAllUsersBusiness(findAllUserRepository);
const findAllUsersController = new FindAllUsersController(findAllUsersBusiness);
return findAllUsersController.handle(req, res)
};
Then in your router you need to do the following:
routes.get("/users", findAllUsersFactory);

TypeScript in Node with Express. Cannot set a controller's class property with a constructor

I have a Node app with Express implementing TypeScript using Babel.
I tried creating a UserController with a private property _user: User and set it in the class constructor. The problem is, I keep getting "message": "Cannot read property '_user' of undefined" in the output.
This is my class:
export class UserController extends CrudController {
private _user: User;
constructor() {
super();
const user = new User();
user.id = 1;
user.email = 'johnappleseed#apple.com';
user.firstName = 'John';
user.lastName = 'Appleseed';
this._user = user; // Setting the global class property
}
get(req: Request, res: Response) {
res.json({ user: this._user });
}
}
The extended class CrudController is just an abstract class, but still, here's the code:
export abstract class CrudController {
public abstract get(req: Request, res: Response): void;
}
This is my routes file:
const userController = new UserController();
router.route('/user')
.get(userController.get);
What could be the issue? Thanks!
Since your passing userController.get to the router, you will loose the this-context of the class, once the router is invoked.
You can solve this by binding the method to userController and thus setting this to the controller (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind for more information):
const userController = new UserController();
router.route('/user')
.get(userController.get.bind(userController);

How to get params from url in angular and express?

I have a URL which looks like http://www.example.com/idf34he8sf/9iad2hf7usnf. I want to get the params idf34he8sf and 9iad2hf7usnf
I have used below code
In angular
this.route.paramMap.subscribe(params => {
this.organizationId = params.get("organizationId");
this.embedId= params.get("embedId");
}
In Node
req.params
and
req.originalUrl
I want to get the params idf34he8sf and 9iad2hf7usnf
You have to define params in your api as-
example/:organizationId/:embedId
then fetch these params using-
constructor(private router: Router) {
this.organizationId = this.router.snapshots.params['organizationId']
this.embedId = this.router.snapshots.params['embedId']
}
Node knows nothing about Angular, you will need to design your API to take those paramaters and pass them when calling the API.
You can use #angular/router
import { Router } from '#angular/router';
Define a variable to hold URL
href:string;
params:string[];
Then in Constructor
constructor(private router: Router) {
}
In ngOnInit
this.href = this.router.url;
this.params = this.href.split('/');
In angular you can use ActivatedRoute to fetch params from the URL
import { Router, ActivatedRoute} from '#angular/router';
constructor(route: ActivatedRoute){}
/* Do Something*/
public someFunction(){
this.route.queryParams.subscribe(params => {
/* use Params*/
}
}
In NodeJS you will need to add while declaring your routes as shown below:
router.get('/:id', (req,res) =>{
let id = req.params; // for parameterised routes
// fetching query string use below:
// region = req.query.region;
return res.json(id);
});
//import the ActivatedRoute to use route.snapshot.params
import { ActivatedRoute} from '#angular/router';
//define a variable to store the param from url
public param:any;
//And in constructor create a instance of ActivatedRoute
constructor(private route:ActivatedRoute,) {}
//Then in ngOnInit
ngOnInit(): void {
this.param = this.route.snapshot.params["Your-params-name in url)"];
// params-name means (/:id/)
//this will store the params from your url to the variable param (public)
}
//in my url is I wanted to store specific id of a book
// from url localhost:4200/books/60ab539f678gfraep/
// I used
{path: 'books/:id',component: showBookComponent},
//in my ROUTING MODULE
//so I gave above code as
public Id:string;
ngOnInit():void {
// this.Id = route.snapshot.params['id'];
}

How to unit test a chain of express middlewares?

I have a controller class that exports an array containing a number of middlewares (utilizing express-validator) that verify that all essential parts of a request are present and as the last element of the array the handler for the request:
Controller class:
import { body, ValidationChain } from "express-validator/check";
import { Request, Response, Handler } from "express";
export default class UserController {
signupChainPost: Handler[];
constructor() {
this.signupChainPost = [
this.getEmailExistsMiddleware("email"),
this.getPasswordValidationMiddleware("password"),
this.signupHandlerPost.bind(this)
];
}
private getEmailExistsMiddleware(fieldName: string): ValidationChain {
return body(fieldName, "some error").isEmail().custom((value, { req }) => {
// ...
});
}
private getPasswordValidationMiddleware(fieldName: string): ValidationChain {
return body(fieldName, "some error").isLength({ min: 5 });
}
private async signupHandlerPost(req: Request, res: Response) {
// request handling
}
}
Usage of the controller class in the main server file using Epxress.js:
const userController = new UserController();
app.post("/user/create", userController.signupChainPost);
Now I want to write unit tests for my request handler but I can't figure out how to test an array of middlewares/handlers. Should I only test the "real handler" and trust the middlewares to prevent invalid requests from reaching my handler? Or is my application design fundamentally wrong which leads to the unit tests being hard to write?
Thanks in advance for the help :)

"this" lost after construct? (ts/node/express)

I am trying to build a simple http app using node-express.
Issue when setting up routes, the constructor of the MyRouter class has this but it's lost in the getRoutes() function.
class Main {
public async run(): Promise<void> {
const myRouter = new MyRouter(this.config);
// this.server is express() during construct
this.server.use("/v1", myRouter.getRoutes);
await this.server.listen(this.config.rest.port);
}
}
class MyRouter {
private router: express.Router;
constructor(private config: any) {
this.router = express.Router();
console.log(this); // Prints the whole Router object!
}
public getRoutes(): express.Router {
console.log(this); // = "undefined" !
this.router.use("/test", otherClass.getRoutes);
return this.router;
}
}
Why is this?
The value of this depends not on where it is defined but by how a function is called. You did this:
this.server.use("/v1", myRouter.getRoutes);
This is equivalent to:
var tmp = myRouter.getRoutes;
this.server.use("/v1", tmp); // `this` will refer to the global object
There are two solutions. Either wrap it in an anonymous function to retain the object that calls the function:
this.server.use("/v1", function(){return myRouter.getRoutes()});
Or use .bind()
this.server.use("/v1", myRouter.getRoutes.bind(myRouter));

Resources