Cannot get data from an Node API - node.js

I have an API (Localhost:3000) using node and a front end (Localhost:4200) using Angular 6. Using my regular chrome browser, I am able to CRUD to the database in the API but when I use the android emulator using (10.0.2.2:4200), I cannot do any of the CRUD to the database anymore. Please see my codes below:
Node [index.js]
const express = require("express");
const nedb = require("nedb");
const rest = require("express-nedb-rest");
const cors = require("cors");
const app = express();
const datastore = new nedb({
filename: "mycoffeeapp.db",
autoload: true
});
const restAPI = rest();
restAPI.addDatastore('coffees', datastore);
app.use(cors());
app.use('/', restAPI);
app.listen(3000);
angular front end
This is in the data.service
import { Injectable } from "#angular/core";
import { HttpClient } from "#angular/common/http";
#Injectable({
providedIn: "root"
})
export class DataService {
public endpoint = "http://localhost:3000";
constructor(
private http: HttpClient
) {}
getList(callback) {
this.http.get(`${this.endpoint}/coffees`)
.subscribe(response => {
callback(response);
});
}
get(coffeeId: string, callback) {
this.http.get(`${this.endpoint}/coffees/${coffeeId}`)
.subscribe(response => {
callback(response);
});
}
save(coffee, callback) {
if (coffee._id) {
this.http.put(`${this.endpoint}/coffees/${coffee._id}`, coffee)
.subscribe(response => {
callback(true);
});
} else {
this.http.post(`${this.endpoint}/coffees`, coffee)
.subscribe(response => {
callback(true);
});
}
}
}
in the component:
constructor(
private data: DataService,
private router: Router,
private gls: GeoLocationService
) { }
ngOnInit() {
this.data.getList(list => {
this.list = list;
});
}

If you run an emulated android device and try to access your development environment environment on 10.0.2.2:4200, you'll be able to reach the angular app provided that th emulator is on the same network.
Now, you need to make sure that your API is reachable from outside of your local machine, and, in your angular front, set the API url using an IP address
export class DataService {
public endpoint = "http://10.0.2.2:3000";
If you use localhost, this will point to the emulated device itself, which does not have you API runnnig

Related

angular-nestjs socket.io doesn't update if page doesn't refresh

I am using Angular and NestJS with socket.io to create a chat application.
When I started saving data on my db, my Angular side stopped updating messages unless page refreshes.
I couldn't find a way to pass the userid on the server gateway in order to search in the db only chat of the user.
Angular service
sendMessage(chat: Chat): void {
this.socket.emit('sendMessage', chat)
} //using it when a message is sent
getNewMessage(): Observable<Chat[]> {
return this.socket.fromEvent<any>('lastChats');
} //using it onInit
sendId(userId: number): void {
this.socket.emit('loadMessages', userId);
} //using it onInit
NestJS Gateway
#WebSocketGateway({ cors: { origin: ['http://localhost:4200'] } })
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
constructor(
#InjectRepository(Chat) private chatRepository: Repository<Chat>,
) { }
#WebSocketServer()
server: Server
async handleConnection(client: any, ...args: any[]) {
const chats = await this.chatRepository.createQueryBuilder('chat')
.innerJoinAndSelect('chat.ally', 'ally')
.innerJoinAndSelect('chat.talent', 'talent')
.getMany();
this.server.emit('lastChats', chats)
}
handleDisconnect(client: any, ...args: any[]) {
console.log("Disconnected")
}
#SubscribeMessage('sendMessage')
handleMessage(socket: Socket, chat: Chat) {
if (chat.messagesJSON && chat.messagesJSON.trim() !== '') {
this.chatRepository.save(chat)
this.server.emit('newChat', chat)
}
#SubscribeMessage('loadMessages')
async handleLoad(socket: Socket, id: number) {
const chats = await this.chatRepository.createQueryBuilder('chat')
.innerJoinAndSelect('chat.ally', 'ally')
.innerJoinAndSelect('chat.talent', 'talent')
.where('ally = :user OR talent = :user', { user: id })
.getMany();
this.server.emit('lastChats', chats)
}
}
To send from angular to nestjs you can use
Angular:
this.socket = io(environment.SOCKET_URL, {
extraHeaders: {Authorization: localStorage.getItem('token')},
});
Nestjs: in the handleConnexion
Const jwt =socket.handshake.headers.authorization
I think you can replace the token by usrerId

Using socket.io with React and Google App Engine

I've created a Node(express)/React app that uses socket.io and Redux's store as follows:
import io from "socket.io-client";
import * as types from "../actions/types";
import { cancelReview, startReview } from "./actions";
const socket = io("http://localhost:8080", {
transports: ["websocket"]
});
export const init = store => {
socket.on("connect", () => {
console.log("websocket connection successful...");
socket.on("cancelReview", (id, name) => {
cancelReview(store, id, name);
});
socket.on("startReview", (id, name) => {
startReview(store, id, name);
});
});
};
This function is then called from store.js as follows:
import { createStore, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension/developmentOnly";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
import { init } from "./socket/socket";
// Initial state
const initialState = {};
// Middleware
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
init(store);
export default store;
Everything works fine on my local machine, but I'm now realizing after doing some research that this will not work on Google's app engine because instead of http://localhost:8080 I need to get the actual IP address from Google's metadata server and pass in EXTERNAL_IP + ":65080". So I'm able to get the external IP in my express app as follows:
const METADATA_NETWORK_INTERFACE_URL =
"http://metadata/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip";
function getExternalIp(cb) {
const request = axios.create({
baseURL: METADATA_NETWORK_INTERFACE_URL,
headers: { "Metadata-Flavor": "Google" }
});
request
.get("/", (req, res) => {
return cb(res.data);
})
.catch(err => {
console.log("Error while talking to metadata server, assuming localhost");
return cb("localhost");
});
}
However, if I pass this value into my render function as seen below, React creates a prop to pass into components (as far as I understand from the info I could find):
app.get("*", (req, res) => {
getExternalIp(extIp => {
res.render(path.resolve(__dirname, "client", "build", "index.html"), {
externalIp: extIp
});
});
I am not able to access this value via the window global. So my question is, how do I access this external IP from my store initialization, since it is not an actual React component?
Thanks in advance.

Using Service in Express Router

I am pretty new in the NodeJS but I would like to learn something new. I came from .NET fancy dependency injection, inversion of controll, microservice shiny world so I am trying write some service in TypeScript based on my previous experiences.
I am using express and express router to create some api. I have some methods in router which handles api calls and I want to use some kind of service object for data retrieving and manipulation.
I inject the service into the router using constructor injection but if I want to use my service it throws an error:
TypeError: Cannot read property 'layoutService' of undefined
I understood that the methods were called withouth context so I added .bind(this) to the each method regsitration and it works, but I dont know if it is the best way how to do it.
Does anyone have a better idea?
simplified server.ts
import express, { Router } from "express";
// inversion of controll
import container from "./ioc";
import { TYPE } from "./constants";
import IMyService from "./abstract/IMyService";
// import routers
import MyRouter from "./api/MyRouter";
app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const router: Router = express.Router();
const myRouter: MyRouter = new MyRouter(container.get<IMyService>(TYPE.IMyService));
app.use("/", router);
app.use("/api/v1/layouts", layoutRouter.router);
MyRouter.ts
import IMyService from "./abstract/IMyService";
import { Router, Request, Response } from "express";
import { inject } from "inversify";
import { TYPE } from "../constants";
export default class MyRouter {
public readonly router: Router;
private readonly myService: IMyService;
constructor(
#inject(TYPE.IMyService) myService: IMyService
) {
this.myService = myService;
this.router = Router();
this.routes();
}
public GetAll(req: Request, res: Response): void {
this.myService.getAll()
.then(data => {
const status: number = res.statusCode;
res.json({ status, data });
})
.catch(err => {
const status: number = res.statusCode;
res.json({ status, err });
});
}
public GetOne(req: Request, res: Response): void {
const id: string = req.params.id;
this.myService.getOne(new ObjectID(id))
.then(data => {
const status: number = res.statusCode;
res.json({ status, data });
})
.catch(err => {
const status: number = res.statusCode;
res.json({ status, err });
});
}
routes(): void {
this.router
.get("/", this.GetAll)
.get("/:id", this.GetOne);
}
}
If you define your function with the arrow syntax (ES6), it will "bind" the context to it automatically and you won't need to bind them. But it will depends on your use case (ou might need to bind a different context)

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>

localhost REST API request error ionic2 angular2

I am making a get/post request to my locally hosted REST API server in an Ionic 2 app. The errow below shows up afer a couple of seconds.
3 387557 group EXCEPTION: Response with status: 0 for URL: null
4 387558 error EXCEPTION: Response with status: 0 for URL: null
5 387558 groupEnd
6 387568 error Uncaught Response with status: 0 for URL: null, http://localhost:8100/build/js/app.bundle.js, Line: 88826
I am able to make a successful curl request to the local server. Here is my code for reference.
app.js
var express = require("express");
var mysql = require("mysql");
var bodyParser = require("body-parser");
var SHA256 = require("sha256");
var rest = require("./REST.js");
var app = express();
function REST(){
var self = this;
self.connectMysql();
};
REST.prototype.connectMysql = function() {
var self = this;
var pool = mysql.createPool({
connectionLimit : 100,
host : 'host',
user : 'user',
password : 'password',
database : 'database',
debug : false
});
pool.getConnection(function(err,connection){
if(err) {
self.stop(err);
} else {
self.configureExpress(connection);
}
});
}
REST.prototype.configureExpress = function(connection) {
var self = this;
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var router = express.Router();
app.use('/api', router);
var rest_router = new rest(router,connection,SHA256);
self.startServer();
}
REST.prototype.startServer = function() {
app.listen(3000, function() {
console.log("All right ! I am alive at Port 3000. OKAY BUDDY");
});
}
REST.prototype.stop = function(err) {
console.log("ISSUE WITH MYSQL n" + err);
process.exit(1);
}
new REST();
REST.js
var mysql = require("mysql");
function REST_ROUTER(router, connection, SHA256) {
var self = this;
self.handleRoutes(router, connection, SHA256);
}
REST_ROUTER.prototype.handleRoutes= function(router,connection,SHA256) {
router.get("/",function(req,res){
res.json({'foo': 'bar'});
});
});
login.js (component)
import {Component} from '#angular/core';
import {NavController} from 'ionic-angular';
import {AuthProvider} from '../../providers/auth/auth';
/*
Generated class for the LoginPage page.
See http://ionicframework.com/docs/v2/components/#navigation for more info on
Ionic pages and navigation.
*/
#Component({
templateUrl: 'build/pages/login/login.html',
providers: [AuthProvider]
})
export class LoginPage {
static get parameters() {
return [[NavController], [AuthProvider]];
}
constructor(nav, AuthProvider) {
this.nav = nav;
this.authProvider = AuthProvider;
this.form = {};
}
login(form) {
this.authProvider.login(form).then(res => {
alert(JSON.stringify(res));
});
}
}
auth.js (provider)
import {Injectable} from '#angular/core';
import {Http, Headers, RequestOptions} from '#angular/http';
import 'rxjs/add/operator/map';
/*
Generated class for the Auth provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
#Injectable()
export class AuthProvider {
static get parameters(){
return [[Http]]
}
constructor(http) {
this.url = 'http://localhost:3000/api';
this.http = http;
}
login(form) {
return new Promise(resolve => {
this.http.get(this.getUrl)
.map(res => res.json())
.subscribe(data => {
resolve(data);
});
});
}
}
I had the same problem, and was able to resolve it. I was serving my API on localhost:8000. When ionic makes a request to localhost or 127.0.0.1, I think it is blocked. I instead found my computer's IP address and hosted my webserver on 0.0.0.0:8000 and instead of hitting http://localhost:8000/api/my/endpoint I hit http://mycomputerip:8000/api/my/endpoint, and it worked!
You are trying to request empty URL bacause of typo in auth.js login function:
this.http.get(this.getUrl)
this.getUrl is not defined in your code samples. Easy fix:
this.http.get(this.url)

Resources