I am trying to make a POST request to Expo's servers using the request library for JS.
Expo requires that certain headers be added, and so I went ahead and added them in a dictionary called headers.
expoPushURL = "https://exp.host/--/api/v2/push/send";
headers = {
"accept": "application/json",
"accept-encoding": "gzip, deflate",
"content-type": "application/json"
};
data = JSON.stringify({
"to": "ExponentPushToken[myDeviceToken]",
"sound": "default",
"title": "hello",
"body": "Hello world!"
});
options = {
url: expoPushURL,
headers: headers,
method: "POST",
body: data,
json: true
};
request(options, function (error, response, body) {
console.log("Response from request: ",response);
console.log("Error from request: ", error);
});
The callback is returning an undefined object. The request module has been imported without any problems. What am I doing wrong?
I am getting this error message:
Error from request: { Error: getaddrinfo ENOTFOUND exp.host exp.host:443
at errnoException (dns.js:28:10)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:76:26)
code: 'ENOTFOUND',
errno: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'exp.host',
host: 'exp.host',
port: 443 }
These "settings" or parameters work perfectly fine when I use curl or Python's requests library, but I need this solution to be in JS. With that said, I am sure that means there is something wrong with my code.
EDIT: The related curl would look like this:
curl -H "Content-Type: application/json" -X POST https://exp.host/--/api/v2/push/send -d '{
"to": "ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]",
"title":"hello",
"body": "world"
}'
You do not have problem with headers, they are working correctly, something else is missing. What is your curl?
I have run your code against my dummy server, which returns in body all interesting values that he accepted. With this code
const expoPushURL = "http://localhost:3099";
const headers = {
"accept": "application/json",
"accept-encoding": "gzip, deflate",
"content-type": "application/json"
};
const data = JSON.stringify({
"to": "ExponentPushToken[myDeviceToken]",
"sound": "default",
"title": "hello",
"body": "Hello world!"
});
const options = {
url: expoPushURL,
headers: headers,
method: "POST",
body: data,
json: true
};
import * as request from 'request';
request(options, function (error, response, body) {
console.log(body.received);
});
I got this response
{ body: '"{\\"to\\":\\"ExponentPushToken[myDeviceToken]\\",\\"sound\\":\\"default\\",\\"title\\":\\"hello\\",\\"body\\":\\"Hello world!\\"}"',
method: 'POST',
headers:
{ accept: 'application/json',
'accept-encoding': 'gzip, deflate',
'content-type': 'application/json',
host: 'localhost:3099',
'content-length': '115',
connection: 'close' },
url: '/' }
If someone would be just interested, the server I am using is having this code
const http = require('http');
const _ = require('lodash');
http.createServer((request, response) => {
const { headers, method, url } = request;
let body = [];
request.on('error', (err) => {
console.error(err);
}).on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
let bodyToSend = JSON.stringify({
alwaysHere: 'Always here',
received: {
body,
method,
headers,
url,
}
});
if (body) {
body = JSON.parse(body);
if (body && _.isObject(body.control)) {
const control = body.control;
if (_.isNumber(control.statusCode)) {
response.statusCode = control.statusCode;
}
if (_.isArray(control.headers)) {
control.headers.forEach(header => {
response.setHeader(header.name, header.value);
});
}
if (_.isString(control.body)) {
bodyToSend = control.body;
}
}
}
if (!response.hasHeader('content-type')) {
response.setHeader('Content-Type', 'application/json');
}
response.write(bodyToSend); // write a response to the client
response.end(); // end the response
});
}).listen(3099);
Related
Hello I have tried to use the instagram api to get a connection token. I first tested it on postman and this is what I did:
I used this link to make a request post to the instagram api:
https://api.instagram.com/oauth/access_token?client_id=clientid&client_secret=clientsecret&grant_type=authorization_code&redirect_uri=https://mysite/&code=thecode
The api gives me an error: Missing required field client_id
But when I set the content type to x-www-form-urlencoded everything works fine on postman.
So I tried to do the same thing in javascript with the node module request. I tried to do the same thing as on postman with the module but it does not work... Here is my code:
request(`https://api.instagram.com/oauth/access_token?client_id=clientid&client_secret=clientsecret&grant_type=authorization_code&redirect_uri=https://mysite/&code=` + code, {
method: 'POST',
headers: {"Content-Type": "x-www-form-urlencoded"}
}, (error, response, body) => {
console.log('body:', body)
})
As per MDN, the content type should be application/x-www-form-urlencoded
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
Update:
You should read the node doc : https://nodejs.dev/learn/making-http-requests-with-nodejs
Get method:
const https = require('https');
const options = {
hostname: 'api.instagram.com',
path: '/oauth/access_token?client_id=clientid&client_secret=clientsecret&grant_type=authorization_code&redirect_uri=https://mysite/&code=thecode',
method: 'GET',
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "Accept-Encoding"
}
};
const req = https.request(options, (res) => {
// ...
});
Post method:
var headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "Accept-Encoding"
};
var options = {
url: 'https://api.instagram.com/oauth/access_token',
method: 'POST',
headers: headers
};
var form = {
grant_type:'urn:ietf:params:oauth:grant-type:jwt-bearer',
client_id: 'id',
client_secret: 'secret'
redirect_uri : 'https://mysite/&code=thecode'
};
var request = https.request(options, function(response) {
// do stuff
});
request.write(querystring.stringify(form));
request.end();
I am trying to use the tiny.cc REST API from Node, but seem to be hitting an issue since the Server always responds with a message 'Missing input parameters'.
var message = JSON.stringify({
"urls": [
{
"long_url": "http://example.com",
}
]
});
var https_options = {
host: 'tinycc.com',
path: '/tiny/api/3/urls/',
port: 443,
method: 'POST',
headers: {
'Authorization': 'Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
'Content-Length': message.length
}
}
var req = https.request(https_options,res => {
var msg = '';
res.on('data',d => msg += d);
res.on('end',() => {
console.log('end',JSON.parse(msg));
});
});
req.on('error',e => console.log('tinyURL error',e));
req.write(message);
req.end();
The response is always
{
error: {
code: 1305,
message: 'Missing input parameters',
details: ''
},
version: '3.1'
}
I don't know which library are you using for making the API call, but I think you will be better using request and including your payload as the body on your post request rather than using the more manual method of writing to the request.
var message = {
"urls": [
{
"long_url": "http://example.com",
}
]
};
var options = {
host: 'tinycc.com',
path: '/tiny/api/3/urls/',
port: 443,
method: 'POST',
body: message,
json: true,
headers: {
'Authorization': 'Basic XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
'Content-Length': message.length,
"Content-Type": "application/json"
}
}
request(options, console.log)
I'm trying to get a response back from an API by sending the token and the header 'content-type': 'application/json', but I don't know where should I put them.
This is my code so far:
var request = require('request');
request.get('google example url', {
//
'auth': {
'bearer': '15252727282'
},
"headers": {
"Content-Type": "application/json"
}
}, function (error, response, body) {
console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body);
});
This is what I'm getting back in my console:
error: null
statusCode: 401
body: HTTP Token: Access denied.
OK I did it using options as the first parameter and with the following lines:
const options = {
url: 'target url',
method: 'GET',
headers: {
"Authorization": "Token token=12425262",
"Content-type": "application/json"
}
};
request(options, function(err, res, body) {
let json = JSON.parse(body);
console.log(json);
});
You're getting that error because you have never defined require anywhere on your client-side.
Add this to your project: http://requirejs.org/docs/release/2.2.0/minified/require.js
If you want to use require on the client take a look at this http://requirejs.org/.
I'm trying to build a request for uClassify API from Node. I can't figure out what is wrong with the code I've written:
const req = JSON.stringify('Hello, my love!');
const options = {
body: req,
method: 'POST',
url: 'https://api.uclassify.com/v1/uClassify/Sentiment/classify',
headers: {
'Content-Type': 'application/json',
Authorization: 'MyKey'
}
};
request(options, (error, response, body) => {
if (!error) {
callback(response);
}
});
I get the following response:
statusCode: 400,
body: "{"statusCode":400,
"message": "Error converting value \"Hello, my love!\" to
type 'UClassify.RestClient.TextPayload'. Path '', line 1, position 17."}"
}"
There's no clear instruction for JS in the documentation, and I wonder whether I've implemented their example in cURL correctly in my request code.
url -X POST -H "Authorization:Token YOUR_READ_API_KEY_HERE" -H
"Content-Type: application/json" --data "{\"texts\":[\"I am so happy
today\"]}" https://api.uclassify.com/v1/uClassify/Sentiment/classify
In your Node.js code your body is incorrect (but in your cURL you use the correct body). uClassify expects the object with property texts.
Change the body in your node.js code so:
const req = JSON.stringify({ texts: ['Hello, my love!'] });
const options = {
body: req,
method: 'POST',
url: 'https://api.uclassify.com/v1/uClassify/Sentiment/classify',
headers: {
'Content-Type': 'application/json',
Authorization: 'MyKey'
}
};
request(options, (error, response, body) => {
if (!error) {
callback(response);
}
});
I have this function and the below data which is passed into this function returns a ECONNRESET, socket hang up error. However, when the discountCode array is reduced to like only 10 objects, it can POST without any problem.
What could the cause for this problem? I tried to do multiple req.write() by segmenting the data in Buffer, however that doesn't work out well. Any NodeJs ninja could give some insights to this problem?
createObj: function(data, address, port, callback) {
//console.log('Create Reward: '+JSON.stringify(data));
var post_data = JSON.stringify(data);
var pathName = '/me/api/v1/yyy/'+data.idBusinessClient+'/newObj';
//
var options = {
hostname: address,
port: port,
path: pathName,
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Accept': 'application/json',
'Accept-Encoding': 'gzip,deflate,sdch',
'Accept-Language': 'en-US,en;q=0.8'
}
};
// http call to REST API server
var req = restHttp.request(options, function(res) {
console.log('HTTP API server PUT Reward response received.');
var resData = '';
res.on('data', function(replyData) {
// Check reply data for error.
console.log(replyData.toString('utf8'));
if(replyData !== 'undefined')
resData += replyData;
});
res.on('end', function() {
//<TODO>Process the data</TODO>
callback(JSON.parse(resData));
});
});
req.write(post_data);
req.end();
console.log('write end');
req.on('close', function() {
console.log('connection closed!');
});
req.on('error', function(err) {
console.log('http request error : '+err);
callback({'error':err});
throw err;
});
req.on('socket', function(socket) {
console.log('socket size:'+socket.bufferSize);
socket.on('data', function(data) {
console.log('socket data:'+data);
});
});
}
]}`
I had the same problem and was able to resolve it by adding a Content-Length header:
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Content-Length': Buffer.byteLength(post_data),
'Accept': 'application/json',
'Accept-Encoding': 'gzip,deflate,sdch',
'Accept-Language': 'en-US,en;q=0.8'
}
However, I still have no clear idea why a missing Content-Length header causes such a trouble. I assume it's some kind of weirdness in the internal Node.js code. Maybe you can even call it a bug, but I'm not sure about that ;)
PS: I'm absolutely interested more information about the cause of this problem. So please leave a comment if you have any idea...
When you change the content of response for sure you need also to update on header the content length:
headers: {
...
'Content-Length': Buffer.byteLength(post_data),
...
}
But i run on this problem also when i try to make multiple request and seems that this is not well managed on different library so a workaround that i have found if this problem persist is to add on headers:
headers: {
...
connection: 'Close'
...
}
So if you are making request on different servers.. this close the connection after finish the process. This worked for me in net, node-http-proxy.
If Express and http-proxy-middleware is used to make the POST call, and some body parser middleware is used like express.json(), the request interceptor fixRequestBody must be used (more info). Otherwise the POST call will hang with the ECONNRESET error.
const express = require('express');
const { createProxyMiddleware, fixRequestBody } = require('http-proxy-middleware');
const app = express();
app.use(express.json());
app.post(
'/path',
createProxyMiddleware('/path', {
target: API_URL,
changeOrigin: true,
pathRewrite: (path, req) => `/something/${req?.body?.someParameter}`,
onProxyReq: fixRequestBody // <- Add this line
});
Had the same problem. The solution for me was to append it to the proxy for it to work. If you're not using a proxy, you can probably just append it to the post request itself.
With proxy:
import express from 'express';
import { createProxyMiddleware } from 'http-proxy-middleware';
import logger from './logger';
// setup routes
server.get('/isAlive', (req, res) => res.send('Alive'));
server.get('/isReady', (req, res) => res.send('Ready'));
server.use(express.static(path.join(__dirname, '../build')));
const restream = (proxyReq, req, res, options) => {
if (req.body) {
let bodyData = JSON.stringify(req.body);
proxyReq.setHeader('Content-Type', 'application/json');
proxyReq.setHeader('Content-Length', Buffer.byteLength(bodyData));
proxyReq.write(bodyData);
}
};
server.use(
'/api',
createProxyMiddleware({
target: 'http://your-backendUrl-api',
onProxyReq: restream,
changeOrigin: true,
proxyTimeout: 30000,
secure: true,
logLevel: 'info',
onError: (err, req, res) => {
logger.error('error in proxy', err, req, res);
},
})
);
E.g without proxy:
import axios, { AxiosResponse } from 'axios';
const api = axios.create({
baseURL: '/api/....',
timeout: 35000,
withCredentials: true,
headers: { Pragma: 'no-cache', 'Cache-Control': 'no-cache' },
validateStatus: (status) => status < 400,
});
const response = await api.post(
`/somepath/${exampleInjectedId}/somepathToRestAPI`,
{
...payload
},
{
baseURL: '/api/...',
timeout: 35000,
withCredentials: true,
headers: {
Pragma: 'no-cache',
'Cache-Control': 'no-cache',
'Content-Length': Buffer.byteLength(
JSON.stringify({
...payload
})
),
},
validateStatus: (status) => status < 400,
}
);