enter image description here
I have added the below code in main.ts
import { NestFactory } from '#nestjs/core';
import{SwaggerModule,DocumentBuilder} from '#nestjs/swagger'
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const options = new DocumentBuilder()
.setTitle('My API')
.setDescription('API description')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('api', app, document);
await app.listen(3000);
}
bootstrap();
//controller
#Post()
addProduct(
#Body('title') title:string,
#Body('price') price:number,
):any{
const idFromService=this.productserive.addNewProduct(title,price);
return idFromService;
}
//productservice
export class ProductService {
products:Product[]=[];
addNewProduct(title:string,price:number){
const id=uId();
const newproduct=new Product(id,title,price);
this.products.push(newproduct);
return {title,price};
}
}
// create a separate dto
import { ApiProperty } from '#nestjs/swagger';
export class TestDto {
#ApiProperty()
readonly title: string
#ApiProperty()
readonly price: number
}
// use it in your controller
#Post()
addProduct(#Body() TestDto:TestDto): any {
return;
}
Related
In mine application using inversify for DI conteinerisation
have a abstract class
#injectable()
export abstract class Name {
tableName: string;
constructor(
#inject("DatabaseService") public db: DatabaseService,
#inject("GenesisApiService") public api: GenesisApiService
) {}
abstract fullSync(accountId: number): Promise<void>;
abstract incrementalSync(accountId: number): Promise<void>;
}
also have class which one extends this Abstract class
#injectable()
export class ServiceName extends Name {
tableName = "Name";
constructor(
#inject("ServiceName") db: ServiceName,
#inject("Service2Name") api: Service2Name
) {
super(ServiceName, Service2Name);
}
async fullSync(accountId: number): Promise<void> {
const apiUrl = "/servlet/rs/v1/schedule/fetch/incrementalSync?authToken=";
const result = await this.api.get(apiUrl);
console.log("result", result);
}
async incrementalSync(accountId: number): Promise<void> {
return null;
}
}
after im containerized like in documentations
import "reflect-metadata";
import { Container } from "inversify";
import { ServiceName } from "./services/ServiceName/ServiceName";
export const container = new Container({
autoBindInjectable: true,
skipBaseClassChecks: true,
});
container.bind<ServiceName>("ServiceName").to(ServiceName);
after tryng to invoke service methods
import { container } from "../ioc";
import { GenesisApiService } from "../services/genesis-api";
export const ServiceName = async () => {
try {
console.log("#############1");
const service = container.get<ServiceName>("ServiceName");
await service.get("123321");
} catch (error) {
console.log("error", error);
}
};
ServiceName();
and getting this error
Error: No matching bindings found for serviceIdentifier: String
I'm developing NestJS App which creates a WebSocket to Binance API. I want to get stream output into browser window or postman.
But now I can get stream output only in the console. I can't understand how to send these streams in the browser.
Please help
A class that creates WS stream Coin.ts
import { GetCryptocurrencies } from "./abstract/get-cryptocurrencies";
import { WebSocket } from "ws";
import { Logger } from "#nestjs/common";
import { Observable } from "rxjs";
export class Coin extends GetCryptocurrencies {
private readonly logger = new Logger(Coin.name)
private baseUrl: string
private url: string
constructor(coin: { name: string, symbol: string }[]) {
super(coin)
this.baseUrl = 'wss://stream.binance.com:9443/stream?streams='
this.url = coin.map((c) => {
return `${c.symbol.toLowerCase()}usdt#miniTicker`
}).join('/')
}
getCryptoData(): any {
const stream$ = new Observable((observer) => {
const ws = new WebSocket(`${this.baseUrl}${this.url}`)
ws.on('open', () => {
this.logger.log('Connection established')
})
ws.onmessage = (msg: any) => {
const message = JSON.parse(msg.data)
observer.next(message)
}
})
return stream$
}
}
A service get-data.service.ts
import { Injectable } from '#nestjs/common';
import { map, Observable } from 'rxjs';
import { Coin } from 'src/classes/coin';
import * as coinlist from '../list/coins.json'
#Injectable()
export class GetDataService {
getCoins(): Observable<any[]> {
const coins = new Coin(coinlist)
return coins.getCryptoData().pipe(map((e) => {
console.log(e)
return e
}))
}
}
A controller get-data.controller.ts
import { Controller, Get, Response } from '#nestjs/common';
import { GetDataService } from './get-data.service';
#Controller('getdata')
export class GetDataController {
constructor(private getDataService: GetDataService){}
#Get()
getCoinsData() {
return this.getDataService.getCoins();
}
}
Im just trying to sort this with no luck how to understand this async await promisse
this method will be used to call a dialog material before the update operation. The dialog has a subscribe and this is the reason I`m using this async await here.
this is the code:
async execute(task: ITask): Promise<boolean> {
return new Promise((resolve) => {
this.confirmation
.confirmDelete(`${task.id} - ${task.title}`)
.subscribe(async (confirmed) => {
if (confirmed) {
await this.repository.update(**<Task[]**>(task.id));
this.dialogService
.openConfirmDialog('Are you really want to delete/update/create?')
.afterClosed();
}
resolve(confirmed);
});
});
}
}
How to pass a object there in <Task[]>
I apreciate your help
Thanks
edited:
this is the task.repository.ts
import { environment } from './../../../environments/environment';
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { ITask } from '../models/itask';
#Injectable({
providedIn: 'root',
})
export class TaskRepository {
constructor(private httpClient: HttpClient) {}
create(task: ITask): Promise<ITask> {
return this.httpClient
.post<ITask>(`${environment.api}/tasks`, task)
.toPromise();
}
update(entity: ITask): Promise<ITask> {
const { id, ...data } = entity;
return this.httpClient
.put<ITask>(`${environment.api}/tasks/${id}`, data)
.toPromise();
}
getById(id: string): Promise<ITask> {
return this.httpClient
.get<ITask>(`${environment.api}/tasks/${id}`)
.toPromise();
}
getAll(): Promise<ITask[]> {
return this.httpClient
.get<ITask[]>(`${environment.api}/tasks/`)
.toPromise();
}
async delete(id: string): Promise<void> {
await this.httpClient.delete(`${environment.api}/tasks/${id}`).toPromise();
return;
}
}
Updated 2
using task as a parameter, solve the problem, but here at my .ts component start to complaim
import { ITask } from './../../models/itask';
import { GetTaskHandler } from './../../business-rules/get-task.handler';
import { UpdateTaskHandler } from './../../business-rules/update-task.handler';
import { CreateTaskHandler } from './../../business-rules/create-task.handler';
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormControl } from '#angular/forms';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-task-form-page',
templateUrl: './task-form-page.component.html',
styleUrls: ['./task-form-page.component.scss'],
})
export class TaskFormPageComponent implements OnInit {
pageTitle = 'Nova tarefa';
// configuração do formulário
form = this.formBuild.group({
title: [''],
description: [''],
done: [false],
});
get title(): FormControl {
return this.form.get('title') as FormControl;
}
get description(): FormControl {
return this.form.get('description') as FormControl;
}
get done(): FormControl {
return this.form.get('done') as FormControl;
}
taskId: string | undefined = undefined;
constructor(
private formBuild: FormBuilder,
private activatedRouter: ActivatedRoute,
private createTaskHandler: CreateTaskHandler,
private updateTaskHandler: UpdateTaskHandler,
private getTaskHandler: GetTaskHandler,
) {}
async ngOnInit(): Promise<void> {
const paramId = this.activatedRouter.snapshot.paramMap.get('id');
if (paramId) {
this.taskId = paramId;
await this.loadTask();
}
}
async loadTask(): Promise<void> {
const response = await this.getTaskHandler.execute(this.taskId || '');
if (response) {
this.pageTitle = 'Editando tarefa';
// atualizando o formulário com os valores retornados pela api
this.form.patchValue({
title: response.title,
description: response.description,
done: response.done,
});
}
}
async onSubmit(): Promise<void> {
const taskToSave: ITask = {
...this.form.value, // pegando todos os valores do formulário
id: this.taskId, // atualizando o id caso exista
};
let response: ITask | undefined;
if (taskToSave.id) {
***response*** = await this.updateTaskHandler.execute(taskToSave);
} else {
response = await this.createTaskHandler.execute(taskToSave);
}
if (response) {
this.taskId = response.id;
}
}
}
I think you made an error, update expects ITask object, so await this.repository.update(**<Task[]**>(task.id)); should be await this.repository.update(task); also I don't think it's a good idea to use a subscription inside a promise. so can you try something like this
async execute(task: ITask): Promise<boolean> {
// Convert to promise
const confirmed = await this.confirmation
.confirmDelete(`${task.id} - ${task.title}`).pipe(first()).toPromise();
if (confirmed) {
await this.repository.update(task);
this.dialogService.openConfirmDialog('Are you really want to delete/update/create?')
.afterClosed();
}
return new Promise((resolve) => {
resolve(confirmed);
});
});
}
}
You should use await this.repository.update(task);.
I have a NestJS Controller:
search.controller.ts
import { Body, Controller, Post, Req, UseFilters } from '#nestjs/common';
import { HttpExceptionFilter } from '../exception/http-exception.filter';
import { SearchData } from './models/search-data.model';
import { SearchResults } from 'interfaces';
import { SearchService } from './search.service';
#Controller('')
#UseFilters(HttpExceptionFilter)
export class SearchController {
constructor(private searchService: SearchService) {}
#Post('api/search')
async searchDataById(
#Body() searchData: SearchData,
#Req() req
): Promise<SearchResults> {
return await this.searchService.getSearchResultsById(
searchData,
token
);
}
}
This search controller uses Filters named HttpExceptionFilter.
This Filter gets triggered whenever there is an HttpException thrown. I have created ServiceException which extends HttpException. I throw new ServiceException() whenever there is an error.
HttpExceptionFilter
import {
ArgumentsHost,
Catch,
ExceptionFilter,
HttpException
} from '#nestjs/common';
import { ErrorDetails } from './error-details.interface';
import { HTTP_ERRORS } from './errors.constant';
#Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const status = exception.getStatus();
const api = exception.getResponse() as string;
const errorDetails = this.getErrorDetails(api, status);
response.status(status).json({
status: status,
title: errorDetails.title,
message: errorDetails.message
});
}
private getErrorDetails(api: string, status: string | number): ErrorDetails {
const errorDetails: ErrorDetails = {
title: HTTP_ERRORS.GENERAL.ERROR.title,
message: HTTP_ERRORS.GENERAL.ERROR.message
};
// if rejection status is logged out or toke expired then redirect to login
if (
HTTP_ERRORS.hasOwnProperty(api) &&
HTTP_ERRORS[api].hasOwnProperty(status)
) {
errorDetails.title = HTTP_ERRORS[api][status].title;
errorDetails.message = HTTP_ERRORS[api][status].message;
}
return errorDetails;
}
}
ServiceException
import { HttpException } from '#nestjs/common';
export class ServiceException extends HttpException {
constructor(private details, private code) {
super(details, code);
}
}
search.service.ts
import { APIS } from '../app.constants';
import { HttpService, HttpStatus, Injectable } from '#nestjs/common';
import { SearchData, SearchResultSchema } from './models/search-data.model';
import { AppConfigService } from '../app-config/app-config.service';
import { AxiosResponse } from 'axios';
import { DataMappingPayload } from './models/data-mapping-payload.model';
import { SEARCH_SCHEMAS } from './search.constants';
import { SearchModelMapper } from './search-model-mapper.service';
import { SearchResults } from '#delfi-data-management/interfaces';
import { ServiceException } from '../exception/service.exception';
#Injectable()
export class SearchService {
constructor(
private searchModelMapper: SearchModelMapper,
private configService: AppConfigService,
private readonly httpService: HttpService
) {}
// eslint-disable-next-line max-lines-per-function
async getSearchResultsById(
searchData: SearchData,
stoken: string
): Promise<SearchResults> {
if (searchData.filters.collectionId && searchData.viewType) {
if (
Object.values(SEARCH_SCHEMAS).indexOf(
searchData.viewType as SEARCH_SCHEMAS
) !== -1
) {
try {
...... some code cant paste here
return this.searchModelMapper.generateSearchResults(
kinds,
mappingPayload,
searchResultsAPI.data.results
);
} catch (error) {
throw new ServiceException(
APIS.SEARCH,
HttpStatus.INTERNAL_SERVER_ERROR
);
}
} else {
throw new ServiceException(APIS.SEARCH, HttpStatus.BAD_REQUEST);
}
} else if (!searchData.filters.collectionId) {
throw new ServiceException(APIS.SEARCH, HttpStatus.BAD_REQUEST);
} else {
throw new ServiceException(APIS.SEARCH, HttpStatus.BAD_REQUEST);
}
}
Now the thing never reaches to HttpExceptionFilter file in the unit tests
search.service.spec.ts
beforeEach(async () => {
const app = await Test.createTestingModule({
imports: [AppConfigModule, HttpModule, SearchModule]
}).compile();
searchService = app.get<SearchService>(SearchService);
});
it('should throw error message if viewType not provided', () => {
const searchDataquery = {
filters: {
collectionId: 'accd'
},
viewType: ''
};
const result = searchService.getSearchResultsById(searchDataquery, 'abc');
result.catch((error) => {
expect(error.response).toEqual(
generateSearchResultsErrorResponse.viewTypeError
);
});
});
Is there a reason why throw new ServiceException, which internally triggers HttpException does not trigger HttpExceptionFilter?
Filters are not bound during unit tests because they require the request context for Nest to bind properly (it's how Nest handles the lifecycle of the request). As unit tests do not have an incoming HTTP request, the lifecycle is only seen as what you are calling explicitly, in this case: SearchSerivce. If you are looking to test a filter, you should set up and e2e type test where you use supertest to send in HTTP requests and allow your filter to catch during the request.
I needed something similar in a different context. In my case I needed a test for a custom filter for graphql. This filter is catching HttpException thrown inside resolvers.
Here was a sample of my test
import { HttpException, HttpStatus, Logger } from '#nestjs/common'
import {
ApolloError,
AuthenticationError,
ForbiddenError,
} from 'apollo-server-errors';
import {ApolloExceptionFilter} from './apollo-exeption.filter'
import { ExecutionContextHost } from '#nestjs/core/helpers/execution-context-host'
describe('ApolloExceptionFilter', () => {
const filter = new ApolloExceptionFilter(new Logger());
const host = new ExecutionContextHost([], null, null);
host.setType('graphql');
it('should throw apollo AuthenticationError', () => {
const t = () => {
filter.catch(new HttpException({}, HttpStatus.UNAUTHORIZED), host);
};
expect(t).toThrow(AuthenticationError);
})
})
You can above that
I am instantiating the filter
I am calling the catch method directly
I've been stuck here since yesterday.
I have an API that retrieves data from mongodb (mlab.com)
var helpers = require('../config/helper.js');
var UserModel = require('../model/UserModel.js');
module.exports = function (server){
server.get("/", function (req, res, next) {
UserModel.find({}, function (err, users) {
helpers.success(res, next, users);
});
});
}
This is the UserModel.js
const mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var UserSchema = new Schema({
id: ObjectId,
fname: String,
lname: String,
email_add: String,
champ_type: String
});
var UserModel = mongoose.model('users', UserSchema);
module.exports = UserModel;
My app.js
//packages
const restify = require('restify');
const mongoose = require('mongoose');
const restifyValidator = require('restify-validator');
const corsMiddleWare = require('restify-cors-middleware');
//local
var setupController = require('./controller/setupController.js');
var userController = require('./controller/userController.js');
var config = require('./config/dbConfig.js');
//init packages
const server = restify.createServer();
mongoose.connect(config.getMongoConnection());
setupController(server, restify, restifyValidator, corsMiddleWare);
userController(server);
server.listen(8080, function () {
console.log('%s listening at %s', server.name, server.url);
});
ALL OF THE ABOVE IS WORKING WHEN I TRIED IT ON POSTMAN
SCREENSHOT OF THE POSTMAN
NOW LET'S GO TO MY ANGULAR 5 PROJECT
First, I generate a component(retrieve.component) using the CLI.
Second, I created a service[logging.service.ts], code:
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { Injectable } from '#angular/core';// If you need external data
import { Http, Response, Headers, RequestOptions, URLSearchParams } from '#angular/http';// If you need to call some API from the cloud
import { Request } from "#angular/http";
// Import RxJs required methods
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { LogModel } from '../model/log.model';
#Injectable()
export class LoggingService {
private ROOT_URL = "http://localhost:8080/";
constructor(private http: Http) {}
//getPosts() {
//let params = new HttpParams().set('userId', '1');
//this.posts = this.http.get(this.ROOT_URL /*, { params }*/);
//}
addComments(): Observable<LogModel[]> {
let headers = new Headers({ "Content-Type": "application/json" }); // ... Set content type to JSON
let options = new RequestOptions({ headers: headers }); // Create a request option
return this.http
.get(this.ROOT_URL, options)
.map((response: Response) => response.json())
.catch((error: any) =>Observable.throw(error.json().error || "Server error"));
}
test() {
//console.log("Hello!");
const subject = new Subject();
subject.subscribe({
next: function(value) {
console.log(value);
}
});
subject.next("Hello!");
subject.next("Free!");
}
}
Third, I created a model (log.model.ts), code:
export interface LogModel {
lname: String;
fname: String;
email_add: String;
champ_type: String;
}
Fourth, I configured my component (retrieve.component.ts), code:
import { Component, OnInit } from '#angular/core';
import { Observable } from "rxjs/Observable";
import { LoggingService } from "../service/logging.service";
import { LogModel } from "../model/log.model";
#Component({
selector: "app-retrieve",
templateUrl: "./retrieve.component.html",
styleUrls: ["./retrieve.component.css"]
})
export class RetrieveComponent implements OnInit {
//posts: Observable<any>;
private results: LogModel[];
private model: any;
constructor(private _loggingservice: LoggingService) {}
getAllusers() {
this.model = this._loggingservice.addComments().subscribe(data => {
this.results = data;
//this.results = Array.of(this.results);
}
err => console.error(err),
() => console.log('getBooks completed')
);
console.log(this.model);
}
ngOnInit() {
this._loggingservice.test();
}
}
Fifth, configured my retrieve.component.html, code:
<p>
retrieve works!
</p>
<button (click)="getAllusers()">Get Posts</button>
<div *ngFor="let item of results?.data">
<p>Output: {{ item }}</p>
</div>
Sixth, configured my app.module.ts, code:
// This typescript file is called a module. It is a group of components bundled together.
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import {
NgForm,
FormBuilder,
FormGroup,
Validators,
FormArray,
FormControl,
FormsModule
} from "#angular/forms"; // for you to enable ngModel in HTMLs
//import { HttpClientModule } from '#angular/common/http';
import { HttpModule } from "#angular/http";
import { AppComponent } from './app.component';
// Before you can use a component, you'll need to declare it here
import { ServerComponent } from './server/server.component';
import { ServersComponent } from './servers/servers.component';
import { ProfileComponent } from './iprofile/profile.component';
import { ProfileService } from './iprofile/profile.service';
import { LoggingService } from './service/logging.service';
import { RetrieveComponent } from './retrieve/retrieve.component';
#NgModule({
declarations: [
AppComponent,
// Then here.
ServerComponent,
ServersComponent,
ProfileComponent,
RetrieveComponent
],
imports: [
BrowserModule,
FormsModule, // for you to enable ngModel in HTMLs
HttpModule
],
providers: [ProfileService, LoggingService],
bootstrap: [AppComponent]
})
export class AppModule {}
Lastly, I implement it on the main html (app.component.html), code:
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{ name }}!
</h1>
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<input type="text" [(ngModel)]="name">
<h3>Facker</h3>
<hr>
<app-servers></app-servers>
<app-profile></app-profile>
<app-retrieve></app-retrieve>
<!--
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>
</ul> -->
Here's the screenshot of the output PS. When I press "get Posts" button it shows "[Object object]"
So, thank you for reading all the stuff. I just want to know what goes wrong? I just want to display to my Angular 5 project what the postman displayed. I'm trying to google simple tutorials but it doesn't work. By the way, restify and corsmiddleware are my default packages, what I mean is you can suggest but I think that won't solve the problem.
So, you have got this piece of code:
getAllusers() {
this.model = this._loggingservice.addComments().subscribe(data => {
this.results = data;
//this.results = Array.of(this.results);
data here is represented as a json, but you want it to be an object. Try to JSON.parse() your data like this:
getAllusers() {
this.model = this._loggingservice.addComments().subscribe(data => {
this.results = JSON.parse(data);
If this isn't working, try to JSON.stringify() your response instead of response.json here:
return this.http
.get(this.ROOT_URL, options)
.map((response: Response) => response.json())
Here I give working example of getting response from API and parsing it into custom object:
public loadPage() {
this.http
.get(environment.API_URL + "search/" + this.query + "/" + pageToLoad.toString())
.map((data) => JSON.stringify(data))
.subscribe((data) => {
const page: Product[] = JSON.parse(data);
this.showedProducts = this.showedProducts.concat(page);
});
}