I am trying to get the location of a user and send it to my server so I can make some api calls. I get the current location of the user, which is fine, but it does not post to the server and I do not know why. Can you look at my code and help me figure it out.
Backend
index.routes.js
router.post('/currentLatLong', ctrlEvent.currentLatLong);
event.controller.js
module.exports.currentLatLong = (req, res) => {
console.log('recieved');
this.currentLoc = req.body;
console.log('this.currentLoc', this.currentLoc);
}
Front-end
Service
constructor(private data: DataService, private http: HttpClient) { }
getUserLocation() {
/* locate the User */
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => {
this.currentLat = position.coords.latitude;
this.currentLng = position.coords.longitude;
console.log('position.coords.latitude', this.currentLat);
this.data.latitudeSource.next(this.currentLat);
this.data.longitudeSource.next(this.currentLng);
const currentLatLong = {
latitude: this.currentLat,
longitude: this.currentLng
};
console.log('currentLatLong', currentLatLong);
return this.http.post(environment.apiBaseUrl + '/currentLatLong',
currentLatLong);
}, err => {
console.log(err);
return false;
});
} else {
console.log('bad');
return false;
}
}
In angular side, you need to call the subscribe() method. Calling the subscribe() method executes the observable, which is what initiates the request.
this.http.post(environment.apiBaseUrl + '/currentLatLong', currentLatLong)
.subscribe(
res => {
console.log(res);
},
err => {
console.log(err);
}
);
An HttpClient method does not begin its HTTP request until you call subscribe() on the observable returned by that method.
Related
I have a challenge where I can't really make a decision on how to deal with HTTP responses / Errors in my services and controllers in my Express API. My goal is to have the services be responsible for one thing only and not deal with HTTP at all. Atleast that's my thought.
I would love some feedback on my approach...
I have added general error middlewares:
const errorResponder = (error, req, res, next) => {
if (error.statusCode && error.message) {
return res.status(error.statusCode).send(error.message);
}
if (error.statusCode) {
return res.status(error.statusCode).send();
}
if (error.message) {
return res.status(500).send(error.message);
}
return next(error); // Forward if above is't triggered
};
const errorFailSafe = (error, req, res, next) => {
console.log("Fail safe");
res.status(500).send("Something went wrong, we are digging into it!");
};
And then in my controller I unwrap what I need from the req and send to a service. Afterward I send the response back to the client.
findUser: async (req,res,next) => {
const userId = req.params.userId;
try {
// Call service
const user = await UserService.findOne(userId);
// Send user back to client
res.status(200).send(user);
} catch (error) {
return next(error)
}
}
In my service using Sequelize:
findOne: async (userId) => {
try {
let user = await db.users.findByPk(userId);
if (user == null) {
throw new NotFound("User not found");
}
return user;
} catch (error) {
throw error;
}
};
The NotFound error is a custom error class extending Error.
class NotFound extends Error {
constructor(message) {
super(message);
this.statusCode = 404;
}
}
module.exports = NotFound ;
Here I kinda break the seperation by having the Service deal with HTTP by calling NotFound.
I could change this so it's the Controller doing the check. Would that be better?
Any feedback would be appreciated. :)
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 am trying to build a Whatsapp chatbot using Node.JS and am running into a bit of trouble in receiving the Whatsapp message from Twilio. On checking the debugger, I get a Bad Gateway error, ie. Error 11200: HTTP Retrieval Failure. The message is getting sent, and ngrok shows the post request, however, dialogflow does not receive the request. On terminal, the error is showing UnhandledPromiseRejectionWarning: Error: 3 INVALID ARGUMENT: Input text not set. I'm not sure if it's because the message is not in JSON format. Please help!
This is the app.post function:
app.post('/api/whatsapp_query', async (req, res) =>{
message = req.body;
chatbot.textQuery(message.body, message.parameters).then(result => {
twilio.sendMessage(message.from, message.to, result.fulfillmentText).then(result => {
console.log(result);
}).catch(error => {
console.error("Error is: ", error);
});
return response.status(200).send("Success");
})
});
And this is the sendMessage function I've imported:
const config = require('./config/keys');
const twilioAccountID = config.twilioAccountID;
const twilioAuthToken = config.twilioAuthToken;
const myPhoneNumber = config.myPhoneNumber;
const client = require('twilio')(twilioAccountID,twilioAuthToken);
module.exports = {
sendMessage: async function(to, from, body) {
return new Promise((resolve, reject) => {
client.messages.create({
to,
from,
body
}).then(message => {
resolve(message.sid);
}).catch(error => {
reject(error);
});
});
}
}
And this is the textQuery function I've imported:
textQuery: async function(text, parameters = {}) {
let self = module.exports;
const request = {
session: sessionPath,
queryInput: {
text: {
text: text,
languageCode: config.dialogFlowSessionLanguageCode
},
},
queryParams: {
payload: {
date: parameters
}
}
};
let responses = await sessionClient.detectIntent(request);
responses = await self.handleAction(responses)
return responses[0].queryResult;
},
Twilio developer evangelist here.
The issue is that you are not passing the correct message body from the incoming WhatsApp message to your textQuery function.
First, you should make sure that you are treating the incoming webhook from Twilio as application/x-www-form-urlencoded. If you are using body-parser, ensure you have urlencoded parsing turned on.
app.use(bodyParser.urlencoded());
Secondly, the parameters that Twilio sends start with a capital letter. So your code currently gets message = req.body and then uses message.body. But it should be message.Body.
Those two points should sort you out.
One final thing though. The Twilio Node.js library will return a Promise if you do not pass a callback function. So you don't need to create a Promise here:
module.exports = {
sendMessage: async function(to, from, body) {
return new Promise((resolve, reject) => {
client.messages.create({
to,
from,
body
}).then(message => {
resolve(message.sid);
}).catch(error => {
reject(error);
});
});
}
}
You can just return the result of the call to client.messages.create
module.exports = {
sendMessage: async function(to, from, body) {
return client.messages.create({ to, from, body });
}
}
Hope this helps.
So I have a POST route that calls a function:
router.route('/generateSeed').post(function(req,res){
generate_seed(res)
});
UPDATE: Here is the genrate_seed() function
function generate_seed(res)
{
var new_seed = lightwallet.keystore.generateRandomSeed();
generate_addresses(new_seed, res);
}
var totalAddresses = 0;
function generate_addresses(seed, res)
{
if(seed == undefined)
{
console.log("seed")
}
var password = Math.random().toString();
lightwallet.keystore.createVault({
password: password,
seedPhrase: seed,
hdPathString: "m/44'/60'/0'/0" //added this changing from Default m/0'/0'/0'/
}, function (err, ks) {
ks.keyFromPassword(password, function (err, pwDerivedKey) {
if(err)
{
}
else
{
ks.generateNewAddress(pwDerivedKey, totalAddresses);
var addresses = ks.getAddresses()
var web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io"));//changed to infura as a provider
var html = "";
var address = addresses;
var seedPhrase = seed;
addToAPI(address,seedPhrase, res); //address
}
});
});
}
function addToAPI(address, seedPhrase, res){
var NewUser = {
publicK: address,
seed: seedPhrase
}
axios.post('http://localhost:3000/CryptoWallet/add/createCryptoWallet', NewUser)//changed from localhost
.then((res)=>{
console.log("Response");
})
.catch(error=>{
console.log(error);
})
}
Which calls to this second route:
router.route('/add/createCryptoWallet').post(function(req,res){
var crypto_wallet = new CryptoWallet(req.body)
console.log("The cyrptoWallet on create", crypto_wallet);
crypto_wallet.save()
.then(crypto_wallet =>{
res.json({data: CryptoWallet({_id:1})}); //<<--- I want this line
})
.catch(err => {
res.status(400).send("unable to save CryptoWallet to databse");
});
});
UPDATE I do get it to POST and save in the database. Right now I can only get the response from the first POST route is there a way to get the response from the second POST route my final goal is the get the _id created by mongo as a response.
Thanks ahead!
You are missing response sending for your first POST request (/generateSeed). addToAPI function need to wait until second POST request is finished and the send its own response. So basically it should look similar to this:
function addToAPI(address, seedPhrase, res){
var NewUser = {
publicK: address,
seed: seedPhrase
}
axios.post('http://localhost:3000/CryptoWallet/add/createCryptoWallet', NewUser)
.then((response)=>{
res.json(response.data); // axios wrappes the body of response into `data` object
})
.catch(error=>{
console.log(error);
res.status(500).('Some error occured');
})
}
I have been staring at this for a while, and finally realized that my code is returning the "200 ok." response instead of the actual data itself, and that is why it won't populate my ionic buttons. When I am calling the API via postman, and printing it to the console it is showing the data that I need, so I am assuming the issue is somewhere in the .ts files.
Below is my API code:
app.get('/getAllProvs', function (req,res) {
//var id = req.params.id;
connection.query('SELECT * from Patient', function(err, rows, fields) {
if (!err){
var response = [];
if (rows.length != 0) {
response.push({'result' : 'success', 'data' : rows});
} else {
response.push({'result' : 'error', 'msg' : 'No Results Found'});
}
res.setHeader('Content-Type', 'application/json');
//res.status(200).send(JSON.stringify(rows));
res.send(rows);
console.log(rows);
} else {
res.status(400).send(err);
}
});
});
below is my provider .ts code:
export class RestService {
data1: any;
constructor(public http: Http) {
console.log('Hello RestServiceProvider Provider');
}
getAllProvs(){
if(this.data1){
return Promise.resolve(this.data1);
}
return new Promise(resolve => {
this.http.get('http://lndapp.wpi.edu:5000/getAllProvs')
.map(res => res.json())
.subscribe(data => {
console.log("rest-services.ts subscribe");
this.data1 = data;
console.log(data);
resolve(this.data1);
});
});
}
}
below is my page .ts file:
export class AllPatientsPage {
data1: any;
constructor(public app: App, public loadingCtrl: LoadingController, private toastCtrl: ToastController, public navCtrl: NavController, public restService: RestService){
this.getAllProvs();
}
}
getAllProvs(){
this.restService.getAllProvs()
.then(data => {
console.log("all-patients.ts data");
console.log(data);
this.data1 = data;
}).catch(e => {
console.log(e);
});
}
}
Send a json response from your service:
res.json(rows);
If this is happening during development, it could be because you're using the same url on your front end react website as your server.js site.
Example:
front end running on : localhost:3000
backend listening on : localhost:3000/api
Fix: Change the port numbers.
front end running on : localhost:3000
backend listening on : localhost:5000/api
Additional help:
package.json: add proxy that points to your server: localhost:5000
browser: clear your cookies.
Hope this helps.