How to get the equivalent nodejs Requst to CURL command? - node.js

I have following CURL command
curl -u YOUR_API_KEY:x \
-H 'Content-Type: application/json' \
-X POST \
-d '{"first_name":"Tony", "kind":"person", "contact_name":"Stark"}' \
'https://ACCOUNT_NAME.quadernoapp.com/api/contacts.json'
I want do this request in NodeJS using the request module.
This is the code I have written.
var options = {
uri: 'https://ACCOUNT_NAME.quadernoapp.com/api/contacts.json',
json: true,
auth: {
user: 'YOUR_API_KEY'
}
data: {"first_name" : "Tonsdfasdy", "kind":"peasdfarson", "contact_name":"Staasdfadfadrk"}
}
request.post(options, function cb(){})
But it is not authenticatd properly. What is the error here?

You're authenticating using HTTP Basic authentication in your cURL command, where username and password are provided with the -u option and separated by :, so you need to provide your code with the password, like so :
var options = {
uri: 'https://ACCOUNT_NAME.quadernoapp.com/api/contacts.json',
json: true,
auth: {
user: 'YOUR_API_KEY',
password: 'x'
},
body: {
first_name : "Tonsdfasdy", kind:"peasdfarson", contact_name:"Staasdfadfadrk"
}
}
request.post(options, function cb(){})
And please try to pass your JSON object in an attribute named body rather than data (it will be transformed to a JSON string thanks to the json: trueoption).
You may also want to check this one : how to do Auth in node.js client
Hope this helps!

Related

Send message with Google Business Messages using access token

Currently I can send a message with Google Business Messages API from an agent to a user from NodeJS code.
const bmApi = new businessmessages.businessmessages_v1.Businessmessages({});
This requires an auth client for a given service account key/secret.
const auth = new GoogleAuth({
keyFilename: '/home/my-keyfile.json',
scopes: 'https://www.googleapis.com/auth/businessmessages',
});
const authClient = await auth.getClient();
// and logic to send message
However the key/secret is hard-coded at the moment.
But at this point in the flow I have the access token.
And want to use that instead of the .json file.
But it will not accept the access token.
Another approach is to directly call the REST interface.
https://developers.google.com/business-communications/business-messages/guides/how-to/message/send
curl -X POST https://businessmessages.googleapis.com/v1/conversations/__CONVERSATION_ID__/messages \
-H "Content-Type: application/json" \
-H "User-Agent: curl/business-messages" \
-H "$(oauth2l header --json ./service_account_key.json businessmessages)" \
-d "{
'messageId': '$(uuidgen)',
'text': 'Hello world!',
'representative': {
'avatarImage': 'https://developers.google.com/identity/images/g-logo.png',
'displayName': 'Chatbot',
'representativeType': 'BOT'
}
}"
Added a header with token.
access_token: <access-token>
But again no joy.
{
"error": {
"code": 401,
"message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
I know this should work as we do it for calls to Google Play Store:
try {
let response = await this.httpClient.post({
url: `${process.env.PLAYSTORE_URL}/${packageName}/reviews/${reviewId}:reply`,
body : {
"replyText" : replyText
},
query: {
access_token: access_token <----
}
});
Any help would be much appreciated.
i think you need to use the variable that match the current CONVERSATION_ID in the url path, with the currently one of each agent message received.
Example:
curl -X POST https://businessmessages.googleapis.com/v1/conversations/$(uuidgen)/messages \
-H "Content-Type: application/json" \
-H "User-Agent: curl/business-messages" \
-H "$(oauth2l header --json ./service_account_key.json businessmessages)" \
-d "{
'messageId': '$(uuidgen)',
'text': 'Hello world!',
'representative': {
'avatarImage': 'https://developers.google.com/identity/images/g-logo.png',
'displayName': 'Chatbot',
'representativeType': 'BOT'
}
}"

Axios Basic Auth with API key Example in Node

There is a curl request like this:
curl -X GET --header 'Accept: application/json' --header 'Authorization: Basic [==APIKEYHERE==]' 'https://apipath.com/path?verbose=true'
I removed the APIKEY and the API path for privacy.
The curl request is working fine, I can't figure out how to convert this into an Axios request since it only needs an API key and not a username and password.
Here is the example I found:
axios.get('https://apipath.com/path?verbose=true', {}, {auth: {username: 'username', password: 'password'}})
.then(function(response) {
console.log(response.data, 'api response');
})
I'm not sure how to get this to work for my case?
The short answer to adding an X-Api-Key to an http request with axios can be summed up with the following example:
const url =
"https://someweirdawssubdomain.execute-api.us-east-9.amazonaws.com/prod/custom-endpoint";
const config = {
headers: {
"Content-Type": "application/json",
},
};
// Add Your Key Here!!!
axios.defaults.headers.common = {
"X-API-Key": "******this_is_a_secret_api_key**********",
};
const smsD = await axios({
method: "post",
url: url,
data: {
message: "Some message to a lonely_server",
},
config,
});
I was stuck for 8 hours trying to figure this out as the errors lined up in the queue, adding the key to the default headers was the only way I could get this to work.
Given the cURL command including --header 'Authorization: Basic [==APIKEYHERE==]', you know that the server wants a header sent using the Basic authentication scheme. That means that your API key is both the username and password joined by a : and encoded with Base64. So, you can decode what the username and password should be by decoding your API key with Base64 and seeing the values joined by the colon.
Consider the spec detailed on MDN: Authorization Header
So if your API key is Ym9iOnBhc3N3b3JkMQ==, and you decode it with Buffer.from("API_KEY", "base64").toString(), you would get the value bob:password1 meaning your username is bob and your password is password1 making your request:
const [username, password] = Buffer.from("YOUR_API_KEY", "base64").toString().split(":");
axios.get('https://apipath.com/path?verbose=true', {}, {
auth: {
username,
password
}
})
.then(function(response) {
console.log(response.data, 'api response');
})
You can define a function like this, then you can pass the token to header after login success.
import axios from "axios";
const setAuthToken = token => {
if (token) {
// Apply to every request
axios.defaults.headers.common["Authorization"] = token;
} else {
// Delete auth header
delete axios.defaults.headers.common["Authorization"];
}
};
axios.get('https://apipath.com/path?verbose=true', {}, {auth: {username: 'username', password: 'password'}})
.then(() => setAuthToken(response.token));

URI encode query parameter in request

I want to replicate the below curl request in node using request module.
curl -X POST \
'https://control.msg91.com/api/sendotp.php?authkey=fdfdfdfdfdfd&mobile=%203456786444&message=Your%20OTPis%20456897&otp=456897' \
-H 'cache-control: no-cache'
How ever when I tried the below code where I have used qs object to send the query parameters seems the + in mobile number is not uri encoded as above. How can I achieve this. Is qs is not the right parameter ? I have also tried using form .
My node code
var request = require('request');
request.post(
{
url:'https://control.msg91.com/api/sendotp.php',
headers: {
'content-type': 'application/json'
},
qs : {
authkey:'fdfdfdfdfdfd',
message:'Your OTP is 456789',
mobile :'+3456786444',
otp: '456789'
}}, function(err,httpResponse,body){
console.log(err);
});

--data-urlencode curl to Node.js request or express module

I am trying to transform this curl command
curl '<url>' -X POST \
--data-urlencode 'To=<phone>' \
--data-urlencode 'From=<phone>' \
--data-urlencode 'Body=<message>' \
-u '<user>:<pass>'
into this Node.js code
var request = require('request');
var options = {
url: 'url',
method: 'POST',
auth: {
'user': 'user',
'pass': 'pass'
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
}
request(options, callback);
I don't get how I can add the --data-urlencode option in the Node.js version of this code.
From curl documentation :
--data-urlencode
(HTTP) This posts data, similar to the other -d, --data options with
the exception that this performs URL-encoding.
So you would use form option to send form URL encoded like this :
var options = {
url: 'url',
method: 'POST',
auth: {
'user': 'user',
'pass': 'pass'
},
form: {
To: 'phone',
From: 'phone',
Body: 'message'
},
headers: {
'Accept': '*/*'
}
};
Note that you can use request-debug to show the actual request where you could check that body is :
To=phone&From=phone&Body=message
And to show the actual data sent by curl use as stated here, use --trace-ascii /dev/stdout :
curl '<url>' -X POST --data-urlencode "Body=<message>" -u <user>:<pass> --trace-ascii /dev/stdout

How to attach files to POST request to Mailgun's API using Node.js and the Request library

I'm writing some code to send emails with attachments through the Mailgun email service. They give the following example in their API docs using CURL and I need to figure out how to do the same thing in Node.js (preferably using the Request library).
curl -s -k --user api:key-3ax6xnjp29jd6fds4gc373sgvjxteol0 \
https://api.mailgun.net/v2/samples.mailgun.org/messages \
-F from='Excited User <me#samples.mailgun.org>' \
-F to='obukhov.sergey.nickolayevich#yandex.ru' \
-F cc='sergeyo#profista.com' \
-F bcc='serobnic#mail.ru' \
-F subject='Hello' \
-F text='Testing some Mailgun awesomness!' \
-F html='\<html\>HTML version of the body\<\html>' \
-F attachment=#files/cartman.jpg \
-F attachment=#files/cartman.png
My current code (Coffescript) looks like the following:
r = request(
url: mailgun_uri
method: 'POST'
headers:
'content-type': 'application/x-www-form-urlencoded'
body: email
(error, response, body) ->
console.log response.statusCode
console.log body
)
form = r.form()
for attachment in attachments
form.append('attachment', fs.createReadStream(attachment.path))
For the basic authorization part you have to set the right headers and send username and password base64 encoded. See this SO question for more information. You can use the headers option for this.
How to send a POST request with form fields is described in the request docs:
var r = request.post('http://service.com/upload')
var form = r.form()
form.append('from', 'Excited User <me#samples.mailgun.org>') // taken from your code
form.append('my_buffer', new Buffer([1, 2, 3]))
form.append('my_file', fs.createReadStream(path.join(__dirname, 'doodle.png')) // for your cartman files
form.append('remote_file', request('http://google.com/doodle.png'))
There also some existing modules on npm that support mailgun, like
node-mailgun
nodemailer (awesome module!)
an example for nodemailer would be
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Mailgun", // sets automatically host, port and connection security settings
auth: {
user: "api",
pass: "key-3ax6xnjp29jd6fds4gc373sgvjxteol0"
}
});
var mailOptions = {
from: "me#tr.ee",
to: "me#tr.ee",
subject: "Hello world!",
text: "Plaintext body",
attachments: [
{ // file on disk as an attachment
fileName: "text3.txt",
filePath: "/path/to/file.txt" // stream this file
},
{ // stream as an attachment
fileName: "text4.txt",
streamSource: fs.createReadStream("file.txt")
},
]
}
transport.sendMail(mailOptions, function(err, res) {
if (err) console.log(err);
console.log('done');
});
Haven't tested it because I don't have a mailgun account but it should work.

Resources