Angular2 - Handling API Response - node.js

Good afternoon! I'm new in Angular 2, so I'm sorry in advance if my question is generic. I cannot figure out how to handle an API response.
My NodeJS Server API function is (Checked and works fine):
router.get('/appointment/:iatreio/:time', function(req, res, next) {
var paramIatreio = req.params.iatreio;
var paramTime = req.params.time;
db.appointments.findOne({iatreio: paramIatreio, time: req.params.time}, function(err, resultFound) {
if (err) { res.send(err); }
if (resultFound) {
res.json(true); // 1st Question: For best practice, res.json(true) or res.send(true)?
} else {
res.json(false);
}
});
});
My Angular2 Service:
import { Injectable } from '#angular/core';
import { Headers , Http } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class AppointmentService {
constructor(private http: Http) { }
isBooked(iatreio: string, time: string): Observable<boolean> {
return this.http
.get('http://localhost:3000/appointment/'+iatreio+'/'+time)
.map(); //2nd Question: What inside map()?
}
} // end of Service
Component Function
isBooked(selectedIatreio: string, selectedTime: string): boolean {
this.appointmentService
.isBooked(selectedIatreio, selectedTime)
.subscribe(() => {}); //3rd Question: What inside subscribe()?
}
My final goal is the "isBooked(...)" function of my Component to be called and to return true or false. I have seen the code in the examples in the Angular2 site, but I'm a little confused on my case.
Can Service function return directly a true or false value or it has to be an Observable?? Map() function is necessary??
Generally, my thinking is right?? Or my goal can be accomplished more easily??
Thank you a lot for your time!!

map is used to convert the response into the model which you look for
isBooked(iatreio: string, time: string): Observable<boolean> {
return this.http
.get('http://localhost:3000/appointment/'+iatreio+'/'+time)
.map((response)=><boolean>response.json());
}
subscribe will return the data emitted by the service
isBooked(selectedIatreio: string, selectedTime: string): boolean {
this.appointmentService
.isBooked(selectedIatreio, selectedTime)
.subscribe((data) => {
//your operation
console.log(data);
});
}

Related

Postman hangs when sending "POST" request to API

So i'm using Postman and i need to send a POST method request to my api but every time i do it hangs even if the handler does nothing except return a simple value. I'm using hapi so the syntax might differ a little bit from the standard express app.
currency.ts
//this is where i define the route methods and paths
import * as Hapi from "hapi";
import IRouteArea from "../server/IRouteArea";
import CurrencyController from "../controller/CurrencyController";
import hapiAuthJwt2 = require("hapi-auth-jwt2");
import { join } from "lodash";
import { RESOLVER } from "awilix";
const CurrencyArea = ({ currencyController }: any): IRouteArea => {
let _controller = currencyController as CurrencyController;
return {
registerRoutes(server: Hapi.Server) {
server.bind(_controller);
server.route({
method: "GET",
path: "/api/currencies",
options: {
auth: {
mode: "try"
},
plugins: { "hapi-auth-cookie": { redirectTo: false } },
handler: _controller.getCurrencies
}
});
server.route({
method: "POST", // this one is causing me problems
path: "/api/currencies/{id}",
options: {
auth: {
mode: "try"
},
plugins: { "hapi-auth-cookie": { redirectTo: false }},
handler: _controller.editCurrency
}
});
}
};
};
export default CurrencyArea;
and even though the actual handler of the request isn't doing anything special...
CurrencyController.ts
//here i define the handlers of requests sent to routes in the previous file
import * as Hapi from "hapi";
import { name } from "mustache";
import GetCurrencyListInteractor from "../../interactor/currencies/GetCurrencyListInteractor";
import Task from "../../runtime/Task";
export default class CurrencyController {
private task: Task;
constructor({ task }: any) {
this.task = task;
}
public async getCurrencies(
request: Hapi.Request,
h: Hapi.ResponseToolkit
): Promise<any> {
try {
return this.task.start<GetCurrencyListInteractor>(
"getCurrencyList",
t => t.execute()
);
} catch (error) {
return error as any;
}
}
public async editCurrency( //it's supposed to just return the parameter sent in the url
request: Hapi.Request,
h: Hapi.ResponseToolkit
): Promise<any> {
try {
return request.params.id;
} catch (error) {
return error as any;
}
}
}
it always hangs and gets stuck on the "sending request" screen when i send the request. One interesting thing is that the exact same route works as intended but only if the method defined in currency.ts is "GET". If i leave everything else the way it is and change the method from "GET" to "POST" or "PUT" or "PATCH" it stops working.
this goes on forever

NestJs #Sse - event is consumed only by one client

I tried the sample SSE application provided with nest.js (28-SSE), and modified the sse endpoint to send a counter:
#Sse('sse')
sse(): Observable<MessageEvent> {
return interval(5000).pipe(
map((_) => ({ data: { hello: `world - ${this.c++}` }} as MessageEvent)),
);
}
I expect that each client that is listening to this SSE will receive the message, but when opening multiple browser tabs I can see that each message is consumed only by one browser, so if I have three browsers open I get the following:
How can I get the expected behavior?
To achieve the behavior you're expecting you need to create a separate stream for each connection and push the data stream as you wish.
One possible minimalistic solution is below
import { Controller, Get, MessageEvent, OnModuleDestroy, OnModuleInit, Res, Sse } from '#nestjs/common';
import { readFileSync } from 'fs';
import { join } from 'path';
import { Observable, ReplaySubject } from 'rxjs';
import { map } from 'rxjs/operators';
import { Response } from 'express';
#Controller()
export class AppController implements OnModuleInit, OnModuleDestroy {
private stream: {
id: string;
subject: ReplaySubject<unknown>;
observer: Observable<unknown>;
}[] = [];
private timer: NodeJS.Timeout;
private id = 0;
public onModuleInit(): void {
this.timer = setInterval(() => {
this.id += 1;
this.stream.forEach(({ subject }) => subject.next(this.id));
}, 1000);
}
public onModuleDestroy(): void {
clearInterval(this.timer);
}
#Get()
public index(): string {
return readFileSync(join(__dirname, 'index.html'), 'utf-8').toString();
}
#Sse('sse')
public sse(#Res() response: Response): Observable<MessageEvent> {
const id = AppController.genStreamId();
// Clean up the stream when the client disconnects
response.on('close', () => this.removeStream(id));
// Create a new stream
const subject = new ReplaySubject();
const observer = subject.asObservable();
this.addStream(subject, observer, id);
return observer.pipe(map((data) => ({
id: `my-stream-id:${id}`,
data: `Hello world ${data}`,
event: 'my-event-name',
}) as MessageEvent));
}
private addStream(subject: ReplaySubject<unknown>, observer: Observable<unknown>, id: string): void {
this.stream.push({
id,
subject,
observer,
});
}
private removeStream(id: string): void {
this.stream = this.stream.filter(stream => stream.id !== id);
}
private static genStreamId(): string {
return Math.random().toString(36).substring(2, 15);
}
}
You can make a separate service for it and make it cleaner and push stream data from different places but as an example showcase this would result as shown in the screenshot below
This behaviour is correct. Each SSE connection is a dedicated socket and handled by a dedicated server process. So each client can receive different data.
It is not a broadcast-same-thing-to-many technology.
How can I get the expected behavior?
Have a central record (e.g. in an SQL DB) of the desired value you want to send out to all the connected clients.
Then have each of the SSE server processes watch or poll that central record
and send out an event each time it changes.
you just have to generate a new observable for each sse connection of the same subject
private events: Subject<MessageEvent> = new Subject();
constuctor(){
timer(0, 1000).pipe(takeUntil(this.destroy)).subscribe(async (index: any)=>{
let event: MessageEvent = {
id: index,
type: 'test',
retry: 30000,
data: {index: index}
} as MessageEvent;
this.events.next(event);
});
}
#Sse('sse')
public sse(): Observable<MessageEvent> {
return this.events.asObservable();
}
Note: I'm skipping the rest of the controller code.
Regards,

Assign route dynamically Node/Express

I need dynamically assign a new route but it for some reason refuses to work.
When I send a request in the Postman it just keeps waiting for a response
The whole picture of what I am doing is the following:
I've got a controller with a decorator on one of its methods
#Controller()
export class Test {
#RESTful({
endpoint: '/product/test',
method: 'post',
})
async testMe() {
return {
type: 'hi'
}
}
}
export function RESTful({ endpoint, method, version }: { endpoint: string, version?: string, method: HTTPMethodTypes }) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor): void {
const originalMethod = descriptor.value
Reflect.defineMetadata(propertyKey, {
endpoint,
method,
propertyKey,
version
}, target)
return originalMethod
}
}
export function Controller() {
return function (constructor: any) {
const methods = Object.getOwnPropertyNames(constructor.prototype)
Container.set(constructor)
for (let action of methods) {
const route: RESTfulRoute = Reflect.getMetadata(action, constructor.prototype)
if (route) {
const version: string = route.version ? `/${route.version}` : '/v1'
Container.get(Express).injectRoute((instance: Application) => {
instance[route.method](`/api${version}${route.endpoint}`, async () => {
return await Reflect.getOwnPropertyDescriptor(constructor, route.propertyKey)
// return await constructor.prototype[route.propertyKey](req, res)
})
})
}
}
}
}
Is it possible to dynamically set the route in the way?
I mainly use GraphQL but sometimes I need RESTful API too. So, I want to solve this by that decorator
In order for the response to finish, there must be a res.end() or res.json(...) or similar. But I cannot see that anywhere in your code.

I am not getting response from nodeJS server in angular 2 [duplicate]

This question already has answers here:
How do I return the response from an Observable/http/async call in angular?
(10 answers)
Closed 5 years ago.
I am newbie to MEAN stack development. So, please help me to figure out the problem.
app.js
const express = require('express');
const app = express();
const path = require('path');
app.use(express.static(path.join(__dirname, './darwin-src/public')));
const port = 3000;
app.get('/images', (req, res) => {
console.log('In server');
var data;
var Scraper = require ('images-scraper')
, google = new Scraper.Google();
google.list({
keyword: 'banana',
num: 10,
detail: true,
nightmare: {
show: false
}
})
.then(function (data) {
console.log('first 10 results from google', data);
res.end("" + data);
})
.catch(function(err) {
console.log('err', err);
});
});
app.listen(port, () => {
console.log(`Starting the server at port ${port}`);
});
image-service.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { Image } from './model/image';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import 'rxjs/add/observable/of';
#Injectable()
export class ImageServiceService {
constructor(private http: Http) { }
private serverApi = 'http://localhost:3000';
public getImages(image: string): Observable<Image[]> {
console.log('Inside Service');
let URI = `${this.serverApi}/images`;
return this.http.get(URI)
.map(function(res) {
return res.json();
});
}
}
image-view.component.ts
import { Component, OnInit } from '#angular/core';
import { ImageServiceService } from '../image-service.service';
import { Image } from '../model/image';
#Component({
selector: 'app-image-view',
templateUrl: './image-view.component.html',
styleUrls: ['./image-view.component.css']
})
export class ImageViewComponent implements OnInit {
private data: Image[] = [];
constructor(private imageService: ImageServiceService) { }
ngOnInit() {
}
onSubmit(image: string) {
console.log(image);
this.imageService.getImages(image).subscribe(response => this.data = response);
console.log(this.data.length);
}
}
The length of array is zero and I can't figure out why. The response comes on nodejs console after a while but the frontend displays the result before the response comes. Please help!
Hit the server url separately in browser and see if you get the expected response. If this is okay, then the problem is with the client.
On seeing your client code, one issue seems obvious. You are not using the observable from ImageServiceService properly. All your manipulations should be within the subscribe method.
onSubmit(image: string) {
this.imageService.getImages(image).subscribe(response => {
this.data = response;
console.log(this.data.length);
// Do other manipulations that you wish to do
});
}
If you using the observable to display something in the view, then
consider . using async pipe
The code in the subscribe handler is not executed synchronously. So, your console.log statement is executed before you get a response from your server. I don't see your image-view.component.html markup. But, I believe you need to use the async pipe in your bound option.
private data$: Observable<Image[]>;
onSubmit(image: string) {
console.log(image);
this.data$ = this.imageService.getImages(image);
}
And you HTML:
<div *ngFor="let image of data$ | async">
{{image.value}}
</div>

Storing observable data into global variable returns 'undefined' in Angular 4

I am currently working with a node server that I've set up and created an endpoint /user-info which res.send({id: <my-id>, name: <my-display-name>})
On Angular I have created a global.service.ts file that will call this endpoint using http.get and subscribe that data and store into two variables I have declared.
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class Globals {
constructor(private http: HttpClient) { }
public id: string;
public name: string;
userInfo() {
this.http.get('/user-info').subscribe(
(data: any) => {
this.id = data.id;
}
);
console.log(this.id);
}
}
Once I console.log(this.id) it returns undefined. I have already the server-side to see if that was causing the problem but it returns a string.
In my server.js file (node server) I am working with express. This is the endpoint:
app.get('/user-info', function(req, res) {
client.get('id', (err, data) => {
client.get('name', (err, reply) => {
res.send({id: data, name: reply})
})
})
})
I am using redis to store values 'id' and 'name' and the client.get is just a redis command used to call those values from cache. I have tested just checking localhost:8000/user-info and everything looks fine.
Am I missing/misunderstanding something? Thanks!
if console.log still outside of call, it will execute before you got a response. Try this:
userInfo() {
this.http.get('/user-info').subscribe(
(data: any) => {
this.id = data.id
console.log(this.id);
}
)
}

Resources