Access HTTP status code on successful Restangular request - coffeescript

How can I access the HTTP response status code after a successful request using Restangular?
CoffeeScript Example
Restangular.all('orders').getList().then (result) ->
console.log result # no status code
console.log 'Preferably, status code should be here: ', result.status
, (error) ->
console.log 'Error status code: ', error.status # this works
I tried to implement a response extractor to tack it on as metadata, but the status code is already stripped by the time it flows into the extractor.

You would use setFullResponse in your modules config to grab the status code on a successful request.
https://github.com/mgonto/restangular#setfullresponse
var app = angular.module('app', ['restangular']);
// Change setFullResponse to be true in the modules config.
app.config(['RestangularProvider', function (RestangularProvider) {
RestangularProvider.setFullResponse(true);
}]);
// Using the new response format.
app.controller('someController', ['Restangular', function (Restangular) {
Restangular.all('orders').getList().then(function (result) {
// Response from the server.
console.log(result.data);
// Response status code.
console.log(result.status);
});
}]);
Coffeescriptified:
app = angular.module('app', ['restangular'])
// Change setFullResponse to be true in the modules config.
app.config ['RestangularProvider', (RestangularProvider) ->
RestangularProvider.setFullResponse true
]
// Using the new response format.
app.controller 'someController', ['Restangular', (Restangular) ->
Restangular.all('orders').getList().then (result) ->
// Response from the server.
console.log result.data
// Response status code.
console.log result.status
]
Hope this helps!

Related

How to get headers from AxiosResponse-Observable?

Using NestJS, Axios returns an Observable<AxiosResponse>.
How can I get the headers of a GET- or HEAD-Request?
Lets say I make a HEAD-request:
import { HttpService } from '#nestjs/axios';
const observable = this.httpService.head(uri);
How can I get the headers from the result?
Update:
I found a nice workaround that just works with a single line of code.
There is another library called https with is more powerful:
import http from "https";
await http.request(uri, { method: 'HEAD' }, (res) => {
console.log(res.headers);
}).on('error', (err) => {
console.error(err);
}).end();
The headers of the response are available in the subscribe callback with the headers property.
this.httpService.head(uri).subscribe(res => {
console.log(res.headers)
});
Playground
According to https://github.com/axios/axios#request-config:
For request headers you should use something like this:
this.httpService.axiosRef.interceptors.request.use(function (config) {
// Do something before request is sent
console.log(config);
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
You should use it onModuleInit (to prevent working a few interceptors in a time)
Also you can make own module like in this answer: https://stackoverflow.com/a/72543771/4546382
For the response headers you can just use response.headers

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!

Disable redirect in fetch request using React native

I'm trying to crawl a web using React Native which has no API. It's written in PHP.
To log an user, a POST request must be sent. The response returns a cookie with a PHPSessid cookie which I must capture to use in subsequent requests.
I would like to capture the cookie value, buy the POST response is a 302 and the redirection is followed automatically, so I can't see the cookie. In node I was able to do it with redirect:manual, but it does not work in react native.
The cookie is sent automatically in subsequent requests, buy I'm trying to manage cookies by hand with react-native-cookie and I'd like to know if it's possible.
Do you know a way to stop the redirection?
I've been checking the code and what I did was the following:
Clear all cookies
Launch an empty login request
Capture the PHPSessID coookie
Launch a login request with that PHPSessID
After that, the subsequent fetch requests would have automatically a PHPSessID cookie with a valid logged in user, so we can use the site with simple fetchs
Here is some code, but the important thing is that you do a first empty login request, capture the PHPSessid and launch the real login request with that PHPSessid.
This would be the main function:
import Cookie from 'react-native-cookie';
// I think this is used only to clear the cookies
function login(user, pass){
// clear all cookies for all domains
// We need to start withouth authorization token
Cookie.clear();
const makeLoginRequest = (sessid) =>
makeLoginRequestForUserAndPass(user,pass,sessid);
return makeInitialRequest()
.then(getSessionIDFromResponse)
.then(makeLoginRequest)
.then(checkIfLoggedAndGetSessionID);
}
The initial request is a request to the login script. Note that I used GET because it worked with my site, perhaps an empty post would be necessary:
function makeInitialRequest() {
const INIT_PATH = '/index.php?r=site/login';
const INIT_URL = site + INIT_PATH;
const request = new Request(INIT_URL, options....);
return fetch(request);
}
We have the session ID in the response. I used a simple regex to extract it. Note that we are not logged in; PHP has created a session and that's what we have here:
function getSessionIDFromResponse(response) {
return getPHPSessIdFromCookie(response.headers.get('set-cookie'));
}
function getPHPSessIdFromCookie(header) {
const regex = /PHPSESSID=(\w*)/;
const match = regex.exec(header);
return match ? match[1] : '';
}
Now the login request. Note that I can't stop redirection here, but I't have to do it because we can have PHPSessid later. Redirection must be set to manual in POST request:
function makeLoginRequestForUserAndPass(user, pass, sessid) {
const request = buildLoginRequest(user, pass, sessid);
return fetch(request);
}
// This is where we build the real login request
function buildLoginRequest(user, pass, sessid) {
const LOGIN_PATH = '/index.php?r=site/login';
const LOGIN_URL = site + LOGIN_PATH;
const fields = [
{name: 'LoginForm[username]', value: user},
{name: 'LoginForm[password]', value: pass},
etc...
];
const data = translateFieldsToURLEncodedData(fields);
const headers = {
'Content-type': 'application/x-www-form-urlencoded',
Cookie: `PHPSESSID=${sessid}`, // HERE is where you put the data
};
const options = { method: 'POST',
headers: headers,
mode: 'cors',
cache: 'default',
agent: proxy,
body: data,
redirect: 'manual' // VERY IMPORTANT: if you don't do it, the cookie is lost
};
return new Request(LOGIN_URL, options);
}
// Simple utility function
function translateFieldsToURLEncodedData(fields){
let pairs = fields.map( (field) => {
return encodeURIComponent(field.name) + '=' + encodeURIComponent(field.value);
});
return pairs.join('&');
}
This is the last part. To see if I was logged in I checked if the response had text belonging to login error's page. I also got the PHPSessid (I think it changed after login, not sure, it was a year ago) but I don't know if I used it, I believe it was included automatically in subsequent requests. I think this part could be simplified an improved:
function checkIfLoggedAndGetSessionID(response) {
return (
checkIfLoggedOK(response)
.then(() => getSessionIDFromResponse(response))
);
}
function checkIfLoggedOK(response){
return getTextFromResponse(response)
.then(throwErrorIfNotLogedOk);
}
function getTextFromResponse(response) {
return response.text();
}
function throwErrorIfNotLogedOk(page) {
if(isErrorPage(page)) throw new Error("Login failed");
}
function isErrorPage(text) {
const ERROR_MESSAGE = 'Something that appears in login failed page of your site';
let n = text.search(ERROR_MESSAGE);
return n !== -1;
}
Hope this can be useful.

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!

Returning result from nested anonymous function in a hubot script

Having never worked with coffescript before, I'm trying to update the hubot script for jenkins integration. In a nutshell I want to call jenkins, get a result from that call and use it in a subsequent call. Based on the existing code in the hubot script I've added the following function:
jenkinsCrumb = (msg) ->
url = process.env.HUBOT_JENKINS_URL
path = "#{url}/crumbIssuer/api/json"
req = msg.http(path)
if process.env.HUBOT_JENKINS_AUTH
auth = new Buffer(process.env.HUBOT_JENKINS_AUTH).toString('base64')
req.headers Authorization: "Basic #{auth}"
req.get() (err, res, body) ->
if err
msg.reply "Jenkins says: #{err}"
else if 200 <= res.statusCode < 400 # Or, not an error code.
msg.reply "#{body}"
body
else if 404 == res.statusCode
msg.reply "Unable to fetch crumb from Jenkins..."
else
msg.reply "Jenkins says: Status #{res.statusCode} #{body}"
When this function is called, the value I want is reported in the variable body. The call to msg.reply properly displays the value in the hubot chat window.
What I would like to do, but can't figure out, is how to have this function return the value of body? I've tried explicitly returning the value of req.get() but it seems that it's returning the full request object.
You can do that by simply adding return body or just body (because of CoffeeScript) to the end of your anonymous function:
jenkinsCrumb = (msg, callback) ->
url = process.env.HUBOT_JENKINS_URL
path = "#{url}/crumbIssuer/api/json"
req = msg.http(path)
if process.env.HUBOT_JENKINS_AUTH
auth = new Buffer(process.env.HUBOT_JENKINS_AUTH).toString('base64')
req.headers Authorization: "Basic #{auth}"
req.get() (err, res, body) ->
if err
msg.reply "Jenkins says: #{err}"
else if 200 <= res.statusCode < 400 # Or, not an error code.
msg.reply "#{body}"
body
else if 404 == res.statusCode
msg.reply "Unable to fetch crumb from Jenkins..."
else
msg.reply "Jenkins says: Status #{res.statusCode} #{body}"
# critical part
callback(body)