I am working on a project which is based on the nest.js framework
The following is a snippet of my function:
#Post('beneficiaries/:beneficiaryId/bankDetails')
#HttpCode(HttpStatus.OK)
async addBankDetails(#Param('beneficiaryId', new ValidationPipe()) beneficiaryHash: BeneficiaryHashIdDto, #Body() body, #Headers() headers) {
const beneficiary = await this.beneficiaryService.getBeneficiaryIdFromHash(beneficiaryHash, ['beneficiaryId', 'currencyCode', 'countryCode']);
let routingOptions = await this.beneficiaryService.getBeneficiaryRoutingConfig(beneficiary.beneficiaryId, pick(headers, GET_HEADERS_LIST));
routingOptions = lmap(routingOptions, partialRight(pick, ['bankDetail', 'beneficiaryRoutingConfigId']));
const [routingConfig] = routingOptions.filter(item => item.beneficiaryRoutingConfigId === body.beneficiaryRoutingConfigId);
if (!routingConfig) {
throw new BadRequestException('Invalid beneficiaryRoutingConfigId');
}
const { error } = this.beneficiaryService.bankDetailsSchema(routingConfig.bankDetail).validate(body, { abortEarly: false });
if (error) {
throw new BadRequestException(error);
}
// write here logic to validate routing codes
await this.beneficiaryService.validateBeneficiaryBankDetails(routingConfig, body, pick(headers, GET_HEADERS_LIST), beneficiary);
// write here logic to insert bank details of bene
return this.beneficiaryService.updateBankDetails(body, headers, beneficiary.beneficiaryId);
}
Nest allows us to extract the params, headers, body, etc of a request.
https://docs.nestjs.com/controllers
I want to extract a particular key from my params
For example my params contain:
1.clientId
2.customerId
3.beneficiaryId
I am able to take out the beneficiaryId and store it in beneficiaryHash but I am not able to perform a validation at the same time.Is there any work around?
You can reach it by custom pipes. as a example like ParseIntPipe
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '#nestjs/common';
#Injectable()
export class ParseIntPipe implements PipeTransform<string, number> {
transform(value: string, metadata: ArgumentMetadata): number {
const val = parseInt(value, 10);
if (isNaN(val)) {
throw new BadRequestException('Validation failed');
}
return val;
}
}
#Get(':id')
async findOne(#Param('id', new ParseIntPipe()) id) {
return this.catsService.findOne(id);
}
for more knowledge please read https://docs.nestjs.com/pipes#transformation-use-case
Related
I am writing an HTTPHandler for lambda execution.
What I want is whenever lambda calls handler, it should go through prechecks and post-checks.
I want to make HTTPHandler dynamic depending on the user's type on body input. It should perform the desired action.
It is difficult to explain, please check the code snippet below and find TODOs for better explanation.
//main lambda handler
export const handler = handleHttpRequest(async (body: Login) => {
const { email, password } = body;
if (!email || !password) throw new Error("Invalid Request. Either email or password is not provided");
// const session = await login(email, password);
// if (!session) throw new UnauthorisedError();
return { json: "session" };
});
//Login.ts
import { IsEmail, IsStrongPassword } from "class-validator";
export class Login {
#IsEmail()
email: string;
#IsStrongPassword()
password: string;
}
//requestHandler.ts
import { validate } from "class-validator";
import { isJson } from "./common";
export const handleHttpRequest = (callback) => {
// TODO: Here I want to take arguments of callback function defined with their Type.
// In above example, we are passing body with type "Login". I want to get that Login as Type.
type BodyType = Parameters<typeof callback>[0]; // Not sure if this is correct.
const actualHandler = async ({ body }) => {
//TODO: As Body type was a class originally. I want to validate the inputs before execution of callback.
// I want to validate based on type user has assigned to body param in line 2.
let error;
//validate user input
if (!isJson(body)) error = new Error("Invalid user input");
body = JSON.parse(body);
if (!error) {
const validationResp = await validate(body);
if (validationResp.length > 0) error = validationResp;
}
let resp = null;
if (!error) resp = await callback(body).catch((e) => e);
else resp = error;
}
}
Please let me know If you need any further clarification on this. I think the solution will be somewhere connected to class-transformer package.
enter code hereI have case i needs 2 connector MongoClient. first client to connect to local mongodb server. 2nd client to connect to remote mongodb. 2 client inside 1 file database-connector.js. is it right or wrong in this ways? what the correct ways in this problem?
class CatchError {
static error: string | unknown;
static save(error: string | unknown) {
this.error = error;
const re = new RegExp('ECONNREFUSED', 'i')
if (re.test(error.message)) {
// fs.write('system.error.log')
}
}
}
class DBClient {
client: MongoClient;
constructor(url: string, config: Partial<MongoClientOptions>) {
this.client = new MongoClient(url, config)
}
async connect() {
try {
this.client = await this.client.connect();
return this.client;
} catch(error) {
CatchError.parse(error)
}
}
}
// for entire data application
export const localDBClient = initializeDBConnection("mongodb://localhost");
// only for authentication to access application
export const remoteDBClient = initializeDBConnection("mongodb+srv://se132.aws-slcuster.com");
gui.js
import { remoteDBClient } from "database-connector.js";
// use client //
model.js
import { localDBClient } from "database-connector.js";
// use client //
I have a separate basic nodejs server on localhost and a separate frontend.
When I try to fetch while the server is offline, fetch() throws failed to fetch* error. So for that, I tried to handle or catch that error by checking the response. ok like
if (!response.ok) throw Error(response.statusText)
Although it catches an error still it throws the error. Even I tried to console logging it.
if (!response.ok) return console.log(response.statusText)
Here are interfaces.
export interface
CommunicatorParameter {
endUrl: string;
}
interface ErrorResponse {
message: string;
}
interface V01List {
tittle: string;
url: string;
}
type V01ListData = Array<V01List>;
type ReleasedVersionsResponse = Array<string>;
type CurrentVersionResponse = string;
interface SuccessResponse{
data: V01ListData | ReleasedVersionsResponse | CurrentVersionResponse ;
}
export type ServerResponse = SuccessResponse | ErrorResponse;
export type CommunicatorResponse = SuccessResponse['data'];
Below is the service function which helps to communicate with the server. Also, I want this function should return direct data(key) value.
interface SuccessResponse{
data: V01ListData | ReleasedVersionsResponse | CurrentVersionResponse ;
}
// fetchDataFromServer.ts
// these are type and interfaces.
import { CommunicatorParameter, ServerResponse, CommunicatorResponse } from "./declarations/index.js";
// These are helper functions
import { buildValidURL, checkForBadResponse } from "./helpers/index.js";
export async function fetchDataFromServer({ endUrl }: CommunicatorParameter): Promise<CommunicatorResponse> {
const fullURL = buildValidURL(endUrl);
const response = await fetch(fullURL, {
method: 'GET'
});
console.log(response.headers)
const jsonParsedData = <ServerResponse>await response.json();
//This function simply checks response and throws an error if the response is not ok.
checkForBadResponse(response, jsonParsedData);
// Here I am doing this because if I return from try/catch or if statement the return type of function does not match and typescript complain about that. I don't think it is a good way to do it. But don't know how to do it.
return ('data' in jsonParsedData) ? jsonParsedData.data : [];
}
I have another function that will help to fetch version data from the server which uses the above communicator fun.
// fetchCurrentVersion.ts
import { fetchDataFromServer } from "../services/fetchDataFromServer.js";
export async function fetchCurrentListVersion() {
const END_URL = "/current_version";
try {
const response = await fetchDataFromServer({ endUrl: END_URL });
// Here I am checking the type of response/data which is returned by communicator as my need, see the interface SuccessResponse data key.
if (typeof response === 'string') {
return response;
}
} catch (error) {
console.log(error.message)
}
// fallback return value;
return "v0.0";
}
Is this approach good? I felt like still there is a better way of doing this. If you could help, please
I have an issue in my Angular web store when i refresh the window, i create a service that takes the user data from the server and then inject to the 'products' section with BehaviorSubject, my goal is to make just one request to the server:
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable({
providedIn: 'root'
})
export class DataService {
private userId = new BehaviorSubject<any>('');
currentUserId = this.userId.asObservable();
constructor() { }
sendUserId(message: string){
this.userId.next(message)
}
}
This works fine but the problem is when i refresh the window in products section, in console i can see that the service takes the user data but when i getProducts() it throws an error, it seems like getProducts() makes the request before the service had the response, i need the user Id to make the products request. My question: Is there a way to await the response of BehaviorSubject and then make the getProducts() request?. This is the code in the products section:
ngOnInit(): void {
this._dataService.currentUserId.subscribe(userId => this.userId = userId);
if(this.userId.length === 0){
this.userService.getUserProfile().subscribe(
res => {
this.userDetails = res['user'];
this.userId = this.userDetails._id;
this.getProducts();
},
err => {
console.log(err);
}
);
} else {
this.getProducts();
}
}
As you can see, i do a condition to check if userId exists, if not i have to make a new user request, this fix the bug but i think there's a better way to solve this. Thanks in advance.
How about placing all your logic within the observer's next function as below:
this._dataService.currentUserId.subscribe(userId => {
if (userId.length === 0)
{
this.userService.getUserProfile().subscribe(
res => {
this.userDetails = res['user'];
this.userId = this.userDetails._id;
this.getProducts();
},
err => {
console.log(err);
}
);
} else
{
this.getProducts();
}
});
I have a method on an service to handle all backend requests. Instead of writing a whole bunch of different calls using the HttpClient, I thought I might write one single function that could connect to my backend and pass it arguments to handle different types of data.
Consider this function
public postRequest(token: string, url: string, body: any, headers: Object = {}) : Observable<any> {
//create new header object
const httpOptions = {
headers: new HttpHeaders()
.set('Authorization', token)
};
//add the headers if any
for(let index in headers){
httpOptions.headers.set(index, headers[index]);
}
//connect to the backend and return the repsonse
return this.http.post( this.config.BASE_SERVER_URL + url, body , httpOptions)
.pipe(
map((res) => {
return res;
}),
catchError(this.handleError)
);
}
It works well except I wanted to be able to set the response type dynamically. Thus I could set the method to use one of my model types.
Here's what I'm trying to accomplish. Hopefully this makes sense.
map(res: "Attendee") => {}
//or
map(res: typeof(typeInput)) => {}
Is it possible to pas a "dynamic" type to the http map method so I can map the different responses to a model of my choice?
I can achieve this by using generic methods.
you can use this approach.
my-own.service.ts
userAuthentication<T>(userName: string, password: string): Observable<T> {
const url = `http://my-own.url`;
const targetData = {
'emailId': userName,
'password': password
};
return this.http.post<CommonResponse<T>>(url, targetData, httpOptions).pipe(
retry(3),
map((data: CommonResponse<T>) => {
if (data.status) {
if (!data.result[0]) {
this.showMessage('You are not authorized for login');
return null;
}
return data.result[0] as T;
}
this.showMessage(data.message);
return null;
}),
tap((userProfile: T) => {
console.log('UserLogin ');
}),
catchError(this.handleError<T>('unable to logged in')));
}
CommonResponse model
export class CommonResponse<T> {
autherizationExpires: string;
autherizationKey: string;
message: string;
result: T | T[];
status: boolean;
}
So, when you call this method like myOwnService.userAuthentication < LoginModel >(...params).subscribe(/ * your codes * /);
It will inherited to the map as well.
let me know if I am not get your question.