Error with responses on nodejs using inversifyjs - node.js

I'm using nodejs with typescript, typeorm and inversify to manage dependency injection and inversify express utils to handle controllers, when I send a response inside then or catch block only returns a 204 no content response, but if I send the response out of the promise it works, someone who has worked with inversify know what could be happening?
User Controller:
#controller("/user")
export class UserController implements interfaces.Controller {
constructor(#inject(TYPES.UserService) private _userService: IUserService) {}
#httpGet("/")
public GetAll(#request() req: Request, #response() res: Response) {
this._userService
.GetAll()
.then((users) => res.send(users))
.catch((error) => res.send(error));
}
}
User Service:
#injectable()
export class UserService implements IUserService {
private readonly _userRepository: IUserRepository;
constructor(#inject(TYPES.UserRepository) userRepository: IUserRepository) {
this._userRepository = userRepository;
}
public GetAll(): Promise<Array<User>> {
return this._userRepository.GetAll();
}
}
User repository:
#injectable()
export class UserRepository implements IUserRepository {
public GetAll(): Promise<Array<User>> {
const userRepository = getRepository(User);
return userRepository.find();
}
Container and server config:
export abstract class ServerConfig {
protected app: Application;
constructor() {
this.Config();
}
private Config(): void {
const container = new Container();
container.bind<IUserService>(TYPES.UserService).to(UserService);
container.bind<IUserRepository>(TYPES.UserRepository).to(UserRepository);
const server = new InversifyExpressServer(container);
server.setConfig((app) => {
app.use(cors());
app.use(helmet());
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(morgan("dev"));
dotenv.config();
app.set("port", process.env.PORT || 8000);
});
this.app = server.build();
}
public Start(): void {
this.app.listen(this.app.get("port"), () => {
console.log(`Server on port ${this.app.get("port")}`);
});
}
}

you need to return the promise or just await the response from the service. Something like this:
#controller("/user")
export class UserController implements interfaces.Controller {
constructor(#inject(TYPES.UserService) private _userService: IUserService) {}
#httpGet("/")
public async GetAll(#request() req: Request, #response() res: Response): Response {
try {
const users = await this._userService.GetAll();
return res.status(200).json(users);
} catch(error) {
return res.status(500).json(error)
}
}
}

Related

Cannot GET /api/posts

post.controller.ts
class PostController implements Controller {
public path = '/posts';
public router = Router();
private PostService = new PostService();
constructor() {
this.initialiseRoutes();
}
private initialiseRoutes(): void {
this.router.get(
`${this.path}`, this.get);
}
private get = async (
req: Request,
res: Response,
next: NextFunction
): Promise<Response | void> => {
try {
const posts = await this.PostService.get();
res.status(200).json({ posts });
} catch (error:any) {
next(new HttpException(400, error.message));
}
};
}
export default PostController;
post.service.ts
class PostService {
private post = PostModel;
public async get(): Promise<Post[]> {
try {
const posts = await this.post.find();
return posts;
} catch (error) {
throw new Error('Unable to get posts');
}
}
}
export default PostService;
Trying out a Get request for a Blog Post Model in Nodejs+Express API with Mongodb. But getting "Cannot GET /api/posts" error. Other requests such as create posts and User CRUD actions are working fine.

How to move responses from service to controller?

I have login service and login controller.
Service:
class LoginService {
private tokenService: TokenService;
constructor() {
this.tokenService = new TokenService();
this.login = this.login.bind(this);
this.getClient = this.getClient.bind(this);
this.getUserProfile = this.getUserProfile.bind(this);
}
public async login(req: Request, res: Response) {
try {
const { password } = req.body;
const client = await this.getClient(req, res);
const userProfile = await this.getUserProfile(client);
if (!comparePassword(password, userProfile.password))
return res.status(StatusCodes.UNAUTHORIZED).json({ error: 'Incorrect password' });
const tokens = this.tokenService.generateTokens(client);
this.tokenService.setToken(res, tokens);
return res.status(StatusCodes.OK).json(tokens);
} catch (error) {
return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({ msg: error.message });
}
}
}
Controller:
class LoginController {
private loginService: LoginService;
constructor(private router: IRouter) {
this.router = router;
this.loginService = new LoginService();
this.routes();
}
public routes() {
this.router.route('/auth').post(loginMiddleware, this.loginService.login);
}
}
So, my question is, how to move responses logic to controller correctly, cuz i'm just started to learn nestjs.

Passport-saml strategy implementation in nodejs

I need some help to implement SAML 2.0 SSO with passport-saml, is used a different strategy to implement the app:
(is not my strategy and I'm not very used to nodejs, i read every documentation possible like: https://github.com/node-saml/passport-saml/blob/master/README.md
but i dont have any idea how to adapt it to this code)
app.ts:
import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';
import dotenv from 'dotenv';
import Controller from '../controllers/controller';
dotenv.config();
class App {
public app: express.Application;
public port: number;
constructor(controllers: Controller[], port: number) {
this.app = express();
this.port = port;
this.initializeMiddlewares();
this.initializeControllers(controllers);
}
private initializeMiddlewares() {
this.app.use(bodyParser.urlencoded({extended : true}));
this.app.use(cors());
}
private initializeControllers(controllers: Controller[]) {
controllers.forEach((controller: Controller) => {
this.app.use('/', controller.router);
});
}
public listen() {
this.app.listen(this.port, () => {
console.log(`App listening on the port ${this.port}`);
});
}
}
export default App;
controller.ts
import { Request, Response, Router } from 'express';
import { GenericErrorResponse, GenericSuccessResponse } from '../models/response/response.model';
class Controller {
public path: string;
public router = Router();
constructor(path: string) {
this.path = path;
}
public generateErrorResponse(status: string, error: any) {
return new GenericErrorResponse(status, error);
}
public generateSuccessResponse(status: string, data: any) {
return new GenericSuccessResponse(status, data);
}
}
export default Controller;
server.ts
import App from './app';
import TestController from '../controllers/test.controller';
const app = new App(
[
new TestController('/test'),
],
parseInt(`${process.env.PORT}`, 10) || 3000
);
app.listen();
test.controller.ts(where I implement every route)
import { Request, Response } from 'express';
import Controller from './controller';
class TestController extends Controller {
constructor(path: string) {
super(path);
this.intializeRoutes();
}
private intializeRoutes() {
this.router.get(`${this.path}/general`, this.getGeneral);
}
getGeneral = (request: Request, response: Response) => {
response.status(200).json(this.generateSuccessResponse('Success', 'Success'));
}
}
export default TestController;

SAML SSO with NodeJs

I want to implement SAML 2.0 SSO with passport-saml library but I don't know where to insert it.
I tried to follow this documentation: https://github.com/node-saml/passport-saml but i have no idea where to insert the saml strategy..
and here is my app:
app.ts:
import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';
import dotenv from 'dotenv';
import Controller from '../controllers/controller';
dotenv.config();
class App {
public app: express.Application;
public port: number;
constructor(controllers: Controller[], port: number) {
this.app = express();
this.port = port;
this.initializeMiddlewares();
this.initializeControllers(controllers);
}
private initializeMiddlewares() {
this.app.use(bodyParser.urlencoded({extended : true}));
this.app.use(cors());
}
private initializeControllers(controllers: Controller[]) {
controllers.forEach((controller: Controller) => {
this.app.use('/', controller.router);
});
}
public listen() {
this.app.listen(this.port, () => {
console.log(`App listening on the port ${this.port}`);
});
}
}
export default App;
controller.ts:
import { Request, Response, Router } from 'express';
import { GenericErrorResponse, GenericSuccessResponse } from '../models/response/response.model';
class Controller {
public path: string;
public router = Router();
constructor(path: string) {
this.path = path;
}
public generateErrorResponse(status: string, error: any) {
return new GenericErrorResponse(status, error);
}
public generateSuccessResponse(status: string, data: any) {
return new GenericSuccessResponse(status, data);
}
}
export default Controller;
server.ts
import App from './app';
import TestController from '../controllers/test.controller';
const app = new App(
[
new TestController('/test'),
],
parseInt(`${process.env.PORT}`, 10) || 3000
);
app.listen();
test.controller.ts(where is implemented every route)
import { Request, Response } from 'express';
import Controller from './controller';
class TestController extends Controller {
constructor(path: string) {
super(path);
this.intializeRoutes();
}
private intializeRoutes() {
this.router.get(`${this.path}/general`, this.getGeneral);
}
getGeneral = (request: Request, response: Response) => {
response.status(200).json(this.generateSuccessResponse('Success', 'Success'));
}
}
export default TestController;

How to implement a profile?

I have a token based authorization. Authorization happens well there are no errors. But now need to somehow display the data of an authorized user. Please tell me how to properly implement the profile on the client (Angular 6)?
I have this server:
controller:
const db = require('../config/db.config.js')
const User = db.user
const errorHandler = require('../utils/errorHandler')
module.exports.getProfile = async function(req, res) {
try {
await User.findOne({ id: req.user.id}, (user) => {
res.json({
success: true,
user: user,
message: "Successful"
})
})
}catch(e) {
errorHandler(req, e)
}
}
routes:
const express = require('express')
const router = express.Router()
const controller = require('../controllers/user')
const passport = require('passport')
router.get('/profile', passport.authenticate('jwt', {session: false}), controller.getProfile)
module.exports = router
passport:
const JwtStrategy = require('passport-jwt').Strategy
const ExtractJwt = require('passport-jwt').ExtractJwt
const db = require('../config/db.config.js')
const User = db.user
const options = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.SECRET_OR_KEY
}
module.exports = passport => {
passport.use(
new JwtStrategy(options, async (payload, done) => {
try {
const user = await User.findById(payload.userId).toJSON('username id')
if (user) {
done(null, user)
} else {
done(null, false)
}
} catch(e) {
console.log(e)
}
})
)
}
And here is a part of the client:
app-components:
import { Component, OnInit } from '#angular/core';
import { AuthService } from './shared/services/auth.service';
#Component({
selector: 'app-root',
template: '<router-outlet></router-outlet>'
})
export class AppComponent implements OnInit {
constructor(private auth: AuthService) {
}
ngOnInit() {
const potentialToken = localStorage.getItem('auth-token')
if (potentialToken !== null) {
this.auth.setToken(potentialToken)
}
}
}
auth.service:
import { Injectable, Optional } from "#angular/core";
import { HttpClient } from "#angular/common/http";
import { Router, ActivatedRoute } from "#angular/router";
import { Observable } from "rxjs";
import { tap } from "rxjs/operators";
import { User } from "../interfaces";
#Injectable({
providedIn: 'root'
})
export class AuthService {
private token = null;
constructor(
private http: HttpClient,
#Optional() private _activatedRoute: ActivatedRoute,
#Optional() private _router: Router
) {}
login(user: User): Observable<{token: string}> {
return this.http.post<{token: string}>('/api/auth/login', user)
.pipe(
tap(
({token}) => {
localStorage.setItem('auth-token', token)
this.setToken(token)
}
)
)
}
setToken(token: string) {
this.token = token
}
getToken(): string {
return this.token
}
isAuthenticated(): boolean {
return !!this.token
}
logout() {
this.setToken(null)
localStorage.clear()
}
}
token.interceptor.ts:
import { Injectable } from "#angular/core";
import { AuthService } from "../services/auth.service";
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from "#angular/common/http";
import { Observable, throwError } from "rxjs";
import { catchError } from "rxjs/operators";
import { Router } from "#angular/router";
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private auth: AuthService, private router: Router){
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.auth.isAuthenticated()) {
req = req.clone({
setHeaders: {
Authorization: this.auth.getToken()
}
})
}
return next.handle(req).pipe(
catchError(
(error: HttpErrorResponse) => this.handleAuthError(error)
)
)
}
private handleAuthError(error: HttpErrorResponse): Observable<any> {
if (error.status === 401) {
this.router.navigate(['/sign_in']), {
queryParams: {
sessionFailed: true
}
}
}
return throwError(error)
}
}
What need to implement on the client to display user data. Tell me please, I'm new.
You just need to create a Service class called UserService which will keep the information related to logged in user.
Whenever login action is performed successfully, just get the user details and fill it in UserService class.
user.service.ts
export class UserService {
private currentUser$: new BehaviorSubject<User>; //<-- check your user type
constructor(private http: Http) { }
getCurrentUser() {
this.currentUser$;
}
setCurrentUser(user:User){
this.currentUser$.next(user); //update the current user
}
}
This service class will give the Observable and you can use it any component or service class.

Resources