Express rest api call with angular 2 How to - rest

Greeting,
I have a trivial issue on calling a rest api from angular 2.
I have a rest api endpoint:
api/room/byName/:roomName
if I use restfull tools like postman etc and call api http://localhost:3000/api/room/byName/roomname1 this works fine and get result.
But when i can call this from angular2 , the rest api is not even being called.
let params: URLSearchParams = new URLSearchParams();
params.set('roomName', roomName);
return this
.http
.get('/api/room/byName',{search:params})
.map((response: Response) => response.json());
I am sure, I am not calling it properly. Appreciate your help on how to call it from angular 2.
Thanks
Edit
After getting advice this is my code now but still no luck:
Angular call:
return this.http
.get('/api/room/byName/'+roomName)
.map((res: Response) => res.json());
Express endpoint:
var rooms = express.Router();
rooms.get('/byName/:roomName', function(req,res){
var roomn = req.params.roomName;
console.log('Looking by roomName: ' + roomn);
Room.findOne({ "roomName": roomn }, function(err, rooms) {
if (err) {
next(err);
} else {
res.json(rooms);
}
});
});
This works fine if i call the endpoint from browser:
http://localhost:3000/api/room/byName/test

The Http get takes only url and not body as parameter.It is not a post to have body.
Try:
let params: URLSearchParams = new URLSearchParams();
params.set('roomName', roomName);
return this
.http
.get(`/api/room/byName/${roomName}`)
.map((response: Response) => response.json());

first make sure you're enabled CORS
2nd: change this
let params: URLSearchParams = new URLSearchParams();
params.set('roomName', roomName);
return this
.http
.get('/api/room/byName',{search:params})
.map((response: Response) => response.json());
to:
return this
.http
.get('/api/room/byName/'+ roomName)
.map((response: Response) => response.json());

Related

Content-type using axios

I'm working with React and axios. I'm trying to fetch the response using axios however, unable to understand why I'm getting wrong content-type even though I'm setting it in my backend code.
Code (backend):
router.get(url, async (req, res) => {
// return new Promise(async (resolve, reject) => {
try {
if (file exists) {
var fileContents = Buffer.from(document[0].data, "base64"); //document contains the data from the postgres database
var readStream = new stream.PassThrough();
readStream.end(fileContents);
res.set(
"Content-disposition",
"attachment; filename=" + document[0].fileName
);
res.setHeader("content-type", document[0].fileType);
readStream.pipe(res);
console.log("+++++++++++++++++++");
console.log(res);
console.log("+++++++++++++++++++");
return;
} else {
res.json({
status: 0,
message: "File not found",
});
return;
}
// resolve({ document });
} catch (err) {
console.log(err);
}
});
The above backend code works absolutely fine. I even printed the response to check whether the content-type is setting or not. I'm even providing the output snippet for that as well
However, in the frontend if I try to fetch the response this is what I'm receiving
I'm not sure what's wrong. Why I'm receiving wrong content-type. Even the content length is same for any sort of file which I try to download.
The axios call :
let response = await Axios.get(fileURL, {
responseType: "blob"/"arraybuffer",
Authorization: "Bearer " + token,
});
Response.data output :
Any help will be appreciated!

Angular 2: Method DELETE is not allowed by Access-Control-Allow-Methods in preflight response

I need to delete a record on my mongodb using mongoose.
Here is my component
deleteProduct(product){
this._confirmationService.confirm({
message: 'Are you sure you want to delete the item?',
accept: () => {
this._productsAdminService.deleteProduct(product._id)
.subscribe(products => {
products.forEach(function(product){
if(product.cat_id === 1) product.catName = 'Dota Shirts';
if(product.cat_id === 2) product.catName = 'Gym Shirts';
if(product.cat_id === 3) product.catName = 'Car Shirts';
});
this.products = products;
},
err => console.log(err));
}
})
}
basically this will just pass the product id to the service to execute http request.
Here is my service
deleteProduct(productId){
let headers = new Headers({'Authorization': 'JWT ' + localStorage.getItem('currentUserToken')});
let options = new RequestOptions({ headers: headers});
return this._http.delete('http://localhost:3000/admin/products/delete/' + productId, options)
.map((response: Response) => response.json())
.catch(this._handlerError);
}
I am using the delete method to call my API in expressJS.
Here is my API
productsAdminRouter.route('/delete/:productId')
.delete(function(req,res){
id = req.params.productId;
console.log(id);
Products.findByIdAndRemove(id)
.exec(function(err, done){
if (err) throw err;
Products.find()
.exec(function(err, products){
res.json(products);
});
});
});
But I always got this error
Can anyone help? I'm stuck.
Exactly like #flashjpr said
I had to write an especific middleware to my entity "ticket".
var allowDelete = function(req, res, next){
res.append('Access-Control-Allow-Methods', 'DELETE')
next()
}
and pass it to the first middleware of that entity
app.use('/tickets', allowDelete, tickets);
EDIT: I'm was using expressjs.
I had the same problem the other day when working with a Java-Spring backend: when Cross-origin resource sharing (or simply cors) is happening, Angular sends apre-flight request before the actual (here DELETE) request which is of type OPTIONS(http).
What you have to do is:
enable CORS on your server
make sure your server accepts OPTIONS request on that particular endpoint ( /delete/:productId)
add the Access-Control-Allow-Methods header to the response of the OPTIONS, DELETE

Getting and "Error, wrong validation token" when trying to create a Facebook Chatbot

I'm trying to create a Facebook chatbot with NodeJS, Express, and a Heroku server.
I created my webhook on heroku and had it verified and saved by facebook. I then started adding code that would reply to the incoming messages and I can't seem to get it connected. It keeps saying "Error, wrong validation token" when I try to load my webhook in my browser. And when I try to send my bot a message I get no response. Even though I already had it verified and didn't change the code.
Here is my code:
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var port = process.env.PORT || 3000;
// body parser middleware
app.use(bodyParser.urlencoded({ extended: true }));
// test route
//app.get('/', function (req, res) { res.status(200).send('Hello world!') });
app.get('/', function (req, res) {
if (req.query['hub.verify_token'] === '8FKU9XWeSjnZN4ae') {
res.send(req.query['hub.challenge']);
}
res.send('Error, wrong validation token');
})
app.post('/', function (req, res) {
messaging_events = req.body.entry[0].messaging;
for (i = 0; i < messaging_events.length; i++) {
event = req.body.entry[0].messaging[i];
sender = event.sender.id;
if (event.message && event.message.text) {
text = event.message.text;
sendTextMessage(sender, "Text received, echo: "+ text.substring(0, 200));
}
}
res.sendStatus(200);
});
// error handler
app.use(function (err, req, res, next) {
console.error(err.stack);
res.status(400).send(err.message);
});
app.listen(port, function () {
console.log('Listening on port ' + port);
});
var token = <myToken>;
function sendTextMessage(sender, text) {
messageData = {
text:text
}
request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
}
}, function(error, response, body) {
if (error) {
console.log('Error sending message: ', error);
} else if (response.body.error) {
console.log('Error: ', response.body.error);
}
});
}
So I'm confused as to why nothing is happening and why I'm getting that error. I feel like I'm missing a whole step. I am following this tutorial by the way: https://developers.facebook.com/docs/messenger-platform/quickstart
Any help is appreciated. Thanks!
Edit: Here are my heroku logs
Do not post your full access tokens here!
Have you tested the output of the challenge? Since it's just a GET and you know all values you can try it yourself: your-app-domain.com/your-callback-url?hub_mode=subscribe&hub_verify_token=the_token_you_set_in_your_app_config&hub_challenge=ping which sould print 'ping' if everything work fine.
Make sure you add sendStatus(200) to the hub challenge response, too.
You need to subscribe your page to the app first. To do so make a POST request to /your-page-id/subscribed_apps which should return "success". You can make a GET request to the same endpoint afterwards to double check your app is subscribed to your page
You did not mention which events you subscribed to (needs to be message_deliveries, messages, messaging_optins, messaging_postbacks)
Make sure the webhooks tab in your app dashboard now says "complete"
Test again
You are actually using "request" but you are never importing it anywhere. Here's how to fix it:
var request = require("request")
Once you have added that to your index.js or app.js file (basically whatever this file is), make sure you do:
npm install request --save
This should fix it. Unfortunately, Heroku doesn't error out and say that it does not know what "request" is and that's why it was so hard to figure this out in the first place!

Get public feeds of a Facebook Page in Node.js

I'm developing a simple node/express/jade website that fetch all the public feeds of a Facebook Page.
I create an application from wich i get client_id (APP_ID) and client_secret (APP_SECRET).
My code works, and it's okay but i wonder if this is the correct way of handling this need.
Here is the code:
var https = require('https'),
concat = require('concat-stream'),
async = require('async');
function FacebookPage(pageId) {
if (!(this instanceof FacebookPage))
return new FacebookPage(pageId);
this.pageId = pageId;
}
FacebookPage.prototype.getPublicFeeds = function (callback) {
var pageId = this.pageId;
async.waterfall([
function (done) {
var params = {
hostname: 'graph.facebook.com',
port: 443,
path: '/oauth/access_token?client_id=MY_CLIENT_ID&' +
'client_secret=MY_CLIENT_SECRET&grant_type=client_credentials',
method: 'GET'
};
https.get(params, function (response) {
//response is a stream so it is an EventEmitter
response.setEncoding("utf8");
//More compact
response.pipe(concat(function (data) {
done(null, data);
}));
response.on("error", done);
});
},
function (access_token, done) {
var params = {
hostname: 'graph.facebook.com',
port: 443,
path: '/v2.0/' + pageId + '/feed?' + access_token,
method: 'GET'
};
https.get(params, function (response) {
//response is a stream so it is an EventEmitter
response.setEncoding("utf8");
//More compact
response.pipe(concat(function (data) {
callback(null, JSON.parse(data));
}));
response.on("error", callback);
});
}]);
};
module.exports = FacebookPage;
EDIT: thank to #Tobi I can delete the part of getting the access_token by putting access_token=app_id|app_secret as explained here:
Not sure why you'd want to include to OAuth stuff (which I think can't work because you don't exchange the code for an actual access token if I understand this correctly)...
According to https://developers.facebook.com/docs/graph-api/reference/v2.0/page/feed/ you need an access token ... to view publicly shared posts., this means you can also use an app access token in the form of app_id|app_secret.
You can then use the
GET /{page_id}/feed
endpoint by passing the access_token paramenter with your app access token. I'd also recommend to use the NPM modules request or restler, these make the HTTP handling much easier.

How to make remote REST call inside Node.js? any CURL?

In Node.js, other than using child process to make CURL call, is there a way to make CURL call to remote server REST API and get the return data?
I also need to set up the request header to the remote REST call, and also query string as well in GET (or POST).
I find this one: http://blog.nodejitsu.com/jsdom-jquery-in-5-lines-on-nodejs
but it doesn't show any way to POST query string.
Look at http.request
var options = {
host: url,
port: 80,
path: '/resource?id=foo&bar=baz',
method: 'POST'
};
http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
}).end();
How about using Request — Simplified HTTP client.
Edit February 2020: Request has been deprecated so you probably shouldn't use it any more.
Here's a GET:
var request = require('request');
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body) // Print the google web page.
}
})
OP also wanted a POST:
request.post('http://service.com/upload', {form:{key:'value'}})
I use node-fetch because it uses the familiar (if you are a web developer) fetch() API. fetch() is the new way to make arbitrary HTTP requests from the browser.
Yes I know this is a node js question, but don't we want to reduce the number of API's developers have to memorize and understand, and improve re-useability of our javascript code? Fetch is a standard so how about we converge on that?
The other nice thing about fetch() is that it returns a javascript Promise, so you can write async code like this:
let fetch = require('node-fetch');
fetch('http://localhost', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: '{}'
}).then(response => {
return response.json();
}).catch(err => {console.log(err);});
Fetch superseeds XMLHTTPRequest. Here's some more info.
Look at http://isolasoftware.it/2012/05/28/call-rest-api-with-node-js/
var https = require('https');
/**
* HOW TO Make an HTTP Call - GET
*/
// options for GET
var optionsget = {
host : 'graph.facebook.com', // here only the domain name
// (no http/https !)
port : 443,
path : '/youscada', // the rest of the url with parameters if needed
method : 'GET' // do GET
};
console.info('Options prepared:');
console.info(optionsget);
console.info('Do the GET call');
// do the GET request
var reqGet = https.request(optionsget, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
// console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('GET result:\n');
process.stdout.write(d);
console.info('\n\nCall completed');
});
});
reqGet.end();
reqGet.on('error', function(e) {
console.error(e);
});
/**
* HOW TO Make an HTTP Call - POST
*/
// do a POST request
// create the JSON object
jsonObject = JSON.stringify({
"message" : "The web of things is approaching, let do some tests to be ready!",
"name" : "Test message posted with node.js",
"caption" : "Some tests with node.js",
"link" : "http://www.youscada.com",
"description" : "this is a description",
"picture" : "http://youscada.com/wp-content/uploads/2012/05/logo2.png",
"actions" : [ {
"name" : "youSCADA",
"link" : "http://www.youscada.com"
} ]
});
// prepare the header
var postheaders = {
'Content-Type' : 'application/json',
'Content-Length' : Buffer.byteLength(jsonObject, 'utf8')
};
// the post options
var optionspost = {
host : 'graph.facebook.com',
port : 443,
path : '/youscada/feed?access_token=your_api_key',
method : 'POST',
headers : postheaders
};
console.info('Options prepared:');
console.info(optionspost);
console.info('Do the POST call');
// do the POST call
var reqPost = https.request(optionspost, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
// console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('POST result:\n');
process.stdout.write(d);
console.info('\n\nPOST completed');
});
});
// write the json data
reqPost.write(jsonObject);
reqPost.end();
reqPost.on('error', function(e) {
console.error(e);
});
/**
* Get Message - GET
*/
// options for GET
var optionsgetmsg = {
host : 'graph.facebook.com', // here only the domain name
// (no http/https !)
port : 443,
path : '/youscada/feed?access_token=you_api_key', // the rest of the url with parameters if needed
method : 'GET' // do GET
};
console.info('Options prepared:');
console.info(optionsgetmsg);
console.info('Do the GET call');
// do the GET request
var reqGet = https.request(optionsgetmsg, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
// console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('GET result after POST:\n');
process.stdout.write(d);
console.info('\n\nCall completed');
});
});
reqGet.end();
reqGet.on('error', function(e) {
console.error(e);
});
Axios
An example (axios_example.js) using Axios in Node.js:
const axios = require('axios');
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
app.get('/search', function(req, res) {
let query = req.query.queryStr;
let url = `https://your.service.org?query=${query}`;
axios({
method:'get',
url,
auth: {
username: 'the_username',
password: 'the_password'
}
})
.then(function (response) {
res.send(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
});
var server = app.listen(port);
Be sure in your project directory you do:
npm init
npm install express
npm install axios
node axios_example.js
You can then test the Node.js REST API using your browser at: http://localhost:5000/search?queryStr=xxxxxxxxx
Similarly you can do post, such as:
axios({
method: 'post',
url: 'https://your.service.org/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
SuperAgent
Similarly you can use SuperAgent.
superagent.get('https://your.service.org?query=xxxx')
.end((err, response) => {
if (err) { return console.log(err); }
res.send(JSON.stringify(response.body));
});
And if you want to do basic authentication:
superagent.get('https://your.service.org?query=xxxx')
.auth('the_username', 'the_password')
.end((err, response) => {
if (err) { return console.log(err); }
res.send(JSON.stringify(response.body));
});
Ref:
https://github.com/axios/axios
https://www.twilio.com/blog/2017/08/http-requests-in-node-js.html
I have been using restler for making webservices call, works like charm and is pretty neat.
To use latest Async/Await features
https://www.npmjs.com/package/request-promise-native
npm install --save request
npm install --save request-promise-native
//code
async function getData (){
try{
var rp = require ('request-promise-native');
var options = {
uri:'https://reqres.in/api/users/2',
json:true
};
var response = await rp(options);
return response;
}catch(error){
throw error;
}
}
try{
console.log(getData());
}catch(error){
console.log(error);
}
Warning: As of Feb 11th 2020, request is fully deprecated.
One another example - you need to install request module for that
var request = require('request');
function get_trustyou(trust_you_id, callback) {
var options = {
uri : 'https://api.trustyou.com/hotels/'+trust_you_id+'/seal.json',
method : 'GET'
};
var res = '';
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
res = body;
}
else {
res = 'Not Found';
}
callback(res);
});
}
get_trustyou("674fa44c-1fbd-4275-aa72-a20f262372cd", function(resp){
console.log(resp);
});
const http = require('http');
const url = process.argv[2];
http.get(url, function(response) {
let finalData = "";
response.on("data", function (data) {
finalData += data.toString();
});
response.on("end", function() {
console.log(finalData.length);
console.log(finalData.toString());
});
});
I didn't find any with cURL so I wrote a wrapper around node-libcurl and can be found at https://www.npmjs.com/package/vps-rest-client.
To make a POST is like so:
var host = 'https://api.budgetvm.com/v2/dns/record';
var key = 'some___key';
var domain_id = 'some___id';
var rest = require('vps-rest-client');
var client = rest.createClient(key, {
verbose: false
});
var post = {
domain: domain_id,
record: 'test.example.net',
type: 'A',
content: '111.111.111.111'
};
client.post(host, post).then(function(resp) {
console.info(resp);
if (resp.success === true) {
// some action
}
client.close();
}).catch((err) => console.info(err));
If you have Node.js 4.4+, take a look at reqclient, it allows you to make calls and log the requests in cURL style, so you can easily check and reproduce the calls outside the application.
Returns Promise objects instead of pass simple callbacks, so you can handle the result in a more "fashion" way, chain the result easily, and handle errors in a standard way. Also removes a lot of boilerplate configurations on each request: base URL, time out, content type format, default headers, parameters and query binding in the URL, and basic cache features.
This is an example of how to initialize it, make a call and log the operation with curl style:
var RequestClient = require("reqclient").RequestClient;
var client = new RequestClient({
baseUrl:"http://baseurl.com/api/", debugRequest:true, debugResponse:true});
client.post("client/orders", {"client": 1234, "ref_id": "A987"},{"x-token": "AFF01XX"});
This will log in the console...
[Requesting client/orders]-> -X POST http://baseurl.com/api/client/orders -d '{"client": 1234, "ref_id": "A987"}' -H '{"x-token": "AFF01XX"}' -H Content-Type:application/json
And when the response is returned ...
[Response client/orders]<- Status 200 - {"orderId": 1320934}
This is an example of how to handle the response with the promise object:
client.get("reports/clients")
.then(function(response) {
// Do something with the result
}).catch(console.error); // In case of error ...
Of course, it can be installed with: npm install reqclient.
You can use curlrequest to easily set what time of request you want to do... you can even set headers in the options to "fake" a browser call.
Warning: As of Feb 11th 2020, request is fully deprecated.
If you implement with form-data, for more info (https://tanaikech.github.io/2017/07/27/multipart-post-request-using-node.js):
var fs = require('fs');
var request = require('request');
request.post({
url: 'https://slack.com/api/files.upload',
formData: {
file: fs.createReadStream('sample.zip'),
token: '### access token ###',
filetype: 'zip',
filename: 'samplefilename',
channels: 'sample',
title: 'sampletitle',
},
}, function (error, response, body) {
console.log(body);
});
I found superagent to be really useful,
it is very simple
for example
const superagent=require('superagent')
superagent
.get('google.com')
.set('Authorization','Authorization object')
.set('Accept','application/json')
Update from 2022:
from node.js version v18 on you can use the globally available fetch API (see https://nodejs.org/en/blog/announcements/v18-release-announce/)
There is also an example usage included on their announcement page:
const res = await fetch('https://nodejs.org/api/documentation.json');
if (res.ok) {
const data = await res.json();
console.log(data);
}