I'm working on a side-project of mine which integrates with Twilio. It's a Node.js app running on the Hapi.js framework.
I have the app set up with Twilio so that when I text my Twilio number, Twilio gets the request from my app's route and texts me back with a static message in the response.
What I'm having trouble with is getting the SMS body from the user's text. Let's say that I text the Twilio number with a word like banana I want to be able to retrieve that from the request so that I can have a dynamic message based on it.
I've tried request.Body, request.message, among several other things, and I can't seem to retrieve the user's text to the Twilio number. I've looked through Twilio's documentation and can't seem to figure it out. I saw this PHP keyword tutorial on Twilio which looked promising, but even accessing request.Body as in that tutorial doesn't seem to work at all.
Does anyone know how to get the text body from a Twilio SMS that a user sends? Any and all help is appreciated
With Hapi, if you want to read all the request body into memory before running your handler you need to set the payload config:
server.route({
config: {
payload: {
output: 'data'
}
},
method: 'POST',
path: '/textMessage',
handler: function (request, reply) {
console.log('Body was', request.payload.toString());
reply('...');
}
});
From the Hapi API docs:
'data' - the incoming payload is read fully into memory. If parse is
true, the payload is parsed (JSON, form-decoded, multipart) based on
the 'Content-Type' header. If parse is false, the raw Buffer is
returned. This is the default value except when a proxy handler is
used.
More options here: http://hapijs.com/api#route-options
After trying different methods to retrieve the request payload from Twilio, I found that the Twilio request body can be accessed via request.url.query, and therefore, the Body of the text, can be retrieved via request.url.query.Body. Thanks for the help #MattHarrison!
Related
The npm-request library allows me to construct HTTP requests using a nice JSON-style syntax, like this.
request.post(
{
url: 'https://my.own.service/api/route',
formData: {
firstName: 'John',
lastName: 'Smith'
}
},
(err, response, body) => {
console.log(body)
}
);
But for troubleshooting, I really need to see the HTTP message body of the request as it would appear on the wire. Ideally I'm looking for a raw bytes representation with a Node.js Buffer object. It seems easy to get this for the response, but not the request. I'm particularly interested in multipart/form-data.
I've looked through the documentation and GitHub issues and can't figure it out.
Simplest way to do this is to start a netcat server on any port:
$ nc -l -p 8080
and change the URL to localhost in your code:
https://localhost:8080/v1beta1/text:synthesize?key=API_KEY
Now, any requests made will print the entire, raw HTTP message sent to the localhost server.
Obviously, you won't be able to see the response, but the entire raw request data will be available for you to inspect in the terminal you have netcat running
I figured out how to dump the HTTP message body with Request. In both cases, I'm just copying the same approach that request uses internally.
Multipart Form Uploads
req._form.pipe(process.stdout);
URL-encoded Forms
console.log(req.body);
You could try #jfriend00 suggestion an use a network sniffer like wireshark but as you're fetching an https URL this might not be the easiest route as it requires some setup to intercept TLS connections.
So maybe it would be enough turning on debug mode for the request module itself, you can do that by simply setting require('request').debug = true. As a third option you could go with the dedicated debug module for request here which allows you to view request and response headers and bodies.
I can think of a number of ways to see the bytes of the request:
Turn on debugging in the request module. There are multiple ways to do that documented here including setting NODE_DEBUG=request or require('request').debug = true or using the request-debug module.
Use a network sniffer to see what's actually being sent over the socket, independent of your node.js code.
Create your own dummy http server that does nothing but log the exact incoming request and send your same request to that dummy server so it can log it for you.
Create or use a proxy (like nginx) that can dump the exact incoming request before forwarding it on to its final destination and send the request to the proxy.
Step through the sending of the request in the debugger to see exactly what it is writing to the socket (this may be time consuming, particularly with async callbacks, but will eventually work).
you could use a nodejs server capable of logging the raw request/response string , then direct your request to that server
i gave an example using both http and https server - no dependencies
nodejs getting raw https request and response
Our React app sends a GET request to our API requesting a Twilio token. Out API then requests the token from Twilio. The token is then sent in the response back to the React app. The React app then executes Twilio.Device.setup(token, {debug: true}), and this appears to happen successfully.
The Twilio.Device.instance object appears to have the token retrieved from the server, and the token matches what the server responded with AND what the server prints to the logs.
We then call Twilio.Device.connect() which results in an error message to the console :
{"payload":{"callsid":"<SOME_ID>","error":{"code":31100,"message":"Bad JSON in msg"}},"type":"hangup","version":""}
Opening the Dev console I see this is all happening in a web socket connection, and the payload sent RIGHT before this message appears (and it is reliably sent immediately before the response, so I believe it is what triggers the error) is a payload of this form:
{
"type":"invite",
"version":"1.4",
"payload":{
"sdp":"v=0\r\no=- 436124720934282410 2 IN ... A BUNCH OF DATA WITH CARRIAGE RETURNS ... f-d0582b8dc5e6\r\n",
"callsid":"TJSceeec256-b343-4d13-bf26-febd73fcd484",
"twilio":{}
}}
So the payload.sdp attribute is definitely NOT Json, but it doesn't really look like it's even trying to be, so it's not some kinda typo.
The entire body of the request is properly formed JSON though, renders and pretty print.
So what do I need to do to start an outgoing call with the Twilio 1.4 JavaScript SDK? About a month ago the dev working on this was making calls successfully, so it's definitely possible, but I'm not sure what changed.
I'm getting the same error. Changing
Twilio.Device.connect();
to
Twilio.Device.connect({x:null});
helped me to get outgoing calls working.
I'm trying to access Medium's API to get a list of public stories from a user. However, I'm getting a CORS error when I try to access it on the client side. Here's the code
axios.get(`http://medium.com/#ev/latest`).then((res)=>{
console.log(res.data)
})
.catch((error)=>{
console.log(error)
})
I did some research and found this github issue, but couldn't find any workaround. Is there any way to make this request work on the client side?
You can get the HTML from https://medium.com/#ev/latest by making your request through a CORS proxy — either a proxy you set up yourself or else just by using a public open CORS proxy like https://cors-anywhere.herokuapp.com/. Here’s how to do it using the standard Fetch API:
fetch("https://cors-anywhere.herokuapp.com/https://medium.com/#ev/latest")
.then(res => res.text())
.then(text => document.querySelector("div").innerHTML = text)
.catch(error => console.log(error))
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div></div>
For more details — including how to set up your own CORS proxy on Heroku in just a few minutes, see How to use a CORS proxy to get around “No Access-Control-Allow-Origin header” problems in the answer at No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API.
Incidentally, if instead you want JSON, you can try https://medium.com/#ev/latest?format=json but you’ll find that what you get back isn’t actually valid JSON; instead it starts out like this:
])}while(1);</x>{"success":true,"payload":{"user":{"userId":"268314bb7e7e","name"…
Apparently that’s intentional, per a comment from a Medium developer in their issue tracker:
The JSON page is not intended to be used as a read API. The extra code is there to support our own use and is a standard technique to avoid JSON hijacking.
That’s trivial to work around, though: Just first handle the response as text in your client code, and strip out the ])}while(1);</x> from the start of it, and then run JSON.parse on what remains.
But as far as using Axios to get the response as text, I think you’ll find it’s not going to work as expected even if you make the request through a CORS proxy; try this:
axios.get('https://cors-anywhere.herokuapp.com/http://medium.com/#ev/latest', {
responseType: 'text'
})
.then(res => console.log(res.data))
.catch(error => console.log("ERROR"))
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
The code hits the catch because apparently even when you specify responseType: 'text', Axios apparently still tries the parse the response as JSON:
This is because JSON.parse is always tried in the response, even if responseType is text. We should fix that indeed.
And https://medium.com/#ev/latest is HTML, not JSON, so running JSON.parse on it will fail.
That’s why the first snippet in this answer uses the Fetch API instead (you can get text back with it).
This is currently not allowed by Medium (There server doesn't respond with the Access-Control-Allow-Origin header). Probably because of security concerns.
As suggested in the GitHub issue you linked to, a possible solution will be to tunnel the request to Medium through your server (as proxy). You can create an endpoint on your server (i.e. http://my-server.com/get-medium/#ev/latest) that will retrieve the requested Medium page (on the server side) and will return it to the client side.
This comment to the issue describes a way to do that using AWS Lambda as the proxy server - link
I'm trying to get information about videos hosted by Vimeo (from my client's channel, so no rights issues). I'm using Javascript, specifically d3.js.
The request works fine when using the old API, with this type of url :
http://vimeo.com/api/v2/video/video_id.output
For instance, this works in d3.js :
d3.json("http://vimeo.com/api/v2/video/123456789.json", function(error,data){
console.log(data);
}):
But I can't get the new API to work as easily in a simple request, using this type of url for instance :
https://api.vimeo.com/videos?links=https://vimeo.com/123456789
What do I need to do ? Authenticate ? If so, how ? I'd be grateful to get examples in either jQuery of d3.
Vimeo's API documentation is not the best, so you have to dig a little around to actually get the information you need. In your case, you do not need to go through the whole OAuth2 loop if you are simply requesting data from endpoints that do not require user authentication, such as retrieving metadata of videos, as per your use case.
First, you will need to create a new app, by going to https://developer.vimeo.com/apps:
You can simply generate a Personal access token from your Vimeo app page under the section that says Generate an Access Token:
Remember that this token will only be visible once (so copy it when it is generated): and you have to keep it secure! The access token should be part of the Authorization header's bearer token. If you are using cURL, it will look like this:
curl -H "Authorization: Bearer <YourPersonalAccessToken>" https://api.vimeo.com/videos/123456789
Therefore, while you can do the following on your page to retrieve video metadata on the clientside, note that you are actually exposing your private token to the world:
d3.json("https://api.vimeo.com/videos/123456789/")
.header("Authorization", "Bearer <YourPersonalAccessToken>")
.get(function(error, data) {
console.log(data);
});
However, I strongly recommend that you proxy this request through your own server, i.e. create a custom endpoint on your server, say /getVimeoVideoMetadata. This API endpoint will receive the video ID, and will add the secretly stored access token you have on your server before making the request. This will mask your access token from your website visitors.
I am working on express js and a particular endpoint renders the page using
res.render('dialog',{state:'admin'});
This endpoint is at http://localhost:3000/api/login. When i open this link in the browser, it opens the dialog.ejs page but when i call this endpoint using a GET request from another part of the server, the dialog.ejs page is not rendered
request({
url: 'http://localhost:3000/api/login',
headers:{
'Authorization' : auth
},
method: 'GET'
}, function(err, response, body) {
console.log("Response to request for authorization code : " + response.statusCode);
});
Please help !
Well, when you build a handmade request chances are that you're missing half of the headers the browser is sending, so that can be one of the reasons the whole thing is failing
On the other, if your making a machine to machine request, you DON'T want the ejs page renders, You only need to recover the neeeded data and /or make the server do something "as you were login in from a browser".
And as you're including the authorization Header, you're probably trying to simulate a login or authorization of some kind ( maybe a JWT Token ?)
Any case i think oyour only options is to mimic what your browser do as far as possible . So Build a perfectly correct set of headers, inject what will
be the result of form data, probably url_encoded, and use the correct request method (GET is perfectly correct, but coming from an html from POST is much more common. check it)
Just only one suggestion. Rendering a full web page from an /api/login seems a bit incorrect. Usually Api enpoints talk JSON only. In and out