MEAN return from http get - javascript

I'm learning to set up a MEAN app, but am stuck with retuning data into my app from a webservice. Just returning a simple variable is no problem, but how do I return the result from the webservice?
The result from the webservices is shown in de terminal console, but not on the frontend (angular). When I return e.g the options var it is shown in the frontend console, but the result from the webservice is not. Than I get $promise: Object, $resolved: false,
I'm building it with MEAN.js
This is what I have till now
shop.server.route.js
'use strict';
/**
* Module dependencies.
*/
var shop = require('../../app/controllers/shop.server.controller.js');
module.exports = function(app) {
app.route('/shop')
.get(shop.listProducts);
};
shop.server.controller.js
'use strict';
var http = require('http'),
errorHandler = require('./errors.server.controller');
/**
* List of Products
*/
exports.listProducts = function(req, res) {
var options = {
host: 'http://api.example.com',
path: '/products?param1=1&param2=2'
};
req = http.get(options, function(res) {
var body = {};
res.on('data', function (chunk) {
body += chunk;
});
res.on('end', function () {
console.log('Got Response' + body );
});
});
req.on('error', function(err) {
console.log( err.message);
res.send('error:' + err.message);
});
};

Angular works with async proccessing and callback digestions, which mean your http call retrun a promise object who get resolved when data arrived.
You should use angular's $http service. As mentioned in the documentation:
The $http service is a function which takes a single argument — a configuration object — that is used to generate an HTTP request and returns a promise with two $http specific methods: success and error.
You code should look like below (In the angular side):
var params = {};
params.param1 = 'paramdata';
$http.get('/shop', params).
success(function(data, status, headers, config) {
// data will contain the results data
}).
error(function(data, status, headers, config) {
// data will contain any error data
});
Feel free the extend your knowledge using the documentation - $http service

Related

How to return information from node.js to angular2

I sent information from angular to a node.js file. I would like to know how can return information from the node.js to angular2.
Code in index.js
app.post('/', function(req,res){
var body = req.body;
*/ information received from angular2 file
(...)
*/ then return information back to angular2 file. **How to do this?**
};
Can someone help me please? Thank you.
First you should learn how is the flow of the http requests.
This is an example using $resource an Angular built-in tool.
The following is a representation of a search functionality where I am sending as a param what the user is looking for, from a search text box in the view:
// :search is the param
angular.module("MyApp")
.factory("Search", function($resource) {
return $resource("/api/search/:search", {}, {
query : {
method : "GET",
isArray : true
}
});
});
This is the controller:
All this controllers does is to watch if there is an user typing in the input text for search and taking the what the user is writing and sending it to the backend, working along with the factory/service which is above. This functionality sends the data to the backend in order to GET a query which is an array of the result of the searched.
angular.module('MyApp')
.controller('AddCtrl', function($scope, $alert, Show, Search) {
$scope.showName = '';
$scope.data = {};
$scope.addShowToModel = '';
$scope.$watch('showName', function (tmpStr) {
if (!tmpStr || tmpStr.length == 0) return 0;
if (tmpStr === $scope.showName) {
Search.query({ 'search': $scope.showName })
.$promise.then(function(data) {
$scope.responseData = data;
})
.catch(function(response) {
console.log(response.error);
});
}
});
});
And here the code from Nodejs:
app.get('/api/search/:search', function(req, res, next) {
var searchParam = req.params.search
.toLowerCase()
.replace(/ /g, '_')
.replace(/[^\w-]+/g, '');
var parser = xml2js.Parser(); // npm module to convert xml to json
request.get('http://thetvdb.com/api/GetSeries.php?seriesname=' + searchParam, function (error, response, body) {
if (error) return next(error);
parser.parseString(body, function (err, result) {
if (result.Data.Series !== undefined) {
// this is how you send the data to the frontend
return res.status(200).send(result.Data.Series);
} else {
res.status(411).send({message: searchParam + " wasn't found"});
}
});
});
});
So, to put it simpler:
app.post('/', function(req, res){
var body = req.body;
console.log(body);
return res.send(//whatever you need to send);
};
Sometimes you don't want to send data to the frontend but a status code to see how the operation went:
app.post('/', function(req, res){
if(everythingIsFine) {
// send only status code
res.sendStatus(200);
}else {
// in case you want to send status + message
res.status(401).send('Invalid whatever thing');
}
};
Hope it helps!
EDIT
In the service, you can use $http instead of $resource. That is the not the important thing on my answer but just telling you. According to a comment:
It would be more appropriate to use $http.get instead of $resource. $resource is intended for RESTful CRUD endpoints. A search endpoint does not fit that specification.

HTTP request from within Express/Node.js

I'm trying to set up an express service for a program that I'm writing that contacts an external API and then returns the results so it can be stored in a Mongo I have set up.
This seems like it should be fairly straightforward, but I'm new to Node.js/Express and I'm getting a "Can't set headers after they are sent" error.
I'm getting the data that I want from the external API, but how to send that data properly back to my Angular app.js so it can update in my table?
"addSelected()" is the function I'm calling in my app.js to kick off the process. The "data" prints part of the way through the full response but then cuts off and gives me the "Can't set Headers after they are sent" error. From what I understand this is from sending the response and then trying to modify the response header after the fact.. but I'm unsure of a workaround or if I'm just formatting everything wrong as this is my first swing at MEAN stack in general.
I know the problem is on the line "res.send(data)" in server.js but I don't know how to correctly format the response.
My code:
server.js
//server.js
//setup ==============================
var express = require ('express');
var request = require('request');
var app = express();
var mongoose = require('mongoose');
var https = require('https');
//config ============================
app.use(express.static(__dirname + '/public/'));
console.log("running PipeHelper");
mongoose.connect('mongoedit');
var Schema = mongoose.Schema;
var opSchema = new Schema({
title: String,
description: String,
company: String,
post_date: String,
close_date: String,
contact: String,
location: String,
url: String,
notice_type: String
});
var item = mongoose.model('item', opSchema);
//routes===========================
//returns full database
app.get('/api/db', function(req, res){
item.find({},function(err, items){
if (err) res.send(err);
res.json(items);
});
});
//searches FBO for opportunities to add to database
app.get('/api/search:FBO_key', function(req, res){
var data;
console.log("2");
var baseURL = "api.data.gov"
var params = "/gsa/fbopen/v0/opps?q=" + req.params.FBO_key;
params += "&api_key="+"keyyyy";
params += "&all";
params += "&start=0";
params += "&p=1";
params += "&limit=10";
url = baseURL+params;
var options = {
port: 443,
host: 'api.data.gov',
path: params,
method: 'GET'
};
//get FBO data
var request = https.request(options, function(response){
console.log("4");
response.on('data', function (chunk){
//response data to send back to app.js
data += chunk.toString();
res.send(data);
});
});
console.log("3");
request.end();
request.on('error', function(e){
console.error(e);
});
});
app.get('/', function(req,res){
res.sendfile('./public/index.html');
});
app.listen(8000);
app.js
var app = angular.module("pipeHelper", ['smart-table']);
app.controller('mainCtrl', [
'$scope', '$http', function($scope, $http){
$scope.selected = [];
$scope.displayData= [];
$scope.items=[];
$scope.FBOsearch;
//populates table on startup with whole DB
$http.get('./api/db')
.success(function(data){
$scope.items=data;
$scope.displayData = [].concat($scope.items);
})
.error(function(data){
console.log('Error: '+data);
});
$scope.addSelected = function(){
//search FBO, add opportunities, update table
console.log("1");
$http.get('./api/search'+'NGA')
.success(function(data){
console.log("5");
console.log(data);
$scope.items=data;
$scope.displayData= [].concat($scope.items);
})
.error(function(data){
console.log('Error: ' +data);
});
};
$scope.isSelected = function(item){
//if its selected, remove it
// if its unselected, add it
if ($scope.selected.indexOf(item)==-1){
$scope.selected.push(item);
}
else{
$scope.selected.splice($scope.selected.indexOf(item), 1);
}
console.log($scope.selected);
//temp placeholder function. Eventually add to array of selected objects for placement in Pipeliner/deletion
};
}]);
solved the issue. I was unaware that response.on('data') gets called multiple times, thus calling my res.send(data) multiple times and incompletely causing it to crash with the error. I added the following to the request function:
response.on('end'function(){
res.send(data);
};
basically when the external API data is finished coming in, send it with express. Learn by doing I suppose. Hope this helps someone eventually.
I can't leave a comment, so I will just make it an answer.
I would recommend installing node-inspector, npm install -g node-debug. Then run your app with node-debug server.js. This will spawn a new instance of Firefox or Chrome dev tools and allows you to debug your nodeJS code. Very useful.
The error you are seeing is most likely related to request.end(), if I were to guess. After .end() is called, you can no longer modify the header content. I doubt it would make a difference, but try putting the request.end() after you have the request.on('error') call.
EDIT: 10/15/15
I would highly recommend installing VS Code. It has a built-in debugger for node apps.

How to use external rest api in Sails js (nodejs MVC)

Im using sailsjs as a MVC for node js, i'm still learning it.
I managed to get data from my own database and use it.
But now i need/want to get data from an external rest api.
I used this in my controller:
// api/controllers/SomeController.js
test : function(res,req){
var j;
var https = require('https');
var options = {
hostname: 'testing.atlassian.net',
port: 443,
path: '/rest/api/2/search?jql=project=ABC',
method: 'GET',
headers: {'Authorization': 'Basic ' + 'SuperSecretLoginAndPassword'}
};
var req = https.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function(d) {
});
});
req.end();
}
The variable d is displaying the right result.
How can i use the request results in my view?
I've searched a lot but i cant find any ways to display this in my view.
And will this be realtime updated? So if something in de rest api changes I won't have to refresh.
Sorry if this is something stupid.
Basically you'll want to wait for your request to fire its callback and then feed the fetched data into res.locals. Assuming you are fetching JSON data, you could do this:
// api/controllers/SomeController.js
test: function(req, res) {
var https = require('https');
...
https.request(options, function(response) {
var responseData = '';
response.setEncoding('utf8');
response.on('data', function(chunk){
responseData += chunk;
});
response.once('error', function(err){
// Some error handling here, e.g.:
res.serverError(err);
});
response.on('end', function(){
try {
// response available as `responseData` in `yourview`
res.locals.requestData = JSON.parse(responseData);
} catch (e) {
sails.log.warn('Could not parse response from options.hostname: ' + e);
}
res.view('yourview');
});
}).end();
}
The example code you supplied has some issues:
test: function(res,req) ... Don't mixup the controller arguments, the first is _req_uest, the second one _res_ponse.
var req = https.request ... You really do not want to override the req argument passed into your controller action. Use some other name.
https.request(options, function(res) {...} Same here. Doing this overrides res for the https.request callback scope - preventing you from using all the goodies (e.g.: res.view) supplied by the res parameter passed to your controller.
I'd guess it would make sense for you to read up on closures and callbacks:
What are Closures and Callbacks?

Any way to make a generic response handler in nodejs?

I'm trying to write a couple of endpoints that will make GET and POST http requests to various backend services, the format of data is all going to be very similar so responseHandler function will be copied over and over to different route function, I wonder if there is a way to externalize responseHandler for reuse. I tried to just move it out, but then I would lose reference to res. Anyone has any tips on a more modular design?
routes['/endpoint'] = function(req, res){
console.log("Serving endpoint: /endpoint")
var params={"param": "param-value"}
var options = {
host: 'localhost',
path: '/service?param='+params.param,
method: 'GET'
};
var responseHandler = function(response) {
var data = '';
// keep track of the data you receive
response.on('data', function(chunk) {
data += chunk + "\n";
});
// finished? ok, send the data to the client in JSON format
response.on('end', function() {
res.header("Content-Type:","application/json");
res.end(data);
});
};
// make the request, and then end it, to close the connection
http.request(options, responseHandler).end();
};
generally i would think you could create a folder in your lib called responseHandlers, add a file that contains something like
var responseHandler = function(response) {
var data = '';
// keep track of the data you receive
response.on('data', function(chunk) {
data += chunk + "\n";
});
// finished? ok, send the data to the client in JSON format
response.on('end', function() {
res.header("Content-Type:","application/json");
res.end(data);
});
};
exports.Handler = responseHandler;
save that as whateverHandler.js, then create an index.js file that requires whatever.js and exports it Handler. this way if you need to add more handlers in the future you just have to add a file and update the index.js. to use, do something in the route handler like
var handler = require('./lib/responseHandlers').whateverHandler;
routes['/endpoint'] = function(req, res){
console.log("Serving endpoint: /endpoint")
var params={"param": "param-value"}
var options = {
host: 'localhost',
path: '/service?param='+params.param,
method: 'GET'
};
};
// make the request, and then end it, to close the connection
http.request(options, handler).end();
};
You could turn responseHandler into a function generator, and pass in your res object so you don't lose it:
var responseHandler = function(res) {
return function(response) {
var data = '';
// keep track of the data you receive
response.on('data', function(chunk) {
data += chunk + "\n";
});
// finished? ok, send the data to the client in JSON format
response.on('end', function() {
res.header("Content-Type:","application/json");
res.end(data);
});
};
}
And use it like this:
routes['/endpoint'] = function(req, res){
console.log("Serving endpoint: /endpoint")
var params={"param": "param-value"}
var options = {
host: 'localhost',
path: '/service?param='+params.param,
method: 'GET'
};
// make the request, and then end it, to close the connection
http.request(options, responseHandler(res)).end();
};

HTTP GET Request in Node.js Express

How can I make an HTTP request from within Node.js or Express.js? I need to connect to another service. I am hoping the call is asynchronous and that the callback contains the remote server's response.
Here is a snippet of some code from a sample of mine. It's asynchronous and returns a JSON object. It can do any form of GET request.
Note that there are more optimal ways (just a sample) - for example, instead of concatenating the chunks you put into an array and join it etc... Hopefully, it gets you started in the right direction:
const http = require('http');
const https = require('https');
/**
* getJSON: RESTful GET request returning JSON object(s)
* #param options: http options object
* #param callback: callback to pass the results JSON object(s) back
*/
module.exports.getJSON = (options, onResult) => {
console.log('rest::getJSON');
const port = options.port == 443 ? https : http;
let output = '';
const req = port.request(options, (res) => {
console.log(`${options.host} : ${res.statusCode}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
output += chunk;
});
res.on('end', () => {
let obj = JSON.parse(output);
onResult(res.statusCode, obj);
});
});
req.on('error', (err) => {
// res.send('error: ' + err.message);
});
req.end();
};
It's called by creating an options object like:
const options = {
host: 'somesite.com',
port: 443,
path: '/some/path',
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
And providing a callback function.
For example, in a service, I require the REST module above and then do this:
rest.getJSON(options, (statusCode, result) => {
// I could work with the resulting HTML/JSON here. I could also just return it
console.log(`onResult: (${statusCode})\n\n${JSON.stringify(result)}`);
res.statusCode = statusCode;
res.send(result);
});
UPDATE
If you're looking for async/await (linear, no callback), promises, compile time support and intellisense, we created a lightweight HTTP and REST client that fits that bill:
Microsoft typed-rest-client
Try using the simple http.get(options, callback) function in node.js:
var http = require('http');
var options = {
host: 'www.google.com',
path: '/index.html'
};
var req = http.get(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
// Buffer the body entirely for processing as a whole.
var bodyChunks = [];
res.on('data', function(chunk) {
// You can process streamed parts here...
bodyChunks.push(chunk);
}).on('end', function() {
var body = Buffer.concat(bodyChunks);
console.log('BODY: ' + body);
// ...and/or process the entire body here.
})
});
req.on('error', function(e) {
console.log('ERROR: ' + e.message);
});
There is also a general http.request(options, callback) function which allows you to specify the request method and other request details.
Request and Superagent are pretty good libraries to use.
note: request is deprecated, use at your risk!
Using request:
var request=require('request');
request.get('https://someplace',options,function(err,res,body){
if(err) //TODO: handle err
if(res.statusCode === 200 ) //etc
//TODO Do something with response
});
You can also use Requestify, a really cool and very simple HTTP client I wrote for nodeJS + it supports caching.
Just do the following for GET method request:
var requestify = require('requestify');
requestify.get('http://example.com/api/resource')
.then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
response.getBody();
}
);
This version is based on the initially proposed by bryanmac function which uses promises, better error handling, and is rewritten in ES6.
let http = require("http"),
https = require("https");
/**
* getJSON: REST get request returning JSON object(s)
* #param options: http options object
*/
exports.getJSON = function (options) {
console.log('rest::getJSON');
let reqHandler = +options.port === 443 ? https : http;
return new Promise((resolve, reject) => {
let req = reqHandler.request(options, (res) => {
let output = '';
console.log('rest::', options.host + ':' + res.statusCode);
res.setEncoding('utf8');
res.on('data', function (chunk) {
output += chunk;
});
res.on('end', () => {
try {
let obj = JSON.parse(output);
// console.log('rest::', obj);
resolve({
statusCode: res.statusCode,
data: obj
});
}
catch (err) {
console.error('rest::end', err);
reject(err);
}
});
});
req.on('error', (err) => {
console.error('rest::request', err);
reject(err);
});
req.end();
});
};
As a result you don't have to pass in a callback function, instead getJSON() returns a promise. In the following example the function is used inside of an ExpressJS route handler
router.get('/:id', (req, res, next) => {
rest.getJSON({
host: host,
path: `/posts/${req.params.id}`,
method: 'GET'
}).then(({ statusCode, data }) => {
res.json(data);
}, (error) => {
next(error);
});
});
On error it delegates the error to the server error handling middleware.
Unirest is the best library I've come across for making HTTP requests from Node. It's aiming at being a multiplatform framework, so learning how it works on Node will serve you well if you need to use an HTTP client on Ruby, PHP, Java, Python, Objective C, .Net or Windows 8 as well. As far as I can tell the unirest libraries are mostly backed by existing HTTP clients (e.g. on Java, the Apache HTTP client, on Node, Mikeal's Request libary) - Unirest just puts a nicer API on top.
Here are a couple of code examples for Node.js:
var unirest = require('unirest')
// GET a resource
unirest.get('http://httpbin.org/get')
.query({'foo': 'bar'})
.query({'stack': 'overflow'})
.end(function(res) {
if (res.error) {
console.log('GET error', res.error)
} else {
console.log('GET response', res.body)
}
})
// POST a form with an attached file
unirest.post('http://httpbin.org/post')
.field('foo', 'bar')
.field('stack', 'overflow')
.attach('myfile', 'examples.js')
.end(function(res) {
if (res.error) {
console.log('POST error', res.error)
} else {
console.log('POST response', res.body)
}
})
You can jump straight to the Node docs here
Check out shred. It's a node HTTP client created and maintained by spire.io that handles redirects, sessions, and JSON responses. It's great for interacting with rest APIs. See this blog post for more details.
Check out httpreq: it's a node library I created because I was frustrated there was no simple http GET or POST module out there ;-)
For anyone who looking for a library to send HTTP requests in NodeJS, axios is also a good choice. It supports Promises :)
Install (npm): npm install axios
Example GET request:
const axios = require('axios');
axios.get('https://google.com')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
Github page
Update 10/02/2022
Node.js integrates fetch in v17.5.0 in experimental mode. Now, you can use fetch to send requests just like you do on the client-side. For now, it is an experimental feature so be careful.
If you just need to make simple get requests and don't need support for any other HTTP methods take a look at: simple-get:
var get = require('simple-get');
get('http://example.com', function (err, res) {
if (err) throw err;
console.log(res.statusCode); // 200
res.pipe(process.stdout); // `res` is a stream
});
Use reqclient: not designed for scripting purpose
like request or many other libraries. Reqclient allows in the constructor
specify many configurations useful when you need to reuse the same
configuration again and again: base URL, headers, auth options,
logging options, caching, etc. Also has useful features like
query and URL parsing, automatic query encoding and JSON parsing, etc.
The best way to use the library is create a module to export the object
pointing to the API and the necessary configurations to connect with:
Module client.js:
let RequestClient = require("reqclient").RequestClient
let client = new RequestClient({
baseUrl: "https://myapp.com/api/v1",
cache: true,
auth: {user: "admin", pass: "secret"}
})
module.exports = client
And in the controllers where you need to consume the API use like this:
let client = require('client')
//let router = ...
router.get('/dashboard', (req, res) => {
// Simple GET with Promise handling to https://myapp.com/api/v1/reports/clients
client.get("reports/clients")
.then(response => {
console.log("Report for client", response.userId) // REST responses are parsed as JSON objects
res.render('clients/dashboard', {title: 'Customer Report', report: response})
})
.catch(err => {
console.error("Ups!", err)
res.status(400).render('error', {error: err})
})
})
router.get('/orders', (req, res, next) => {
// GET with query (https://myapp.com/api/v1/orders?state=open&limit=10)
client.get({"uri": "orders", "query": {"state": "open", "limit": 10}})
.then(orders => {
res.render('clients/orders', {title: 'Customer Orders', orders: orders})
})
.catch(err => someErrorHandler(req, res, next))
})
router.delete('/orders', (req, res, next) => {
// DELETE with params (https://myapp.com/api/v1/orders/1234/A987)
client.delete({
"uri": "orders/{client}/{id}",
"params": {"client": "A987", "id": 1234}
})
.then(resp => res.status(204))
.catch(err => someErrorHandler(req, res, next))
})
reqclient supports many features, but it has some that are not supported by other
libraries: OAuth2 integration and logger integration
with cURL syntax, and always returns native Promise objects.
If you ever need to send GET request to an IP as well as a Domain (Other answers did not mention you can specify a port variable), you can make use of this function:
function getCode(host, port, path, queryString) {
console.log("(" + host + ":" + port + path + ")" + "Running httpHelper.getCode()")
// Construct url and query string
const requestUrl = url.parse(url.format({
protocol: 'http',
hostname: host,
pathname: path,
port: port,
query: queryString
}));
console.log("(" + host + path + ")" + "Sending GET request")
// Send request
console.log(url.format(requestUrl))
http.get(url.format(requestUrl), (resp) => {
let data = '';
// A chunk of data has been received.
resp.on('data', (chunk) => {
console.log("GET chunk: " + chunk);
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
console.log("GET end of response: " + data);
});
}).on("error", (err) => {
console.log("GET Error: " + err);
});
}
Don't miss requiring modules at the top of your file:
http = require("http");
url = require('url')
Also bare in mind that you may use https module for communicating over secured network. so these two lines would change:
https = require("https");
...
https.get(url.format(requestUrl), (resp) => { ......
## you can use request module and promise in express to make any request ##
const promise = require('promise');
const requestModule = require('request');
const curlRequest =(requestOption) =>{
return new Promise((resolve, reject)=> {
requestModule(requestOption, (error, response, body) => {
try {
if (error) {
throw error;
}
if (body) {
try {
body = (body) ? JSON.parse(body) : body;
resolve(body);
}catch(error){
resolve(body);
}
} else {
throw new Error('something wrong');
}
} catch (error) {
reject(error);
}
})
})
};
const option = {
url : uri,
method : "GET",
headers : {
}
};
curlRequest(option).then((data)=>{
}).catch((err)=>{
})

Categories

Resources