I would like to consume a REST service in Node.js using request.js, as follows:
var request = require('request');
request.get({
url: 'https://www.googleapis.com/storage/v1/b',
auth: {
'bearer': 'oauth2_token'
}
}, function(err, res) {
console.log(res.body);
});
However, I would like to specify also a set of request parameters, such as project, prefix, etc. (as specified at https://cloud.google.com/storage/docs/json_api/v1/buckets/list).
How can I pass these parameters in the request for consuming the API service?
You can pass in qs as the additional queries. See example below:
const queryObject = { project: 'project', prefix: 'prefix' };
request.get({
url: 'https://www.googleapis.com/storage/v1/b',
qs: queryObject,
auth: {
'bearer': "oauth2_token"
}
}, function(err, res) {
console.log(res.body);
});
See here for github issue.
Related
I have a node.js application served over https. I would like to call an API from that application. The API is also served over https and it has been generated using the express-generator.
Unfortunately the call never works. There is no error message. The call never reaches the API.
Strangely enough if I try to call another public API (e.g. https://api.publicapis.org/entries') that is working perfectly.
Here is my call:
const requestBody = {
'querystring': searchQuery,
};
const options = {
rejectUnauthorized: false,
keepAlive: false, // switch to true if you're making a lot of calls from this client
};
return new Promise(function (resolve, reject) {
const sslConfiguredAgent = new https.Agent(options);
const requestOptions = {
method: 'POST',
body: JSON.stringify(requestBody),
agent: sslConfiguredAgent,
redirect: 'follow',
};
fetch('https://192.168.112.34:3003/search', requestOptions)
.then(response => response.text())
.then(result => resolve(result))
.catch(error => console.log('error', error));
});
};
And here is the API which I would like to call:
router.post('/', cors(), async function(req, res, next) {
req.body;
queryString = req.body.querystring;
let data = JSON.stringify({
"query": {
"match": {
"phonetic": {
"query": queryString,
"fuzziness": "AUTO",
"operator": "and"
}
}
}
});
const { body } = await client.search({
index: 'phoneticindex',
body: data
});
res.send(body.hits.hits)
});
What is wrong with my API and/or the way I am trying to communicate with it?
UPDATE: I receive the following error in the fetch catch block: 'TypeError: Failed to fetch'
When I create a request in Postman I receive the expected response.
UPDATE 2: This is most probably an SSL related issue. The webapp is expecting an API with a valid certificate. Obviously my API can only have a self signed cert which is not enough here. How can I generate a valid cert for an API which is running on the local network and not publicly available?
UPDATE 3: I managed to make it work by changing the fetch parameters like this:
fetch(url, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
mode: 'cors',
body: raw,
agent: httpsAgent,
redirect: 'follow',
})
and on the API side I added the following headers:
'Content-Type': 'application/json',
'Access-Control-Allow-Origin' : 'https://localhost:2200',
'Access-Control-Allow-Methods' : 'POST',
'Access-Control-Allow-Headers' : 'Content-Type, Authorization'
I also added app.use(cors()) and regenerated the self-signed certificates.
I trying to write node function to call third party API . I using the angular Fire Function for display the results in angular project. The issues is no data response;
Here is my node js code.
const request = require('request');
const UserDetail = () => {
const options ={
url: 'https://www.reddit.com/r/funny.json',
method: 'GET',
headers: {
'Accept': 'application/json',
'Accept-Charset': 'utf-8',
'User-Agent': 'my-reddit-client'
}
}
request(options, function(err, res, body) {
let json = JSON.parse(body);
console.log(json);
});
}
UserDetail();
Here is my firebase function code:
exports.userdetails = functions.https.onRequest(require('./api/user/userdetail'));
Here is my angular service calling firebase function code:
callUserDetails(){
const details = this.functions.httpsCallable('userdetails')({ text: 'Some Request Data' })
.pipe()
.subscribe(resp => {
console.log({ resp });
}, err => {
console.error({ err });
});
}
You are mixing up Callable Cloud Functions and HTTPS Cloud Functions.
By doing
exports.userdetails = functions.https.onRequest(...)
you define an HTTPS Cloud Function,
but by doing
this.functions.httpsCallable('userdetails')({ text: 'Some Request Data' })
in your front-end, you actually call a Callable Cloud Function.
You should either change your Cloud Function to a Callable one, or call the userdetails HTTPS Cloud Function by sending an HTTP Request to the Cloud Function URL.
I would advise the first approach because Callable brings several advantages over a "simmple" HTTPS one (see the doc).
In addition you need to note that request supports callback interfaces natively but does not return a Promise. And it is necessary to use Promises in order to manage the life cycle of a Callable Cloud Function (see the official video serie).
I would use Axios along the following lines (untested):
exports.userdetails = functions.https.onCall(async (data, context) => {
try {
const options = {
url: 'https://www.reddit.com/r/funny.json',
method: 'get',
headers: {
'Accept': 'application/json',
'Accept-Charset': 'utf-8',
'User-Agent': 'my-reddit-client'
}
}
const axiosResponse = await axios(options);
// Build the resp to be sent to the frontend by
// using axiosResponse.data .... up to you, see https://github.com/axios/axios#response-schema
return { resp: .... }
} catch (error) {
// See https://firebase.google.com/docs/functions/callable#handle_errors
}
});
Maybe you should call angular service like this:
// provider class
constructor(private http: HttpClient) {}
this.http.get(url, {params: {}, headers: {}}).subscribe(result => {
//// result
})
Following curl API is successfully deploying .zip file from the local file system into the Azure Function APP.
curl -X POST -u user123:P#ssword --data-binary #"C:\Ddrive\Porject\deploy-zip\wb-uc-code.zip" "https://abc-world.scm.azurewebsites.net/api/zipdeploy"
But I wanna achieve the same with NodeJs: So I converted it as -
function () {
var dataString = "#C:\Ddrive\Workbench\deploy-zip\wb-uc1.zip";
var options = {
url: 'https://abc-world.scm.azurewebsites.net/api/zipdeploy',
method: 'POST',
body: dataString,
auth: {
'user': 'user123',
'pass': 'P#ssword'
}
};
request.post(options, (response, error) => {
if (error) {
console.log("error");
}
else {
console.log(response.body);
}
})
}
while executing am getting error:
------->>>
Most Probably I think am unable to provide file-path appropriately in Options. Can someone help with this?
There are two things you need to pay attention to.
1.You should pass data-binary, you were passing path string in your code.
2.The order of response and error is reversed.
Please refer to the working code as below.
var request=require('request')
var fs = require("fs")
var dataString=fs.createReadStream("D:\\testProject\\NodeJs\\nodejs-docs-hello-world\\test4.zip");
var options = {
url: 'https://tonytestwebnode.scm.azurewebsites.net/api/zipdeploy',
method: 'POST',
body: dataString,
auth: {
'user': 'tonytestweb',
'pass': 'XXXX!'
}
};
request.post(options, (error, response) => {
console.log(response.statusCode);
})
I have an API Server and NodeJs Server and when a file is requested NodeJs redirected the request to API Server
API Server Send the File as raw data to NodeJs
and Nodejs redirects the file to the browser
But when I checked the network data using wire shark the packet received at browser is not original as that from API Server (work in case of text files, but not in image, video, pdf, doc etc)
router.get('/GetCaseSupportDocument', function (req, res) {
var MyJsonData = {
DocId:parseInt(req.query.DocId) || 0
};
request({
url: 'http://somedomain/someurl', //URL to hit
method: 'POST',
json: MyJsonData
}, function (error, response, body) {
if (error) {
res.status(200).send('Failed');
} else {
res.status(200).send(body);
}
})
});
Can anyone tell why it changes between NodeJs to Browser?
Is there any better solution for this type of transmission?
Updated After finding solution . This works
router.get('/GetCaseSupportDocument', function (req, res) {
var MyJsonData = {
DocId:parseInt(req.query.DocId) || 0
};
request({
url: Url.CaseService + 'GetCaseSupportDocument', //URL to hit
method: 'POST',
json: MyJsonData
}).pipe(res);
})
There is a simple proxy using streams that you can try:
router.get('/GetCaseSupportDocument', function (req, res) {
var MyJsonData = {
DocId: parseInt(req.query.DocId) || 0
};
// updated the response
request({
url: 'http://somedomain/someurl', //URL to hit
method: 'POST',
json: MyJsonData
}).pipe(res);
});
More details with proxy-ing you can find on the request documentation https://github.com/request/request
I try to use the node-soap module like this:
const soap = require('soap');
soap.createClient('some-wsdl-url', function(err, client) {
const args = {
'ValidateCustomerRequest': {
'memberNumber': 12345
}
};
client.ValidateCustomer(args, function(err, result) {
console.log(result);
});
});
Now I get an "invalid format" response from the webservice. To debug this I would very much like to see what the actual XML looks like that is sent to the webservice.
I already tried this one:
require('request').debug = true
... which was suggestes in another SO answer.
But the output is not that helpful:
[ERROR] REQUEST { uri:
Url { ... },
method: 'GET',
headers:
{ 'User-Agent': 'node-soap/0.18.0',
Accept: 'text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'none',
'Accept-Charset': 'utf-8',
Connection: 'close',
Host: 'xxx' },
followAllRedirects: true,
body: null,
callback: [Function] }
I don't see my "ValidateCustomerRequest" in there and body is null. Also I'm wondering why method is GET, shouldn't that be POST?
So does this debug output looks normal and/or is there another way to see the created XML request?
I overlooked this bit of the documentation:
Client.lastRequest - the property that contains last full soap request for client logging
You can log this within the callback of the webservice call. So above code will look like this:
const soap = require('soap');
soap.createClient('some-wsdl-url', function(err, client) {
const args = {
'ValidateCustomerRequest': {
'memberNumber': 12345
}
};
client.ValidateCustomer(args, function(err, result) {
console.log(result);
console.log('last request: ', client.lastRequest) // <-- here
});
});
This will output the generated XML request.