Following the getting started documentation for Amplify Flutter REST API, the auto-generated POST request below for ExpressJS results in the following error:
SyntaxError: Unexpected token ' in JSON at position 1
at JSON.parse
The GET request returns fine, but when changing to POST and adding the body field below from the documentation the error is returned. How can a POST request be successfully called from Flutter using the Amplify REST API?
Flutter GET Request - (no error)
Future<void> callAPI() async {
try {
RestOptions options = RestOptions(
path: '/example',
apiName: 'ExpressJSRESTAPI'
);
RestOperation restOperation = Amplify.API.get(
restOptions: options
);
RestResponse response = await restOperation.response;
print('GET call succeeded');
print(new String.fromCharCodes(response.data));
} on ApiException catch (e) {
print('GET call failed: $e');
}
}
Flutter POST Request (throws error)
Future<void> callAPI() async {
try {
RestOptions options = RestOptions(
path: '/example',
body: Uint8List.fromList('{\'name\':\'Mow the lawn\'}'.codeUnits),
apiName: 'ExpressJSRESTAPI'
);
RestOperation restOperation = Amplify.API.post(
restOptions: options
);
RestResponse response = await restOperation.response;
print('POST call succeeded');
print(new String.fromCharCodes(response.data));
} on ApiException catch (e) {
print('POST call failed: $e');
}
}
ExpressJS GET request path
app.get('/example', function(req, res) {
// Add your code here
res.json({success: 'get call succeed!', url: req.url});
});
ExpressJS POST request path
app.post('/example', function(req, res) {
// Add your code here
res.json({success: 'post call succeed!', url: req.url, body: req.body})
});
From the documentation, notice the reverse slash (\) in your RestOptions' fromList arguments.
RestOptions options = RestOptions(
path: '/todo',
body: Uint8List.fromList('{\'name\':\'Mow the lawn\'}'.codeUnits)
);
Based on the github discussion here the issue happening due to unneeded escape character.
Change your body parameter to this:
body: Uint8List.fromList('{"name":"Mow the lawn now!"}'.codeUnits)
or
body: ascii.encode('{"name":"Mow the lawn"}')
I have an api which communicates with a third party service. This third party service uses two live server url's which it uses to asynchronously pass the actual response with of any kind of communication with the service - result and error back to my application using webhook. So I created a tunnel with ngrok and I also created two urls (http request listener i.e route) which receive the result/error from the service. Hence when I hit api 1, the actual response is passed in req.body to the listener 1 & 2. What now I need to figure out is if there is any way to pass this response from the webhook listener back to api 1, or if there is any way the async flow of my api 1 can keep going on by communicating directly with the webhook listener.
//Controller
const sendPaymentRequest = async (req, res) => {
try {
//Send payment request to 3rd party service
const endpoint = "/mpesa/b2c/v1/paymentrequest";
const url = MPESA_URL + endpoint;
const config = {
headers: {
Authorization: `Bearer ${access_token}`,
},
};
const body = {
Remarks: "Sending money from mobile wallet",
QueueTimeOutURL: "http://f815c811f619.ngrok.io/api/v1/b2c/error",
ResultURL: "http://f815c811f619.ngrok.io/api/v1/b2c/result",
};
const payment_reponse = await axios.post(url, body, config);
const { data } = payment_reponse;
console.log("Payment request => ", data); //Not the actual response
//*------------Need actual response from the listener in routes.js--------//
res.status(200).json({ message: "Send money request", data });
} catch (error) {
console.log("Error while making a payment request", error);
res
.status(400)
.json({ message: "Error while send payment request", error: error.data });
}
};
//Routes.js
this.router.post("/b2c/result", (req, res) => {
console.log(req.body); //Actual response from API-1
});
this.router.post("/b2c/error", (req, res) => {
console.log(req.body); //Error if any from API-1
});
I don't think you can wait for the webhook call inside the api 1 block.
You could persist this request in a database, and when the payment API calls your webhook can query your database for information about the original request and process the information based on that.
I'm writing an auth. route for a node.js webserver. I'm using Express and it works well.
What I'm having trouble with is invoking a sendMail() function when an error occurs. At the moment, I'm just throwing a new error in the route to test.
throw new Error('testing...');
Because I'm using the express-async-errors module, if an error occurs in a route, program flow goes to my error middleware function.
It works perfect.
But in this error middleware function, I call my sendMail() function, which immediately fails giving me the same error as above: 'testing...'
const sendEmail = require('../email/sendEmail');
// error middleware function
async function error(err, req, res, next) {
const wasSent = await sendEmail('my-user-name#gmail.com', 'Error', err);
console.log(wasSent);
// http 500 - internal server error
res.status(500).send("Something unexpected happened. Our team has been notified.");
}
The result is my catch block in the below sendMail() function gets called.
What am I doing wrong?
Here's my sendmail function:
const nodemailer = require("nodemailer");
const striptags = require('striptags');
const config = require('config');
async function sendEmail(to, subject, content) {
try {
// create reusable transporter object using the default smtp transport
let transporter = nodemailer.createTransport({
host: config.get('emailHost'),
port: config.get('emailPort'),
secure: config.get('emailSecure'), // true for 465, false for other ports
auth: {
user: config.get('emailUsername'),
pass: config.get('emailPassword'),
},
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: config.get('emailFrom'), // sender address
to: to, // list of receivers
subject: subject,
text: striptags(content), // plain text body
html: content, // html body
});
// e.g. message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321#example.com>
//console.log("message sent: %s", info.messageId);
return true;
}
catch(ex) {
console.log("error: sendEmail() invocation failed;", ex);
return false;
}
}
module.exports = sendEmail;
The error was the "err" object.
Once I converted this to a string using UTIL it worked.
const util = require('util');
...
const fullErrorTrace = util.inspect(err, { showHidden: false, depth: null }).replace(/[\r\n]/gm, '<br />');
const wasSent = await sendEmail('my-user-name#gmail.com', 'Error', fullErrorTrace);
...
I have an Express server running.
What i do is upload an Excel File from HTML and then Express parse that file and do some calculating.
In the Excel file, each row has information about address of a User.
For each Address, our Express server will use google map geocoding API to calculate the latitude & longitude.
But, because Google doesn't accept more than 50 request per second to their geocoding API, so i have to use settimeout to delay the calculating.
For example if the Excel file has 50 addresses, so i have to use settimeout on each address to avoid that rate limit.
Here is my code to use settimeout and calculate latitude, longitude
createFromFile(req, res) {
var form = new formidable.IncomingForm();
return form.parse(req, function (err, fields, files) {
if (err)
return res.status(500).json({error: err.message})
var workbook = new exceljs.Workbook();
return workbook.xlsx.readFile(files.excelfile.path).then(function() {
// use workbook
var worksheet = workbook.getWorksheet(1)
var data = []
for (var i=2; i<=worksheet.rowCount; i++) {
data.push({
from_name: worksheet.getCell('A'+i).value + '',
from_address: worksheet.getCell('B'+i).value + '',
from_phone: worksheet.getCell('C'+i).value + '',
receiver_name: worksheet.getCell('D'+i).value + '',
receiver_address: worksheet.getCell('E'+i).value + '',
receiver_phone: worksheet.getCell('F'+i).value + '',
note: worksheet.getCell('H'+i).value + ''
})
}
var delay = function(t) {
return new Promise(function(resolve) {
setTimeout(resolve, t)
})
}
return Promise.all(data.map(function(item, i) {
return function() {
return delay(750*i).then(function() {
winston.log('debug', 'process for item '+i)
return geocoder.geocode(item.from_address).then(function(geo_data) {
data[i].from_coord = {
lat: geo_data[0].latitude,
lng: geo_data[0].longitude
}
return geocoder.geocode(item.receiver_address).then(function(geo_data) {
data[i].receiver_coord = {
lat: geo_data[0].latitude,
lng: geo_data[0].longitude
}
})
})
.catch(function(geo_error) {
winston.log('error', 'geo_error', {error: geo_error})
throw new Error('Address in line ' + i + ' is not valid')
})
})
}()
}))
.then(function() {
winston.log('debug', 'we are done calculating location')
return res.status(201).json(data)
})
})
.catch(function(e) {
winston.log('error', 'an error occurred')
return res.status(500).json({error: e.message})
})
})
}
And below is my codes to call that Express API, i used React to do frontend job & used javascript fetch api to request to server.
startUploadFile() {
this.props.showLoader()
let data = new FormData()
data.append('excelfile', this.state.selectedFile)
data.append('name', 'excelfile')
var me = this
fetch(Const.restServer + '/create-from-file', {
headers: {
'Access-Token': this.props.access_token,
},
method: 'POST',
body: data
})
.then(function(r) {
return r.json()
})
.then(function(r) {
if (r.hasOwnProperty('error'))
throw new Error(r.error)
me.props.hideLoader()
me.props.showDialog('success', 'Process Complete')
})
.catch(function(e) {
console.log(e)
me.props.hideLoader()
me.props.showDialog('error', e.message)
})
}
My problem is when i used above codes to uploading a file on browser, i see two request in express log file. Something like this:
I will provide my codes to log info of every request here too
app.use(function(req, res, next) {
winston.log('debug', 'call api:', {
api: req.url, requestMethod: req.method
})
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Access-Token, Web-Admin-Request"
);
next()
});
function isAuthenticated(req, res, next) {
/**
** Rest API Middleware check if access_token is valid
*/
let accessToken = req.body.accessToken || req.get('Access-Token')
// bunch of codes to check accessToken
next()
}
app.post('/order/create-from-file', isAuthenticated, orderController.createFromFile);
I don't understand why this happen. If I use Postman & select a File & upload, it works fine - just only One Request in logs.
Can anyone tell me what is the reason. I feel like this is a Bug of Express. My Express version is 4.15.2
The Access-Token request header your code adds to the request triggers browsers to send a CORS preflight OPTIONS request before trying the POST request.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests gives more detail but the gist of it is, as long as your code’s adding that Access-Token header to the request, there’s no way you can prevent browsers from making the extra preflight OPTIONS request—because it’s something browsers do automatically as part of the CORS protocol.
The reason you don’t see the extra request when you use Postman is that it doesn’t do the CORS preflight OPTIONS request—only browsers send it, and only for requests made by XHR/Fetch from frontend JavaScript code running in a browser at a specific origin (which Postman isn’t).
Well, finally i can fix this problem by passing 'Access-Token' into request body instead of request header (now, my server always receive only one request). Thank to #sideshowbarker because your comment trigger me to do this method.
I still think this Problem is a bug in Express, but because it didn't occur on my local development environment, so i will not send a report to them.
How can I make an HTTP request from within Node.js or Express.js? I need to connect to another service. I am hoping the call is asynchronous and that the callback contains the remote server's response.
Here is a snippet of some code from a sample of mine. It's asynchronous and returns a JSON object. It can do any form of GET request.
Note that there are more optimal ways (just a sample) - for example, instead of concatenating the chunks you put into an array and join it etc... Hopefully, it gets you started in the right direction:
const http = require('http');
const https = require('https');
/**
* getJSON: RESTful GET request returning JSON object(s)
* #param options: http options object
* #param callback: callback to pass the results JSON object(s) back
*/
module.exports.getJSON = (options, onResult) => {
console.log('rest::getJSON');
const port = options.port == 443 ? https : http;
let output = '';
const req = port.request(options, (res) => {
console.log(`${options.host} : ${res.statusCode}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
output += chunk;
});
res.on('end', () => {
let obj = JSON.parse(output);
onResult(res.statusCode, obj);
});
});
req.on('error', (err) => {
// res.send('error: ' + err.message);
});
req.end();
};
It's called by creating an options object like:
const options = {
host: 'somesite.com',
port: 443,
path: '/some/path',
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
And providing a callback function.
For example, in a service, I require the REST module above and then do this:
rest.getJSON(options, (statusCode, result) => {
// I could work with the resulting HTML/JSON here. I could also just return it
console.log(`onResult: (${statusCode})\n\n${JSON.stringify(result)}`);
res.statusCode = statusCode;
res.send(result);
});
UPDATE
If you're looking for async/await (linear, no callback), promises, compile time support and intellisense, we created a lightweight HTTP and REST client that fits that bill:
Microsoft typed-rest-client
Try using the simple http.get(options, callback) function in node.js:
var http = require('http');
var options = {
host: 'www.google.com',
path: '/index.html'
};
var req = http.get(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
// Buffer the body entirely for processing as a whole.
var bodyChunks = [];
res.on('data', function(chunk) {
// You can process streamed parts here...
bodyChunks.push(chunk);
}).on('end', function() {
var body = Buffer.concat(bodyChunks);
console.log('BODY: ' + body);
// ...and/or process the entire body here.
})
});
req.on('error', function(e) {
console.log('ERROR: ' + e.message);
});
There is also a general http.request(options, callback) function which allows you to specify the request method and other request details.
Request and Superagent are pretty good libraries to use.
note: request is deprecated, use at your risk!
Using request:
var request=require('request');
request.get('https://someplace',options,function(err,res,body){
if(err) //TODO: handle err
if(res.statusCode === 200 ) //etc
//TODO Do something with response
});
You can also use Requestify, a really cool and very simple HTTP client I wrote for nodeJS + it supports caching.
Just do the following for GET method request:
var requestify = require('requestify');
requestify.get('http://example.com/api/resource')
.then(function(response) {
// Get the response body (JSON parsed or jQuery object for XMLs)
response.getBody();
}
);
This version is based on the initially proposed by bryanmac function which uses promises, better error handling, and is rewritten in ES6.
let http = require("http"),
https = require("https");
/**
* getJSON: REST get request returning JSON object(s)
* #param options: http options object
*/
exports.getJSON = function (options) {
console.log('rest::getJSON');
let reqHandler = +options.port === 443 ? https : http;
return new Promise((resolve, reject) => {
let req = reqHandler.request(options, (res) => {
let output = '';
console.log('rest::', options.host + ':' + res.statusCode);
res.setEncoding('utf8');
res.on('data', function (chunk) {
output += chunk;
});
res.on('end', () => {
try {
let obj = JSON.parse(output);
// console.log('rest::', obj);
resolve({
statusCode: res.statusCode,
data: obj
});
}
catch (err) {
console.error('rest::end', err);
reject(err);
}
});
});
req.on('error', (err) => {
console.error('rest::request', err);
reject(err);
});
req.end();
});
};
As a result you don't have to pass in a callback function, instead getJSON() returns a promise. In the following example the function is used inside of an ExpressJS route handler
router.get('/:id', (req, res, next) => {
rest.getJSON({
host: host,
path: `/posts/${req.params.id}`,
method: 'GET'
}).then(({ statusCode, data }) => {
res.json(data);
}, (error) => {
next(error);
});
});
On error it delegates the error to the server error handling middleware.
Unirest is the best library I've come across for making HTTP requests from Node. It's aiming at being a multiplatform framework, so learning how it works on Node will serve you well if you need to use an HTTP client on Ruby, PHP, Java, Python, Objective C, .Net or Windows 8 as well. As far as I can tell the unirest libraries are mostly backed by existing HTTP clients (e.g. on Java, the Apache HTTP client, on Node, Mikeal's Request libary) - Unirest just puts a nicer API on top.
Here are a couple of code examples for Node.js:
var unirest = require('unirest')
// GET a resource
unirest.get('http://httpbin.org/get')
.query({'foo': 'bar'})
.query({'stack': 'overflow'})
.end(function(res) {
if (res.error) {
console.log('GET error', res.error)
} else {
console.log('GET response', res.body)
}
})
// POST a form with an attached file
unirest.post('http://httpbin.org/post')
.field('foo', 'bar')
.field('stack', 'overflow')
.attach('myfile', 'examples.js')
.end(function(res) {
if (res.error) {
console.log('POST error', res.error)
} else {
console.log('POST response', res.body)
}
})
You can jump straight to the Node docs here
Check out shred. It's a node HTTP client created and maintained by spire.io that handles redirects, sessions, and JSON responses. It's great for interacting with rest APIs. See this blog post for more details.
Check out httpreq: it's a node library I created because I was frustrated there was no simple http GET or POST module out there ;-)
For anyone who looking for a library to send HTTP requests in NodeJS, axios is also a good choice. It supports Promises :)
Install (npm): npm install axios
Example GET request:
const axios = require('axios');
axios.get('https://google.com')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
Github page
Update 10/02/2022
Node.js integrates fetch in v17.5.0 in experimental mode. Now, you can use fetch to send requests just like you do on the client-side. For now, it is an experimental feature so be careful.
If you just need to make simple get requests and don't need support for any other HTTP methods take a look at: simple-get:
var get = require('simple-get');
get('http://example.com', function (err, res) {
if (err) throw err;
console.log(res.statusCode); // 200
res.pipe(process.stdout); // `res` is a stream
});
Use reqclient: not designed for scripting purpose
like request or many other libraries. Reqclient allows in the constructor
specify many configurations useful when you need to reuse the same
configuration again and again: base URL, headers, auth options,
logging options, caching, etc. Also has useful features like
query and URL parsing, automatic query encoding and JSON parsing, etc.
The best way to use the library is create a module to export the object
pointing to the API and the necessary configurations to connect with:
Module client.js:
let RequestClient = require("reqclient").RequestClient
let client = new RequestClient({
baseUrl: "https://myapp.com/api/v1",
cache: true,
auth: {user: "admin", pass: "secret"}
})
module.exports = client
And in the controllers where you need to consume the API use like this:
let client = require('client')
//let router = ...
router.get('/dashboard', (req, res) => {
// Simple GET with Promise handling to https://myapp.com/api/v1/reports/clients
client.get("reports/clients")
.then(response => {
console.log("Report for client", response.userId) // REST responses are parsed as JSON objects
res.render('clients/dashboard', {title: 'Customer Report', report: response})
})
.catch(err => {
console.error("Ups!", err)
res.status(400).render('error', {error: err})
})
})
router.get('/orders', (req, res, next) => {
// GET with query (https://myapp.com/api/v1/orders?state=open&limit=10)
client.get({"uri": "orders", "query": {"state": "open", "limit": 10}})
.then(orders => {
res.render('clients/orders', {title: 'Customer Orders', orders: orders})
})
.catch(err => someErrorHandler(req, res, next))
})
router.delete('/orders', (req, res, next) => {
// DELETE with params (https://myapp.com/api/v1/orders/1234/A987)
client.delete({
"uri": "orders/{client}/{id}",
"params": {"client": "A987", "id": 1234}
})
.then(resp => res.status(204))
.catch(err => someErrorHandler(req, res, next))
})
reqclient supports many features, but it has some that are not supported by other
libraries: OAuth2 integration and logger integration
with cURL syntax, and always returns native Promise objects.
If you ever need to send GET request to an IP as well as a Domain (Other answers did not mention you can specify a port variable), you can make use of this function:
function getCode(host, port, path, queryString) {
console.log("(" + host + ":" + port + path + ")" + "Running httpHelper.getCode()")
// Construct url and query string
const requestUrl = url.parse(url.format({
protocol: 'http',
hostname: host,
pathname: path,
port: port,
query: queryString
}));
console.log("(" + host + path + ")" + "Sending GET request")
// Send request
console.log(url.format(requestUrl))
http.get(url.format(requestUrl), (resp) => {
let data = '';
// A chunk of data has been received.
resp.on('data', (chunk) => {
console.log("GET chunk: " + chunk);
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
console.log("GET end of response: " + data);
});
}).on("error", (err) => {
console.log("GET Error: " + err);
});
}
Don't miss requiring modules at the top of your file:
http = require("http");
url = require('url')
Also bare in mind that you may use https module for communicating over secured network. so these two lines would change:
https = require("https");
...
https.get(url.format(requestUrl), (resp) => { ......
## you can use request module and promise in express to make any request ##
const promise = require('promise');
const requestModule = require('request');
const curlRequest =(requestOption) =>{
return new Promise((resolve, reject)=> {
requestModule(requestOption, (error, response, body) => {
try {
if (error) {
throw error;
}
if (body) {
try {
body = (body) ? JSON.parse(body) : body;
resolve(body);
}catch(error){
resolve(body);
}
} else {
throw new Error('something wrong');
}
} catch (error) {
reject(error);
}
})
})
};
const option = {
url : uri,
method : "GET",
headers : {
}
};
curlRequest(option).then((data)=>{
}).catch((err)=>{
})