get request throwing 404 error in Angular 5 app - javascript

I am a newbie to Angular.I am creating a demo video player app, following youtube series, but I am struck at a point where I can't get data for my get request.I am using Angular 5.2.10.Below are my files and code:
server.js:
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const api = require('./server/routes/api');
const port = 3000;
const app = express();
app.use(express.static(path.join(__dirname,'dist')));
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
app.use('/api',api);
app.get('*',(req,res)=>{
res.sendFile(path.join(__dirname,'dist/index.html'));
});
app.listen(port,function(){
console.log("server running on localhost"+port);
});
api.js:
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const Video = require('../models/video');
const
db="mongodb://usersubhash:subhashpwd#ds217350.mlab.com:17350/videoplayer";
mongoose.Promise = global.Promise;
mongoose.connect(db,function(err){
if(err){
console.log("Error!"+err);
}
});
router.get('/videos',function(req,res){
//res.send('api works');
Video.find({}).exec(function(err,videos){
if(err){
console.log("error retrieving videos");
}else{
res.json(videos);
}
});
});
module.exports = router;
video.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const videoSchema = new Schema({
title:String,
url:String,
description:String
});
module.exports = mongoose.model('video',videoSchema,'videos');
video.ts:
export class Video {
_id:string;
title:string;
url:string;
description:string
}
environment.ts
export const environment = {
production: false,
apiUrl: 'http://localhost:3000'
};
video.service.ts:(where I have getVideos() method)
import { Injectable } from '#angular/core';
import {Http,Response} from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class VideoService {
constructor(private _http:Http) { }
private _getUrl = `${environment.apiUrl}/api/videos`;
getVideos(){
return this._http.get(this._getUrl).map((response:Response)=> response.json());
}
}
videoCenter.component.ts:(where I am subscribing to getVideos() method):
import { Component, OnInit } from '#angular/core';
import {Video} from '../video';
import { VideoService } from '../video.service';
#Component({
selector: 'app-video-center',
templateUrl: './video-center.component.html',
styleUrls: ['./video-center.component.css'],
providers:[VideoService]//,Http,HttpClientModule
})
export class VideoCenterComponent implements OnInit {
myAllVideos:Array;//here I want to put my get Request Data
constructor(private _videoService:VideoService) { }
selectedVideo:Video;
onSelectVideo (video:any){
this.selectedVideo=video;
}
ngOnInit() {
this._videoService.getVideos().subscribe(result => this.myAllVideos = result);
}
}
When I run node server.js in VSCode terminal , then in POSTMAN app I can get all records by requesting GET in "localhost:3000/api/videos".But in my app, I am unable to load data which is running in 4200 port.
When I click on button which loads video-center.component.ts , getVideos() is triggered in ngOnInit() but it throws this error:

Your screenshot showing the error has this url:
http://localhost:4200/api/videos
But your server.js says:
const port = 3000;
So your server is running on port 3000, not 4200. Port 4200 is normally where Angular runs.
So you need to modify your getUrl:
private _getUrl = "http://localhost:3000/api/videos";
Rather than hard code this I suggest you read-up on how to setup an environment file, and put the host part "http://localhost:3000" in the environment file and read it from there. Then your code could be:
private _getUrl = `${environment.apiUrl}/api/videos`;
NOTE
Just to be clear - although Angular runs on the client, it is an app that has to be started from somewhere. For example, in a production situation you might have this:
https://app.mydomain.com <- users visit this, and the browser starts running your angular app
https://api.mydomain.com <- your angular app will get its data from here
In production it's quite likely both of these urls will be accessed on port 80. But since the subdomains are different (api versus app) that is perfectly fine.
However, when running locally in development mode, you cannot run two different things (ie. an Angular application and a Node application) on the same address (localhost) with the same port.
Since you are running them both on localhost, they must have different ports. So when you wrote:
return this._http.get(this._getUrl)...
it is defaulting to where Angular itself is running, localhost:4200, not your api. You need to tell angular your api is on port 3000.

Related

Socket.io on Heroku does not run as expected

I have a MERN application. I want to run this on Heroku. That also works so far. But I can't get socket.io to run on Heroku. My server listens on port 5555. Below I have listed all possible scenarios that I have already tried without success. What else can I do ?
I specify "ws://localhost:5555" or "http://localhost:5555" whatever it is, it works with a local address.
Thank you very much!
index.js Server
import express from "express";
import http from "http";
import { Server } from "socket.io";
const app = express();
const server = http.createServer(app);
const socketio = new Server(server, { cors: { origin: "*" } });
socketio.on("connect", (socket) => {
socket.on("addUser", (userId) => {
addUser(userId, socket.id);
console.log(users);
});
...
});
app.listen(process.env.PORT || 5050, () => {
verbindugZuMongoDb();
});
server.listen(5555);
App.js
import { io } from "socket.io-client";
useEffect(() => {
setSocket(io("wss://example.herokuapp.com:5555/")); // Also not working
setSocket(io("https://example.herokuapp.com:5555/")); // Also not working
setSocket(io()); // Also not working
setSocket(io(":5555")); // Also not working
setSocket(io("https://example.herokuapp.com/")); // Also not working
}, []);

Cross import in node.js

I´m making a node.js project in typescript. I want to put my socket.io code in a separate file to organize.
I see in the console that socketHandling.ts is loaded before index.ts, which I find odd.
But the problem is that Typeof server in socketHandling.ts is undefined.
How do I make sure the server variable from index.ts is defined before socketHandling.ts is executed?
index.ts
import * as express from "express";
import * as path from "path";
import * as socketHandle from "./socketHandling";
console.log("index.ts loaded");
export const server = express()
.use(express.static(path.join(__dirname, "../../public")))
.set("views", path.join(__dirname, "../../views"))
.set("view engine", "ejs")
.get("/*", httpGet)
.post("/*", httpPost)
.listen(PORT, () => console.log(`Listening on ${PORT}`));
socketHandle.initSockets();
socketHandling.ts
import { Server } from "socket.io";
import { server } from "./index";
console.log("socketHandling.ts loaded");
console.log(server);
const io = new Server(server);
export function initSockets(): void {
io.on("connection", (socket) => {
console.log(`Client connected ${socket.id}`);
socket.on("disconnect", () => {
console.log(`Client disconnected ${socket.id}`);
});
});
}
Why does it go through socketHandling before the index server is defined?
If index.ts is your entry point, once the program counter reaches line 3 of index.ts, the import will make it start executing socketHandling.ts, which contains another import back to index.ts, which wasn't even done executing yet. So this looks like a circular import maybe you should avoid the situation altogether.
Proposed Solution:
Avoid the circular import by passing in the server from the top into the initSockets method that you import from the library file.
Try the following refactor:
index.ts
import * as express from "express";
import * as path from "path";
import * as socketHandle from "./socketHandling";
console.log("index.ts loaded");
export const server = express()
.use(express.static(path.join(__dirname, "../../public")))
.set("views", path.join(__dirname, "../../views"))
.set("view engine", "ejs")
.get("/*", httpGet)
.post("/*", httpPost)
.listen(PORT, () => console.log(`Listening on ${PORT}`));
socketHandle.initSockets(server);
socketHandling.ts
import { Server } from "socket.io";
console.log("socketHandling.ts loaded");
let io: Server;
export function initSockets(server): void {
if (!io) {
io = new Server(server);
}
io.on("connection", (socket) => {
console.log(`Client connected ${socket.id}`);
socket.on("disconnect", () => {
console.log(`Client disconnected ${socket.id}`);
});
});
}
Typically it wont be sustainable to export stuff from your application entry point for the entire library to use. Usually you see these kinds of variables passed down into methods rather than globally referenced across different files throughout the entire application.

Angular Node | SocketIO | Event not emitted from node

I had asked this question before but here's a simple code for the same.
Im sending the data to Node from angular via websocket but I don't get the emitted event:
I've followed 10+ tutorials and forums, newest from here: https://www.youtube.com/watch?v=66T2A2dvplY&t=317s
service:
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
import { io } from 'socket.io-client';
#Injectable({
providedIn: 'root'
})
export class SocketService {
socket = io('ws://localhost:3000'); // adding 'http://localhost:3000' also doesnt work
constructor() {}
listen(eventName: string) {
return new Observable( subscriber => {
this.socket.on(eventName, data => {
subscriber.next(data);
});
});
}
emit(eventName: string, data) {
this.socket.emit(eventName, data);
}
}
from component's ngOnInit(), this is called:
this._socketService.listen('test event').subscribe( data => {
console.log("data from server: ", data);
});
server code of Node:
const app = require('./app');
const port = process.env.PORT || 3000;
const server = require('http').createServer(app);
const socketio = require('socket.io');
const io = socketio(server,
{
serveClient: true,
pingInterval: 60000,
pingTimeout: 60000000,
cors: {
origin: "http://localhost:4200",
methods: ["GET", "POST"],
credentials: true
}
});
io.on('connection', function (socket) {
console.log("A user connected ", socket.connected); // works till here for every ping interval
socket.emit('test event', 'here is some data'); // this is either not executed or doesn't work
});
server.listen(port);
socket.connected is always true in NODE server, but false in Angular
What Ive tried:
CORS has been suppressed, I hope that's not the issue cuz nothing is seen like so
changing io.('connection' ...) to io.connect('connect'...)
init this.socket = io(...) in constructor
There is no data exchange seen in Network or Network > WS tab in case I emit from Angular too
This is my 3rd day with this problem, I'll highly appreciate any help.
Thank you
your mixing protocols from client.
change
socket = io('ws://localhost:3000');
to
socket = io('http://localhost:3000', { withCredentials: true });
As mentioned in introduction under chapter What Socket.IO is not that socket.io is not a pure WS lib.

How to send data from react to nodejs without localhost?

I am trying to deploy reactjs & nodejs app to heroku.
I have successfully deployed frontend,but frontend is sending data to nodejs using localhost due to which when running app through heroku only frontend is working.
This code send data to nodejs.
saveUserJson = (User) =>{
const url = 'http://localhost:5000/write'
axios.post(url,User)
.then(response => {
//console.log(response);
});
}
This is nodejs code(ignore hostname in code).
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');
const morgan = require('morgan');
const cors = require('cors');
const jsonData = require('../src/descriptors/bnk48.json')
const app = express();
const port = 5000;
const hostname = '192.168.43.113';
app.use(bodyParser.json());
app.use(morgan('dev'));
app.use(cors());
app.get('/',(req,res) => res.status(200).send({
message: "Server is running..."
}));
const WriteTextToFileSync = (contentToWrite) => {
fs.writeFileSync('./src/descriptors/bnk48.json',contentToWrite,(err) =>{
//console.log(contentToWrite);
if(err) {
console.log(err);
}else {
console.log('Done writing to file successfully...')
}
})
}
const user = {
}
app.post('/write',(req,res,next) =>{
const user = {
"name": req.body[0].name,
"descriptors": req.body[0].descriptors
}
jsonData[user.name]=user
//console.log(req.body[0].descriptors)
const requestContent = JSON.stringify(jsonData,null,2);
WriteTextToFileSync(requestContent)
});
app.use((req,res,next) => res.status(404).send({
message: "Couldn't find specified route that was requested..."
}));
app.listen(port,hostname,()=>{
console.log(
`
!!! server is running..
!!! Listening for incoming requests on port ${port}
!!! Server running at http://${hostname}:${port}/
!!! http://localhost:5000
`
)
})
How can i change localhost so that while deploying it automatically chooses where to send data?
How can i change localhost so that while deploying it automatically chooses where to send data?
There are several ways to do this, but it's quite common to use environment variables for this purpose. These are set by environment, your development machine being one environment and your production site on Heroku being another environment. You could for example define the environment variable BACKEND_ROOT_URL to hold the schema and FQDN of your site, and make your axios call like this:
saveUserJson = (User) =>{
const url = `${process.env.BACKEND_ROOT_URL}/write`
axios.post(url,User)
.then(response => {
//console.log(response);
});
}
The build-time value of url will be different, depending on which environment you perform the build in.
Setting environment variables locally can be done in several ways. In a Bash shell you can set them manually like export BACKEND_ROOT_URL=http://localhost:5000. That get's boring quite fast though, so I would recommend you to check out dotenv which handles this for you efficiently.
Heroku has its own way of handling the setting of envvars - check the documentation here

Unable to insert to the MongoDB instance from different files in a single project

I have made a basic skeleton of a typescript project here: https://github.com/xameeramir/instruments-admin
The mongoose connection is made from the index.ts file:
require('dotenv').config();
import express from "express";
const app = express();
const port = 8080; // default port to listen
import routes from "./routes";
import { connectToTheDatabase } from './mongooseUtility';
// define a route handler for the default home page
app.get("/status", (req, res) => {
res.send("Instruments admin functionalities available!");
});
connectToTheDatabase();
app.use(routes);
// start the Express server
app.listen(port, () => {
console.log(`Instruments admin functionalities available at PORT ${port}`);
});
In the all-tradeables.controller.ts, I'm calling InstrumentModel.insertMany.
Now, for some unknown reasons, the insertion is not happening. When I go to the MongoDB instance, I don't see any document inserted.
I have looked around the internet and I don't see any mistake in the code. Can someone please help me understand why the insertion is not working?
Problem was you were returning model without mongo instance.
Solution goes here:
replace all-tradeables.model.ts content with the following:
// import * as mongoose from 'mongoose';
import { Schema, Model, model } from 'mongoose';
const mongooseInstance = require("mongoose");
let connString = 'mongodb://localhost:27017/dbnamegoeshere';
mongooseInstance.connect(connString, {useNewUrlParser: true});
// define Schema
let InstrumentSchema = new Schema({
instrument_token: Number,
exchange_token: Number,
tradingsymbol: String,
name: String,
last_price: Number,
expiry: Date,
strike: Number,
tick_size: Number,
lot_size: Number,
instrument_type: String,
segment: String,
exchange: String
});
// compile schema to model
export const InstrumentModel = mongooseInstance.model('Instrument', InstrumentSchema);
export const storeAllInstruments = (InstrumentsData: any) => {
// return (() => {
return new Promise((resolve, reject) => {
})
// })();
}

Categories