Apply an interface in Typescript - node.js

I am creating a project with Node JS and Typescript, I have a class and an interface where I type all the data. What I need to know is how to apply it to the classroom.
This is my interface:
export interface IController {
url: string,
api: string
}
This is my class where I want to apply it:
import { Request, Response } from 'express';
import { constUtils } from '../utils/const.utils';
import { IController } from '../utils/model.utils';
import { utilsController } from '../utils/index.utils';
class IndexController {
public async index(req: Request, res: Response): Promise<IController> {
try {
let api = req.query.api;
let constUt = new constUtils();
let url = constUt.conf.API_MOCS[`${api}`].url;
await utilsController.utilsCsvConverter(api, url);
} catch (error) {
console.log(error);
}
}
}
export const indexController = new IndexController();

This assumes that the local variables url and api should be returned in a Promise resolving to an object specified the by IController interface:
import { Request, Response } from 'express';
import { constUtils } from '../utils/const.utils';
import { IController } from '../utils/model.utils';
import { utilsController } from '../utils/index.utils';
class IndexController {
public async index(req: Request, res: Response): Promise<IController> {
try {
let api = req.query.api;
let constUt = new constUtils();
let url = constUt.conf.API_MOCS[`${api}`].url;
await utilsController.utilsCsvConverter(api, url);
return {url, api};
} catch (error) {
console.log(error);
}
}
}
export const indexController = new IndexController();

If you want use or apply interface to the class you should have to implement it within the applied class. Below code might give you clear idea.
class IndexController implements csvModel {
url: string;
api: string;
public async index(req: Request, res: Response): Promise<IController> {
try {
this.api = req.query.api;
let constUt = new constUtils();
this.url = constUt.conf.API_MOCS[`${api}`].url;
} catch (error) {
console.log(error);
}
}
}
export const indexController = new IndexController();

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 inject repository into nestjs-rate-limiter guard

I've tried to inject a repository into the guard which extends from RateLimiterGuard nestjs-rate-limiter but I got an error when call super.canActivate(ctx). It said that this.reflector.get is not a function. Is there any mistake that I have?
Here is my code:
import { RateLimiterGuard, RateLimiterOptions } from 'nestjs-rate-limiter';
import type { Request } from 'express';
import config from 'config';
import { ExecutionContext, Injectable } from '#nestjs/common';
import { MockAccountRepository } from '../modules/mock/mock-accounts/accounts-mock.repository';
import { Reflector } from '#nestjs/core';
import { UserIdentifierType } from 'src/modules/users/user.types';
const ipHeader = config.get<string>('server.ipHeader');
#Injectable()
export class ForwardedIpAddressRateLimiterGuard extends RateLimiterGuard {
constructor(
reflector: Reflector,
options: RateLimiterOptions,
private readonly mockAccRepo: MockAccountRepository,
) {
super(options, reflector);
}
protected getIpFromRequest(request: Request): string {
return request.get(ipHeader) || request.ip;
}
async canActivate(ctx: ExecutionContext): Promise<boolean> {
const req = ctx.switchToHttp().getRequest();
const phoneNumber = req.body?.phoneNumber || req.params?.phoneNumber;
// If mock phone number, always allow
if (
await this.mockAccRepo.findOne({
identifier: phoneNumber,
identifierType: UserIdentifierType.PHONE_NUMBER,
})
) {
return true;
}
// Otherwise, apply rate limiting
return super.canActivate(ctx);
}
}

"then" is not exuceted after a Promise<void> when writing a file from a POST Request

I have currently an express server. I am trying to make a POST request without success.
Here is my ccontroller :
import { BAD_REQUEST } from '#app/constant';
import { SaveDrawService } from '#app/services/save-draw.service';
import { TYPES } from '#app/types';
import { Image } from '#common/communication/Image';
import { NextFunction, Request, Response, Router } from 'express';
import { inject, injectable } from 'inversify';
import 'reflect-metadata';
#injectable()
export class SaveDrawController {
router: Router;
constructor(#inject(TYPES.SaveDrawService) private saveDrawService: SaveDrawService) {
this.configureRouter();
}
private configureRouter(): void {
this.router = Router();
this.router.post('/write', (req: Request, res: Response, next: NextFunction) => {
if (!req.body) return res.sendStatus(BAD_REQUEST);
this.saveDrawService.writeData(req.body as Image);
return res.sendStatus(this.saveDrawService.code);
});
this.router.get('/read', (req: Request, res: Response, next: NextFunction) => {
return res.send(this.saveDrawService.readImageData());
});
}
}
Image here is a interface that i want to POST with these parameters:
export interface Image {
title: string;
tags: string[];
data: string; // base64 image from HTML canvas
}
Here is my service where I try to write the file :
import { ERROR, OK } from '#app/constant';
import { Image } from '#common/communication/Image';
import { readFile, writeFile } from 'fs';
import { injectable } from 'inversify';
import 'reflect-metadata';
import * as util from 'util';
#injectable()
export class SaveDrawService {
code: number;
constructor() {}
async writeData(image: Image): Promise<void> {
const base64Data = image.data.replace('data:image/png;base64,', '');
const write = util.promisify(writeFile);
return await write('test.png', base64Data, 'base64')
.then(() => {
this.code = OK; // 200
})
.catch((error: Error) => {
console.error(error);
this.code = ERROR; // 500
});
}
async readImageData(): Promise<string> {
const read = util.promisify(readFile);
return await read('test.png', { encoding: 'base64' });
}
extractFormat(base64Data: string) {}
}
The problem is that the "then" in write is not executed after the write and the "this.code" is therefore never updated and makes the request crash. I just started and I really don't know what can be causing this.
Here is my request I make to test the code:
On my server the POST is received and my server log this :
POST /api/draw/write 500 20.825 ms - 92
UPDATE: both my GET and POST return a error, but they are writing and reading the file on the server (I verify by making a POST and after a GET with logs to see if they are the same)
I think this is what you should change. Don't use async/await with then/catch, these are two different notation to wait for asynchronous code and get data.
async writeData(image: Image): Promise<void> {
const base64Data = image.data.replace('data:image/png;base64,', '');
const write = util.promisify(writeFile);
const resp = await write('test.png', base64Data, 'base64');
if (resp.ok) // whatever your condition
{
this.code = OK;
} else {
console.error(resp.error); // show error here
this.code = ERROR;
}
}
Check here for more details.

How to pool postgresql connections in nodejs with facade design pattern?

Hello i am writing simple web application using design similar to facade design pattern. Application is written in Typescript using nodejs, expressjs, node-postres and inversify. Let say i have this simple example
Router.ts
router.get('/test', testController.test);
TestController.ts
import { Request, Response } from 'express';
import { ITestUC } from '../usecase/TestUC';
import { di } from '../core/Di';
import { TYPES } from '../core/Types';
class TestController {
public async test(req: Request, res: Response, next: Function) {
const uc = di.get<ITestUC>(TYPES.ITestUC);
await uc.run();
res.send({ data:1 });
}
}
export const testController = new TestController();
TestUC.ts
import "reflect-metadata";
import { injectable, interfaces } from "inversify";
import { di } from "../core/Di";
import { TYPES } from "../core/Types";
import { ITestManager1 } from "../library/Test/TestManager1";
import { ITestManager2 } from "../library/Test/TestManager2";
import { PoolClient } from "pg";
import { PostgresClient, IPostgresClient } from "../core/PostgresClient";
import { IPostgresPool } from "../core/PostgresPool";
function db(transaction: boolean) {
return (target: any, property: string, descriptor: TypedPropertyDescriptor<() => void>) => {
const fn = descriptor.value;
if(!fn) return;
descriptor.value = async function (){
let poolClient: PoolClient,
postgresClient: PostgresClient = new PostgresClient();
try {
poolClient = await di.get<IPostgresPool>(TYPES.IPostgresPool).pool.connect();
postgresClient.set(poolClient);
di.rebind<IPostgresClient>(TYPES.IPostgresClient).toDynamicValue((context: interfaces.Context) => { return postgresClient });
if (transaction) postgresClient.begin();
await fn.apply(this);
if (transaction) postgresClient.commit();
} catch (e) {
if (transaction) postgresClient.rollback();
throw e;
} finally {
postgresClient.get().release();
}
}
}
}
#injectable()
export class TestUC implements ITestUC {
#db(true)
public async run(): Promise<void> {
const manager1 = await di.get<ITestManager1>(TYPES.ITestManager1);
manager1.test1('m1');
const manager2 = await di.get<ITestManager2>(TYPES.ITestManager2);
manager2.test1('m2');
}
}
export interface ITestUC {
run(): Promise<void>
}
TestManager1.ts
import { injectable, inject} from "inversify";
import "reflect-metadata";
import { TYPES } from "../../core/Types";
import { ITestSql1 } from "./TestSql1";
#injectable()
export class TestManager1 implements ITestManager1 {
#inject(TYPES.ITestSql1) private sql: ITestSql1;
public async test1(value: string) {
await this.sql.test1(value);
}
}
export interface ITestManager1 {
test1(value: string)
}
TestSql1.ts
import { injectable, inject } from "inversify";
import "reflect-metadata";
import { IPostgresClient } from "../../core/PostgresClient";
import { TYPES } from "../../core/Types";
#injectable()
export class TestSql1 implements ITestSql1{
#inject(TYPES.IPostgresClient) db: IPostgresClient;
public async test1(value: string) {
const query = {
name: 'insert-test',
text: `
INSERT INTO pr.test (
process,
operation,
key
) VALUES (
$1,
$2,
$3
)`,
values: [
this.db.get()['processID'],
1,
value
]
};
await this.db.get().query(query);
}
}
export interface ITestSql1 {
test1(value: string)
}
PostgresClient.ts
import { PoolClient } from "pg";
export class PostgresClient implements IPostgresClient {
private client: PoolClient;
get(): PoolClient {
return this.client;
}
set(client: PoolClient) {
this.client = client;
}
async begin() {
await this.client.query('BEGIN');
}
async commit() {
await this.client.query('COMMIT');
}
async rollback() {
await this.client.query('ROLLBACK');
}
}
export interface IPostgresClient {
get(): PoolClient;
set(client: PoolClient);
commit();
rollback();
begin();
}
TestManager2.ts and TestSql2.ts are basically same as TestManager1.ts and TestSql1.ts
My problem is that every request seems to use only one same postgresql connection from pool (Tested with JMeter) and serialize all api request.
Pool doesn't even create other connections to postgresql. It looks like other requests waits for previous request end or postgresql connection release.
How to instantiate one connection (transaction) for every request using node-postgres pool and at the same time don't block other requests?
Is this code blocking? Or i misunderstood somthing in documentation? Or simply this design isn't suitable for nodejs? I really don't now and stuck for week.

Nest js with swagger decorators, re decorate methods

I'm building an API with nest js with swagger, I builded an abstract class "BaseController" with the CRUD methods, the idea is extends from the BaseController to the controllers passing the entity. My question is how I could re-decorate the inherited methods to implement the swagger decorators in the different controllers (with different entities)?
This is my BaseController:
import {
Body,
Delete,
Get,
HttpException,
HttpStatus,
InternalServerErrorException,
Param,
Post,
Put,
Query,
} from '#nestjs/common';
import { UpdateResult } from 'typeorm';
import { BaseService } from './base.service';
import { ApiException } from '#models/api-exception.model';
export abstract class BaseController<T> {
protected readonly service: BaseService<T>;
constructor(service: BaseService<T>) {
this.service = service;
}
#Get()
root(#Query('filter') filter = {}): Promise<T[]> {
try {
return this.service.find(filter);
} catch(e) {
throw new HttpException(e, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
#Get(':id')
getById(#Param('id') id: string | number): Promise<T> {
try {
return this.service.findById(id);
} catch(e) {
throw new HttpException(e, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
#Post()
create(#Body() body: T): Promise<T> {
try {
return this.service.create(body);
} catch(e) {
throw new HttpException(e, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
#Put()
update(#Body() body: { id: string | number } & T): Promise<UpdateResult> {
return this.service.update(body.id, body);
}
#Delete(':id')
delete(#Param('id') id: string | number) {
try {
return this.service.delete(id);
} catch(e) {
throw new InternalServerErrorException(e);
}
}
}
For example if a create "TodoController extends BaseController" how I could apply the swagger decorators? Is there a way to make something like "dynamic decorators"?

Resources