Empty return of NodeJS in Angular - javascript

My NodeJs application return in this url (http://localhost:3000/api/campaigns) a json response.
But when my Angular application call this url, get a empty response.
I try to change the 200 http code to 404, and I see this change, but always there ara a empty response.
Angular:
var campaigns = function(country) {
var deferred = $q.defer();
$http.get( "http://localhost:3000/api/campaigns" ).then(function(response) {
deferred.resolve(response);
}, function(response) {
deferred.reject(response);
});
return deferred.promise
}
And in my NodeJs code:
exports.findAllCampaigns = function(req, res) {
Campaign
.find({})
.limit(10)
.exec(function(err, campaigns) {
if(err) res.send(500, err.message);
res.status(200).jsonp(campaigns);
});
};
In my browser console, the XHR request is always empty (http 200).

This is just to have a response on this question (i would like that either charlietfl or Carlos Vazquez posted this as response rather than me :) )
BY charlietfl --> Just implement CORS in api
BY Carlos Vázquez --> Thanks! I just enabled the cors middleware with:
var cors = require('cors');
var app = express();
app.use(cors());

Related

api proxy server not parsing data back to user CORS

I am trying to access an api but when I access it in the browser, I get a CORS error. To get around this problem I set up an api proxy server. When this proxy gets a html request it connects to the browser blocked api and pulls the data needed. I think there is a problem on the proxy server where it is also blocking CORS and that needs to be changed, I’m not so sure. When I call the proxy api it gets the data from the browser blocked api and logs it to the console but does not push it to the browser because of the error below.
1.How do I correct this error “Reason: CORS header 'Access-Control-Allow-Origin' missing”
2.Should I be doing this a different way?
Error
Data being logged on the server
Server routing code - app.js
const apiCallFromRequest = require('./Request')
const apiCallFromNode = require('./NodeJsCall')
const apiCallFromTEST = require('./test.js')
const http = require('http')
http.createServer((req, res) => {
if(req.url === "/test"){
let start_time = new Date().getTime();
apiCallFromTEST.callApi(function(response){
//console.log(JSON.stringify(response));
res.write(JSON.stringify(response));
console.log(response);
console.log("Request API Requested");
console.log('API Test Time:', new Date().getTime() - start_time, 'ms');
res.end();
});
API proxy rought code -test.js
var rp = require('request-promise');
const callExternalApiUsingRequest = (callback) => {
var options = {
uri: 'https://app.invoiceninja.com/api/v1/products',
headers: {
'X-Ninja-Token': 'APIKEY'
},
json: true // Automatically parses the JSON string in the response
};
rp(options)
.then(function (data) {
console.log(data);
return callback(data);
})
.catch(function (err) {
// API call failed...
});
}
module.exports.callApi = callExternalApiUsingRequest;
website side - Just a basic fetch request
function gotProductData(){
fetch('http://localhost:3000/test')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
Try to install "cors" package (npm install cors) and import to app.js :
const cors = require('cors');
Run that above routes:
app.use(cors())
More details:
https://www.npmjs.com/package/cors#installation

Cannot GET / DELETE Express.js

I have this script with which I'm trying to POST, GET and DELETE some stuff.
When I try POST or GET, the right messages are logged, but when I try DELETE, I get the following error:
Cannot GET /del_user
The URL I'm using is http://127.0.0.1:8081/del_user
What can be wrong in here?
var express = require('express');
var app = express();
// This responds with "Hello World" on the homepage
app.get('/', function (req, res) {
console.log("Got a GET request for the homepage");
res.send('Hello GET');
})
// This responds a POST request for the homepage
app.post('/', function (req, res) {
console.log("Got a POST request for the homepage");
res.send('Hello POST');
})
// This responds a DELETE request for the /del_user page.
app.delete('/del_user', function (req, res) {
console.log("Got a DELETE request for /del_user");
res.send('Hello DELETE');
})
// This responds a GET request for the /list_user page.
app.get('/list_user', function (req, res) {
console.log("Got a GET request for /list_user");
res.send('Page Listing');
})
// This responds a GET request for abcd, abxcd, ab123cd, and so on
app.get('/ab*cd', function(req, res) {
console.log("Got a GET request for /ab*cd");
res.send('Page Pattern Match');
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
I solved it by changing the app.delete to app.get and then placing the required remove statement inside the app.get. Something like this :-
app.get('/delete/:userId', (req, res) => {
Users.remove({ _id: req.params.userId }, (error, posts) => {
if (error) {
console.warn(error);
}
else {
data = posts
res.render("delete", {"data": data})
}
});
});
In your code you're binding the /del_user URL to the HTTP DELETE method.
So all you need to do is specify the DELETE method in your application or in Postman.
If you're not using it, it's an App in Google Chrome and you might want to download it, it makes your life a LOT easier ;)
Also, since the HTTP method is already declared to be DELETE, there is no need to specify it in the URL.
This is part of the RESTful working.
If you are using AJAX to try your code, you need to specify the method, which is delete.
$.ajax({
url: "http://127.0.0.1:8081/del_user",
type: "DELETE"
});

MYSQL + Node.JS Post Request Confusion

I am very new to networking and I have this code which, when I use a REST API like Postman, does exactly what I want it to do:
router.post('/', function(req,res,next){
var reqObj = req.body;
console.log(reqObj);
req.getConnection(function(err, conn){
if(err)
{
console.error('SQL Connection error: ', err);
return next(err);
}
else
{
var query = conn.query("INSERT INTO coordinates (id,lat,lon) VALUES(3,2,1);");
if(err)
{
console.error('SQL error: ', err);
return next(err);
}
res.json("Coordinates sent.");
}
})
} );
That is, it sends the query request to the MYSQL database. My question is, how do I do this without using Postman to send the POST request?
Thank you.
You can't unless you make a post request from within your application or something. If you don't intend on sending data, you can just make it a GET request by changing
router.post('/', function(req,res,next){
to
router.get('/', function(req,res,next){
Then you can just go to the relevant URL from your browser. If you're using chrome and you just wanna see the JSON data, I'd also recommend installing the JSONView chrome extension.
EDIT
Here's the example request using request-promise
var request = require('request-promise');
var objectData = {
name: 'Bruce',
alias: 'Batman'
};
var options = {
method: 'POST',
uri: 'http://your.api/endpoint/',
body: objectData,
json: true // Automatically stringifies the body to JSON
};
request(options).then(function(response){
// handle success response
}, function(error){
// handle error response
})

AngularJS POST Fails: Response for preflight has invalid HTTP status code 404

I know there are a lot of questions like this, but none I've seen have fixed my issue. I've used at least 3 microframeworks already. All of them fail at doing a simple POST, which should return the data back:
The angularJS client:
var app = angular.module('client', []);
app.config(function ($httpProvider) {
//uncommenting the following line makes GET requests fail as well
//$httpProvider.defaults.headers.common['Access-Control-Allow-Headers'] = '*';
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
app.controller('MainCtrl', function($scope, $http) {
var baseUrl = 'http://localhost:8080/server.php'
$scope.response = 'Response goes here';
$scope.sendRequest = function() {
$http({
method: 'GET',
url: baseUrl + '/get'
}).then(function successCallback(response) {
$scope.response = response.data.response;
}, function errorCallback(response) { });
};
$scope.sendPost = function() {
$http.post(baseUrl + '/post', {post: 'data from client', withCredentials: true })
.success(function(data, status, headers, config) {
console.log(status);
})
.error(function(data, status, headers, config) {
console.log('FAILED');
});
}
});
The SlimPHP server:
<?php
require 'vendor/autoload.php';
$app = new \Slim\Slim();
$app->response()->headers->set('Access-Control-Allow-Headers', 'Content-Type');
$app->response()->headers->set('Content-Type', 'application/json');
$app->response()->headers->set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
$app->response()->headers->set('Access-Control-Allow-Origin', '*');
$array = ["response" => "Hello World!"];
$app->get('/get', function() use($array) {
$app = \Slim\Slim::getInstance();
$app->response->setStatus(200);
echo json_encode($array);
});
$app->post('/post', function() {
$app = \Slim\Slim::getInstance();
$allPostVars = $app->request->post();
$dataFromClient = $allPostVars['post'];
$app->response->setStatus(200);
echo json_encode($dataFromClient);
});
$app->run();
I have enabled CORS, and GET requests work. The html updates with the JSON content sent by the server. However I get a
XMLHttpRequest cannot load http://localhost:8080/server.php/post. Response for preflight has invalid HTTP status code 404
Everytime I try to use POST. Why?
EDIT: The req/res as requested by Pointy
EDIT:
It's been years, but I feel obliged to comment on this further. Now I actually am a developer. Requests to your back-end are usually authenticated with a token which your frameworks will pick up and handle; and this is what was missing. I'm actually not sure how this solution worked at all.
ORIGINAL:
Ok so here's how I figured this out.
It all has to do with CORS policy. Before the POST request, Chrome was doing a preflight OPTIONS request, which should be handled and acknowledged by the server prior to the actual request. Now this is really not what I wanted for such a simple server. Hence, resetting the headers client side prevents the preflight:
app.config(function ($httpProvider) {
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
});
The browser will now send a POST directly. Hope this helps a lot of folks out there... My real problem was not understanding CORS enough.
Link to a great explanation: http://www.html5rocks.com/en/tutorials/cors/
Kudos to this answer for showing me the way.
You have enabled CORS and enabled Access-Control-Allow-Origin : * in the server.If still you get GET method working and POST method is not working then it might be because of the problem of Content-Type and data problem.
First AngularJS transmits data using Content-Type: application/json which is not serialized natively by some of the web servers (notably PHP). For them we have to transmit the data as Content-Type: x-www-form-urlencoded
Example :-
$scope.formLoginPost = function () {
$http({
url: url,
method: "POST",
data: $.param({ 'username': $scope.username, 'Password': $scope.Password }),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function (response) {
// success
console.log('success');
console.log("then : " + JSON.stringify(response));
}, function (response) { // optional
// failed
console.log('failed');
console.log(JSON.stringify(response));
});
};
Note : I am using $.params to serialize the data to use Content-Type: x-www-form-urlencoded. Alternatively you can use the following javascript function
function params(obj){
var str = "";
for (var key in obj) {
if (str != "") {
str += "&";
}
str += key + "=" + encodeURIComponent(obj[key]);
}
return str;
}
and use params({ 'username': $scope.username, 'Password': $scope.Password }) to serialize it as the Content-Type: x-www-form-urlencoded requests only gets the POST data in username=john&Password=12345 form.
For a Node.js app, in the server.js file before registering all of my own routes, I put the code below. It sets the headers for all responses. It also ends the response gracefully if it is a pre-flight "OPTIONS" call and immediately sends the pre-flight response back to the client without "nexting" (is that a word?) down through the actual business logic routes. Here is my server.js file. Relevant sections highlighted for Stackoverflow use.
// server.js
// ==================
// BASE SETUP
// import the packages we need
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var morgan = require('morgan');
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
// ====================================================
// configure app to use bodyParser()
// this will let us get the data from a POST
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// Logger
app.use(morgan('dev'));
// -------------------------------------------------------------
// STACKOVERFLOW -- PAY ATTENTION TO THIS NEXT SECTION !!!!!
// -------------------------------------------------------------
//Set CORS header and intercept "OPTIONS" preflight call from AngularJS
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === "OPTIONS")
res.send(200);
else
next();
}
// -------------------------------------------------------------
// STACKOVERFLOW -- END OF THIS SECTION, ONE MORE SECTION BELOW
// -------------------------------------------------------------
// =================================================
// ROUTES FOR OUR API
var route1 = require("./routes/route1");
var route2 = require("./routes/route2");
var error404 = require("./routes/error404");
// ======================================================
// REGISTER OUR ROUTES with app
// -------------------------------------------------------------
// STACKOVERFLOW -- PAY ATTENTION TO THIS NEXT SECTION !!!!!
// -------------------------------------------------------------
app.use(allowCrossDomain);
// -------------------------------------------------------------
// STACKOVERFLOW -- OK THAT IS THE LAST THING.
// -------------------------------------------------------------
app.use("/api/v1/route1/", route1);
app.use("/api/v1/route2/", route2);
app.use('/', error404);
// =================
// START THE SERVER
var port = process.env.PORT || 8080; // set our port
app.listen(port);
console.log('API Active on port ' + port);

Correct way to protect URL with JSON web token and node.js/express

I'm currently authorizing users with JSON web tokens using node.js and express with EJS as the view engine.
Using simple middleware in my server.js file:
app.use(function(request, response, next){
var token = request.body.token || request.query.token || request.headers['x-access-token'];
console.log(request.body);
if(token){
jwt.verify(token, app.get('superSecret'), function(err, decoded){
if(err){
response.json({"message": "Failed to authenticate user"});
}
else{
request.decoded = decoded;
next();
}
});
}
else{
return response.status(403).json({"message":"No token was provided"});
}
});
and protected routes below it e.g:
app.post('/userlist', function(request, response) {
response.json({some: json})
});
What I can't understand or figure out is how to protect a GET route such as:
app.get('/userprofile', function(request, response) {
response.render('pages/userprofile');
});
If I make the request by some url directly www.example.com/userprofile access is denied, as there is no token included with the request.
If I make it via ajax:
$.ajax({
type:"GET",
url:"https://www.example.com/userprofile",
headers:{"x-access-token": token },
success: function(result, success){
},
error: function (result, error){
}
});
The response is not rendered but comes back in the result object. I've got my wires crossed somewhere here.
A token needs to be passed in order to be used. If the server doesn't have access to it, the server can't validate it. So, you can pass the token in the path :
app.get('/userprofile/:token',function(request,response){
console.log(request.params.token);
});
In the query string :
app.get('/userprofile',function(request,response){
console.log(request.query.token);
});
Or as a cookie :
var cookieParser = require('cookie-parser');
app.use(cookieParser);
app.get('/userprofile',function(request,response){
console.log(request.cookies.token);
});
http response code should be sent, default is 200 as in your case response.json({"message": "Failed to authenticate user"});
try
response.json(401, {"message": "Failed to authenticate user"});

Categories