Nest js POST Request Not Recognizing DTO method - javascript

I'm having some trouble hitting a POST endpoint that triggers a typeorm repository.save() method to my postgres DB.
Here's my DTO object:
import { ApiProperty } from '#nestjs/swagger/';
import { IsString, IsUUID} from 'class-validator';
import { Client } from '../../../models';
import { User } from '../../../user.decorator';
export class ClientDTO implements Readonly<ClientDTO> {
#ApiProperty({ required: true })
#IsUUID()
id: string;
#ApiProperty({ required: true })
#IsString()
name: string;
public static from(dto: Partial<ClientDTO>) {
const cl = new ClientDTO();
cl.id = dto.id;
cl.name = dto.name;
return cl;
}
public static fromEntity(entity: Client) {
return this.from({
id: entity.id,
name: entity.name,
});
}
public toEntity = (user: User | null) => {
const cl = new Client();
cl.id = this.id;
cl.name = this.name;
cl.createDateTime = new Date();
cl.createdBy = user ? user.id : null;
cl.lastChangedBy = user ? user.id : null;
return cl;
}
}
My controller at POST - /client:
import {
Body,
Controller,
Get, Post
} from '#nestjs/common';
import { ClientDTO } from './dto/client.dto';
import { ClientService } from './client.service';
import { User } from 'src/user.decorator';
#Controller('client')
export class ClientController {
constructor(
private clientService: ClientService
) { }
#Get()
public async getAllClients(): Promise<ClientDTO[]> {
return this.clientService.getAllClients();
}
#Post()
public async createClient(#User() user: User, #Body() dto: ClientDTO): Promise<ClientDTO> {
return this.clientService.createClient(dto, user);
}
}
And my service:
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { Client } from '../../models';
import { ClientDTO } from './dto/client.dto';
import { User } from '../../user.decorator';
#Injectable()
export class ClientService {
constructor(
#InjectRepository(Client) private readonly clientRepository: Repository<Client>
) {}
public async getAllClients(): Promise<ClientDTO[]> {
return await this.clientRepository.find()
.then(clients => clients.map(e => ClientDTO.fromEntity(e)));
}
public async createClient(dto: ClientDTO, user: User): Promise<ClientDTO> {
return this.clientRepository.save(dto.toEntity(user))
.then(e => ClientDTO.fromEntity(e));
}
}
I get a 500 internal server error with log message stating that my ClientDTO.toEntity is not a function.
TypeError: dto.toEntity is not a function
at ClientService.createClient (C:\...\nest-backend\dist\features\client\client.service.js:29:47)
at ClientController.createClient (C:\...\nest-backend\dist\features\client\client.controller.js:27:35)
at C:\...\nest-backend\node_modules\#nestjs\core\router\router-execution-context.js:37:29
at process._tickCallback (internal/process/next_tick.js:68:7)
I'm confused because this only happens via http request. I have a script that seed my dev database after I launch it fresh in a docker container called seed.ts:
import * as _ from 'lodash';
import { Client } from '../models';
import { ClientDTO } from '../features/client/dto/client.dto';
import { ClientService } from '../features/client/client.service';
import { configService } from '../config/config.service';
import { createConnection, ConnectionOptions } from 'typeorm';
import { User } from '../user.decorator';
async function run() {
const seedUser: User = { id: 'seed-user' };
const seedId = Date.now()
.toString()
.split('')
.reverse()
.reduce((s, it, x) => (x > 3 ? s : (s += it)), '');
const opt = {
...configService.getTypeOrmConfig(),
debug: true
};
const connection = await createConnection(opt as ConnectionOptions);
const clientService = new ClientService(connection.getRepository(Client));
const work = _.range(1, 10).map(n => ClientDTO.from({
name: `seed${seedId}-${n}`,
}))
######################## my service calls ClientDTO.toEntity() without issue ###########################
.map(dto => clientService.createClient(dto, seedUser)
.then(r => (console.log('done ->', r.name), r)))
return await Promise.all(work);
}
run()
.then(_ => console.log('...wait for script to exit'))
.catch(error => console.error('seed error', error));
It makes me think I am missing something simple/obvious.
Thanks!

Looks like you are using ValidationPipe. The solution is mentioned here
https://github.com/nestjs/nest/issues/552
when setting your validation pipe you need to tell it to transform for example
app.useGlobalPipes(new ValidationPipe({
transform: true
}));

The fact that the dto is declared like this dto: ClientDTO in the controller is not enough to create instances of the class. This is just an indication for you and the other developers on the project, to prevent misuses of the dto object in the rest of the application.
In order to have instances of classes, and use the methods from the class, you have to explicitly set a mapping like this:
#Post()
public async createClient(#User() user: User, #Body() dto: ClientDTO): Promise<ClientDTO> {
const client = ClientDTO.from(dto);
return this.clientService.createClient(client, user);
}
Assuming ClientDTO.from is the right function to use for the data contained in dto. If not, adapt it, create a new one, or add a constructor.

Your dto was not a class-based object when coming in through your api call-- it's just a generic object. Therefore it can't have methods and so your toEntity method won't work. The error message you get is a red herring that doesn't tell you the true cause of the failure.
You can fix this by creating a new object based on your class and then calling a method on the new object to copy the properties in from your plain object dto, or by using the class-transformer library, or by whatever you want that achieves the same result.

Related

Pass value to subject service Angular js

i try passa values to child component using subject service, I am based on Documentatio, but somethink is wrong and when a try print data dont show nothing.
i have the navComponent which request api base on select input. When changing select update request and send new data to child page.
Service:
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs';
#Injectable()
export class SearchService {
// Observable string sources
private data = new Subject<any>();
// Observable string streams
value$ = this.data.asObservable();
// Service message commands
setValeu(value: any) {
this.data.next(value);
}
}
NavComponent:
async consultaIndicadores() {
try {
this.loading = true
let con = await this.rq.postRequest(... request ...).toPromise()
this.loading = false
if (con.status == 200) {
this.dados = con.data;
this.search.setValeu(this.dados)
}
}
} catch (error) {
this.loading = false
console.log(error)
}
}
childComponent
constructor(private trans: SearchService) {
this.subscription = trans.value$.subscribe(val => {
console.log(val);
})
}
in each component i seted provider, pass service to constructor etc... I dont know what its wrong. please help me

NestJS createParamDecorator return undefined

I'm using Nest version ^6.7.2
I'm trying to create a createParamDecorator that gets the req.user value from a request.
Inside the createParamDecorator, the req.user has a value, however when I try to get the value in a controller by using the decorator the value is undefined.
const AuthSession = createParamDecorator((data, req) => {
console.log(req.user); // session data
return req.user;
});
Controller()
export default class AuthController {
#Get("/token/ping")
#UseGuards(AuthGuard("jwt"))
tokenPing(#AuthSession() session: Session) {
console.log(session); // undefined
return session;
}
}
Edit: I just tried updating to nestjs v7 and I'm having the same issue
import { createParamDecorator, ExecutionContext } from "#nestjs/common";
const AuthSession = createParamDecorator((data: any, ctx: ExecutionContext) => {
return { message: "asdf" };
});
export default AuthSession;
#Controller()
export default class AuthController {
#Get("/token/ping")
#UseGuards(AuthGuard("jwt"))
tokenPing(#AuthSession() session: Session) {
console.log(session); // undefined
return session;
}
}
you can get the information firs from ExecutionContext:
import { createParamDecorator, ExecutionContext } from '#nestjs/common';
export const User = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);
check the example in the doc : Custom decorator
I figured out what the issue was. I had a custom validation PipeTransform that returned undefined if the ArgumentMetadata.type was neither "body" nor "param". So now I just return the first argument of the validator's transform method (the input) if the ArgumentMetadata.type is neither "body" nor "param" and that fixed the problem.

Check if displayName in users is unique Firebase & Angular

Just before adding a new user to firebase, I want to check if the displayName already exists for an other user. I'm storing the displayName in users:
root / users / document *(uid as id)* / fields *like uid, displayName, email, ...*
I've tried it like this:
import { Injectable, NgZone } from '#angular/core';
import { auth } from 'firebase/app';
import { User } from "./user";
import { Router } from "#angular/router";
import { AngularFireAuth } from "#angular/fire/auth";
import { AngularFirestore, AngularFirestoreDocument } from '#angular/fire/firestore';
import { AngularFireDatabase } from '#angular/fire/database';
import { ToastController } from '#ionic/angular';
...
constructor(
public firestore: AngularFirestore,
public firebase: AngularFireDatabase,
public ngFireAuth: AngularFireAuth,
public router: Router,
public ngZone: NgZone,
public toastController: ToastController
) {
this.getUserData();
this.newUser = {} as newUser;
}
...
check_displayName() {
var usersRef = this.firestore.collection("users");
usersRef.where(doc.forEach(doc => doc, '==', this.state.displayName)).get()
.then(snapshot => {
if (snapshot.empty) {
console.log('displayName is unique', snapshot.empty)
return false
} else {
return true
console.log('displayName already exists')
}
})
}
But I get an issue:
ReferenceError: doc is not defined
How can I iterate through the docs when there are unique document-ids (uid)?
Thx for your hints
Can you try this ??
check_displayName(userNameToCheck) {
const usersRef = this.afStore.collection("users");
usersRef.where('displayName', '==', userNameToCheck).get()
.then(snapshot => {
if (snapshot.empty) {
console.log('displayName is unique', snapshot.empty);
return false;
} else {
console.log('displayName already exists');
return true;
}
});
}
I think you need to get the snapshot first and check if it is empty. There is no meaning in iterating through all docs and increasing your Firestore Reads.
And regarding the forEach(), first you need to get the snapshot and then use something like snapshot.forEach(). But in your case, if the snapshot is empty the username is unique and you did you job with just 1 read cost.
Small Tip: I have not checked if username comparision is case-sensitive. So I keep another field named displayNameLower and then compare that with lower-cased version of username to check.
Something like; .where('displayNameLower', '==', userNameToCheck.toLowerCase())
The solutiion above by Dharmaraj is pretty okay. But I would like to add further to it. We can make use of limit() so that the firebase stops querying once any first matching document from collection is found.If fastens the querying ultimately.
const firebaseAdmin = require('firebase-admin');
firebaseAdmin.initializeApp();
const afStore = firebaseAdmin.firestore();
check_displayName(userNameToCheck) {
const userRef = this.afStore.collection("users");
userRef.where('displayName', '==', userNameToCheck).limit(1).get()
.then(snapshot => {
if (snapshot.empty) {
console.log('displayName is unique', snapshot.empty)
return false
} else {
console.log('displayName already exists')
return true
}
})
.catch(err => {
console.log('Alert:: error in querying the users document');
});;
}

kuzzle / react native - Cannot inherits class from BaseController

I'm trying to extends the KUZZLE JavaScript SDK in order to call some controllers on kuzzle servers, implemented via plugins.
I'm following that guide: add controller
Here is my controller which extends from the BaseController:
const { BaseController } = require('kuzzle-sdk');
export class UserController extends BaseController {
constructor (kuzzle) {
super(kuzzle, 'plugins-user/userController');
}
/**
* Method to call the action "CreateAccount" on the UserController
* #param {*} user
*/
async createAccount(user) {
const apiRequest = {
action: 'new',
body: {
user
}
};
try {
const response = await this.query(apiRequest);
return response.result.user;
}
catch (error) {
//Manage errors
}
}
}
And here is where I specify the controller in order to use it further in the App, on the creation of the singleton.
const {UserController} = require('./UserController');
const { Kuzzle, WebSocket } = require('kuzzle-sdk');
class KuzzleService {
static instance = null;
static async createInstance() {
var object = new KuzzleService();
object.kuzzle = new Kuzzle(
new WebSocket('localhost'),{defaultIndex: 'index'}
);
object.kuzzle.useController(UserController, 'user');
await object.kuzzle.connect();
const credentials = { username: 'admin', password: 'pass' };
const jwt = await object.kuzzle.auth.login('local', credentials);
return object;
}
static async getInstance () {
if (!KuzzleService.instance) {
KuzzleService.instance = await KuzzleService.createInstance();
}
return KuzzleService.instance;
}
}
export default KuzzleService;
Somehow I'm getting the following error:
Controllers must inherit from the base controller
Is there something wrong with the imports ?
I've found out the solution to that issue. Firstly, I was not on the right version of the kuzzle SDK released recently (6.1.1) and secondly the controller class must be exported as default:
const { BaseController } = require('kuzzle-sdk');
export default class UserController extends BaseController {
constructor (kuzzle) {
super(kuzzle, 'plugins-user/userController');
}
/**
* Method to call the action "CreateAccount" on the UserController
* #param {*} user
*/
async createAccount(user) {
const apiRequest = {
action: 'new',
body: {
user
}
};
try {
const response = await this.query(apiRequest);
return response.result.user;
}
catch (error) {
//Manage errors
}
}
}
And then the UserController needs to be importer that way:
import UserController from './UserController.js'
Then, as specified in the documentation, we need just inject the kuzzle object into the controller that way:
kuzzle.useController(UserController, 'user');

Angular - get synchronously from Promise

I want to print history of products. I have an id of product in ActivatedRoute.params. In ngOnInit method I have to get all history of product and assign to variable. Then I want to map product to productHistory, because I want to have last version with history toghether. But the problem is with getting history. Method to getting history return Promise and I cannot get length of productsHistory when I use this property and I get undefined. How can I get this property after loading from service?
I want to execute method after execution getHistory().
My code:
ProductService.ts:
import { Injectable } from '#angular/core';
import { Headers, Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
// rest imports
#Injectable()
export class ProductService {
// URL to web api
private projectsUrl = 'http://localhost:8080/products';
private headers = new Headers({'Content-Type': 'application/json'});
constructor(private http: Http) {}
getHistory(id: number): Promise<ProductHistory[]> {
const url = `${this.projectsUrl}/projectId/${id}`;
return this.http.get(url)
.toPromise()
.then(response => response.json() as ProductHistory[])
.catch(this.handleError);
}
handleError() {
//...
// implementation is irrelevant
}
}
ProductHistoryComponent.ts:
import { Component, Input, OnInit } from '#angular/core';
import { ActivatedRoute, Params } from '#angular/router';
import { Location } from '#angular/common';
import { ProductService } from './product.service';
import { ProductHistory } from './product-history';
import { Product } from './model/product';
import 'rxjs/add/operator/switchMap';
#Component({
selector: 'product-history',
templateUrl: './product-history.component.html',
styleUrls: [ './product-history.component.css' ]
})
export class ProductHistoryComponent implements OnInit {
auditProducts: ProductHistory[] = new Array<ProductHistory[]>();
selectedProduct: ProductHistory;
constructor(
private route: ActivatedRoute,
private location: Location,
private productService: ProductService
) {}
ngOnInit(): void {
let id: number = this.route.snapshot.params['id'];
this.productService.getHistory(id)
.then(history => this.historyProducts = history);
this.productService.getProduct(id)
.then(product => {
let lastVersion: ProductHistory = this.createLastVersion(product);
this.auditProducts.push(lastVersion);
});
}
onSelect(ProductHistory: ProductHistory): void {
this.selectedProduct = ProductHistory;
this.compare(this.selectedProduct);
}
goBack(): void {
this.location.back();
}
compare(history: ProductHistory): void {
let previous: ProductHistory;
if (history.changeNumber != null && history.changeNumber > 1) {
previous = this.historyProducts[history.changeNumber - 2];
if (typeof previous != 'undefined') {
this.setPreviousDiffsFalse(previous);
if (previous.name !== history.name) {
history.nameDiff = true;
}
if (previous.price !== history.price) {
history.priceDiff = true;
}
}
}
}
createLastVersion(product: Product): ProductHistory {
let lastVersionProduct: ProductHistory = new ProductHistory();
lastVersionProduct.id = this.historyProducts.length + 1;
lastVersionProduct.name = product.name;
lastVersionProduct.price = product.price;
lastVersionProduct.changeNumber = this.historyProducts[this.historyProducts.length - 1].changeNumber + 1;
return lastVersionProduct;
}
setPreviousDiffsFalse(previous: ProductHistory): void {
previous.nameDiff = false;
previous.priceDiff = false;
}
}
You can't run it synchronously, you have to wait for each promise to return a result before you can do something with that result. The normal way to do this is to nest code inside then blocks when using promises. Alternatively you can also use async/await with the latest version of typescript and you only have to change your component code as you are already returning the Promise type from your service. This makes code easier to read (IMO) although the emitted javascript code will still use function/callback nesting (unless you are targeting es7 I believe, maybe someone will correct or confirm this).
// note the use of async and await which gives the appearance of synchronous execution
async ngOnInit() {
let id: number = this.route.snapshot.params['id'];
const history = await this.productService.getHistory(id);
this.historyProducts = history;
const product = await this.productService.getProduct(id);
let lastVersion: ProductHistory = this.createLastVersion(product);
this.auditProducts.push(lastVersion);
}
I would suggest using observables instead of promises ... but to answer your question, you just need to perform the second request after the first is received. Something like this:
ngOnInit(): void {
let id: number = this.route.snapshot.params['id'];
this.productService.getHistory(id)
.then(history => {
this.historyProducts = history);
this.productService.getProduct(id)
.then(product => {
let lastVersion: ProductHistory = this.createLastVersion(product);
this.auditProducts.push(lastVersion);
});
}
}
I just moved the second request within the then of the first request. NOTE: I did not syntax check this.

Categories

Resources