How send string/image base64 to Sailsjs - Skipper with ajax - sails.js

Currently I am capturing the image of the camera, this Base64 format,and I'm sending through ajax.
xhr({
uri: 'http://localhost:1337/file/upload',
method: 'post',
body:'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAA...'
}
0 file(s) uploaded successfully!

Here is a nice link that will guide you to do send an image from an Ajax Client to an ajax server.
http://www.nickdesteffen.com/blog/file-uploading-over-ajax-using-html5
You can read this sails documentation to receive files on a sails server :
http://sailsjs.org/documentation/reference/request-req/req-file
You can do as the following example :
Client side ( ajax ):
var files = [];
$("input[type=file]").change(function(event) {
$.each(event.target.files, function(index, file) {
var reader = new FileReader();
reader.onload = function(event) {
object = {};
object.filename = file.name;
object.data = event.target.result;
files.push(object);
};
reader.readAsDataURL(file);
});
});
$("form").submit(function(form) {
$.each(files, function(index, file) {
$.ajax({url: "/ajax-upload",
type: 'POST',
data: {filename: file.filename, data: file.data}, // file.data is your base 64
success: function(data, status, xhr) {}
});
});
files = [];
form.preventDefault();
});
Server side ( sails ) :
[let's say you have a model Picture that take an ID and a URL]
[here is a sample of Picture controller, just to give you an idea]
module.exports = {
uploadPicture: function(req, res) {
req.file('picture').upload({
// don't allow the total upload size to exceed ~10MB
maxBytes: 10000000
},
function onDone(err, uploadedFiles) {
if (err) {
return res.negotiate(err);
}
// If no files were uploaded, respond with an error.
if (uploadedFiles.length === 0){
return res.badRequest('No file was uploaded');
}
// Save the "fd" and the url where the avatar for a user can be accessed
Picture
.update(777, { // give real ID
// Generate a unique URL where the avatar can be downloaded.
pictureURL: require('util').format('%s/user/pictures/%s', sails.getBaseUrl(), 777), // GIVE REAL ID
// Grab the first file and use it's `fd` (file descriptor)
pictureFD: uploadedFiles[0].fd
})
.exec(function (err){
if (err) return res.negotiate(err);
return res.ok();
});
});
}
};
Hope this will help in your research.
I also recommand you to use Postman to test your API first, then code your client.

Related

Image returned from REST API always displays broken

I am building a content management system for an art portfolio app, with React. The client will POST to the API which uses Mongoose to insert into a MongoDB. The API then queries the DB for the newly inserted image, and returns it to the client.
Here's my code to connect to MongoDB using Mongoose:
mongoose.connect('mongodb://localhost/test').then(() =>
console.log('connected to db')).catch(err => console.log(err))
mongoose.Promise = global.Promise
const db = mongoose.connection
db.on('error', console.error.bind(console, 'MongoDB connection error:'))
const Schema = mongoose.Schema;
const ImgSchema = new Schema({
img: { data: Buffer, contentType: String }
})
const Img = mongoose.model('Img', ImgSchema)
I am using multer and fs to handle the image file. My POST endpoint looks like this:
router.post('/', upload.single('image'), (req, res) => {
if (!req.file) {
res.send('no file')
} else {
const imgItem = new Img()
imgItem.img.data = fs.readFileSync(req.file.path)
imgItem.contentType = 'image/png'
imgItem
.save()
.then(data =>
Img.findById(data, (err, findImg) => {
console.log(findImg.img)
fs.writeFileSync('api/uploads/image.png', findImg.img.data)
res.sendFile(__dirname + '/uploads/image.png')
}))
}
})
I can see in the file structure that writeFileSync is writing the image to the disk. res.sendFile grabs it and sends it down to the client.
Client side code looks like this:
handleSubmit = e => {
e.preventDefault()
const img = new FormData()
img.append('image', this.state.file, this.state.file.name)
axios
.post('http://localhost:8000/api/gallery', img, {
onUploadProgress: progressEvent => {
console.log(progressEvent.loaded / progressEvent.total)
}
})
.then(res => {
console.log('responsed')
console.log(res)
const returnedFile = new File([res.data], 'image.png', { type: 'image/png' })
const reader = new FileReader()
reader.onloadend = () => {
this.setState({ returnedFile, returned: reader.result })
}
reader.readAsDataURL(returnedFile)
})
.catch(err => console.log(err))
}
This does successfully place both the returned file and the img data url on state. However, in my application, the image always displays broken.
Here's some screenshots:
How to fix this?
Avoid sending back base64 encoded images (multiple images + large files + large encoded strings = very slow performance). I'd highly recommend creating a microservice that only handles image uploads and any other image related get/post/put/delete requests. Separate it from your main application.
For example:
I use multer to create an image buffer
Then use sharp or fs to save the image (depending upon file type)
Then I send the filepath to my controller to be saved to my DB
Then, the front-end does a GET request when it tries to access: http://localhost:4000/uploads/timestamp-randomstring-originalname.fileext
In simple terms, my microservice acts like a CDN solely for images.
For example, a user sends a post request to http://localhost:4000/api/avatar/create with some FormData:
It first passes through some Express middlewares:
libs/middlewares.js
...
app.use(cors({credentials: true, origin: "http://localhost:3000" })) // allows receiving of cookies from front-end
app.use(morgan(`tiny`)); // logging framework
app.use(multer({
limits: {
fileSize: 10240000,
files: 1,
fields: 1
},
fileFilter: (req, file, next) => {
if (!/\.(jpe?g|png|gif|bmp)$/i.test(file.originalname)) {
req.err = `That file extension is not accepted!`
next(null, false)
}
next(null, true);
}
}).single(`file`))
app.use(bodyParser.json()); // parses header requests (req.body)
app.use(bodyParser.urlencoded({ limit: `10mb`, extended: true })); // allows objects and arrays to be URL-encoded
...etc
Then, hits the avatars route:
routes/avatars.js
app.post(`/api/avatar/create`, requireAuth, saveImage, create);
It then passes through some user authentication, then goes through my saveImage middleware:
services/saveImage.js
const createRandomString = require('../shared/helpers');
const fs = require("fs");
const sharp = require("sharp");
const randomString = createRandomString();
if (req.err || !req.file) {
return res.status(500).json({ err: req.err || `Unable to locate the requested file to be saved` })
next();
}
const filename = `${Date.now()}-${randomString}-${req.file.originalname}`;
const filepath = `uploads/${filename}`;
const setFilePath = () => { req.file.path = filepath; return next();}
(/\.(gif|bmp)$/i.test(req.file.originalname))
? fs.writeFile(filepath, req.file.buffer, (err) => {
if (err) {
return res.status(500).json({ err: `There was a problem saving the image.`});
next();
}
setFilePath();
})
: sharp(req.file.buffer).resize(256, 256).max().withoutEnlargement().toFile(filepath).then(() => setFilePath())
If the file is saved, it then sends a req.file.path to my create controller. This gets saved to my DB as a file path and as an image path (the avatarFilePath or /uploads/imagefile.ext is saved for removal purposes and the avatarURL or [http://localhost:4000]/uploads/imagefile.ext is saved and used for the front-end GET request):
controllers/avatars.js (I'm using Postgres, but you can substitute for Mongo)
create: async (req, res, done) => {
try {
const avatarurl = `${apiURL}/${req.file.path}`;
await db.result("INSERT INTO avatars(userid, avatarURL, avatarFilePath) VALUES ($1, $2, $3)", [req.session.id, avatarurl, req.file.path]);
res.status(201).json({ avatarurl });
} catch (err) { return res.status(500).json({ err: err.toString() }); done();
}
Then when the front-end tries to access the uploads folder via <img src={avatarURL} alt="image" /> or <img src="[http://localhost:4000]/uploads/imagefile.ext" alt="image" />, it gets served up by the microservice:
libs/server.js
const express = require("express");
const path = app.get("path");
const PORT = 4000;
//============================================================//
// EXPRESS SERVE AVATAR IMAGES
//============================================================//
app.use(`/uploads`, express.static(`uploads`));
//============================================================//
/* CREATE EXPRESS SERVER */
//============================================================//
app.listen(PORT);
What it looks when logging requests:
19:17:54 INSERT INTO avatars(userid, avatarURL, avatarFilePath) VALUES ('08861626-b6d0-11e8-9047-672b670fe126', 'http://localhost:4000/uploads/1536891474536-k9c7OdimjEWYXbjTIs9J4S3lh2ldrzV8-android.png', 'uploads/1536891474536-k9c7OdimjEWYXbjTIs9J4S3lh2ldrzV8-android.png')
POST /api/avatar/create 201 109 - 61.614 ms
GET /uploads/1536891474536-k9c7OdimjEWYXbjTIs9J4S3lh2ldrzV8-android.png 200 3027 - 3.877 ms
What the user sees upon successful GET request:

How upload and save image using Sails and MongoDB

I'm working on a project and I'm using a backend sails js, a MongoDB as database and front-end React js.
I have a problem on the upload image.
Here is the code Sails backend and when I test it in PostMan, I got this result (result test PostMan), and the image is not stored in the specified folder but a value containing id and name of file is inserted in MongoDB,
uploadFile: function (req, res) {
var image= req.file('avatar');
image.upload({
adapter: require('skipper-gridfs'),
uri: 'mongodb://localhost:27017/name_db.name_collection',
dirname: '../../assets/images/'
}, function (err, filesUploaded) {
if (err){
return res.header("Access-Control-Allow-Origin", "*");
/*res.negotiate(err);*/res.json(err);
}
else{
return
res.header("Access-Control-Allow-Origin", "*"); res.ok({
files: filesUploaded,
textParams: req.params.all()
});
}
});
},
result test postMan
And here is the Reactjs front-end code
_handleSubmit(e) {
e.preventDefault();
// TODO: do something with -> this.state.file
fetch('http://localhost:1337/uploadPhoto/logos', {
method: 'POST',
body: JSON.stringify({avatar:this.state.file})
})
.then((response) => response.json())
.catch((err) => { console.log(err); });
}
Sails version 0.12,
React version 15.5,
and MongoDB version 3.4.9.
Thanks for your help
There is no dirname parameter for skipper-gridfs adapter because the file won't be stored onto the local file system.
Skipper will store the file into the MongoDB database.
U need to send it as form Data
let formData = new FormData()
console.log(values);
await formData.append('profile_picture',values.profile_picture.rawFile,values.profile_picture)
await fetch('http://localhost:1337/api/moderators',{
body:formData,
method:'POST',
credentials:'include' //If Using Session for react-app instead of JWT token
})

Uploading files via sails v.9.16

I am trying to upload a bunch of files to the server with skipper and jquery-file-uploader in sails v.9.x. I also need to add in two other field names with the form and multiple files. But i'm having some trouble getting it to work quite right. When I log the server it says that the files aren't there. Could I get some help?
Here is my front-end js:
var filesList = [],
fileupload = $('#uploader'),
paramNames = [];
var button = $("button.success.start.uploadbutton");
file_upload = fileupload.fileupload({
autoUpload: false,
fileInput: $("input:file"),
}).on("fileuploadadd", function(e, data){
filesList.push(data.files[0]);
paramNames.push(e.delegatedEvent.target.name);
});
button.click(function(e){
e.preventDefault();
var data = fileupload.serialize();
var toServer = {
data: data, files:filesList, paramName: paramNames
};
console.log(file_upload.fileupload);
file_upload.fileupload('send', toServer
).success(function(result, textstatus, jqXHR){
console.log("gettting the file uploaded!");
});
});
and here is the server side:
'upload': function (req, res) {
req.file('files').upload(function (err, files) {
console.log(files);
if (err) return res.serverError(err);
return res.json({
message: files.length + ' file(s) uploaded successfully!',
files: files
});
});
and the express js:
module.exports.express = {
bodyParser: require('skipper')
}

Photo upload with facebook-node-sdk Module / (#324) Requires upload file

I'm trying to send a photo using facebook node sdk module to a page. https://github.com/Thuzi/facebook-node-sdk/
I'm able to post to the page wall or to uplaod from an url. But i have a problem trying to uplaod photo from data.
That is how i connected :
FB.api('oauth/access_token', {
client_id: clientid,
client_secret: clientsecret,
redirect_uri: redirecturi,
code: code,
scope: scope,
fileUpload : true,
}, function (resf) { ...}
I get the good access token like this :
FB.api('/me/accounts', function (resf) {
if (!resf || resf.error) {
console.log(!resf ? 'error occurred' : resf.error);
return;
}
for (var i = 0; i < resf.data.length; i++) {
if (resf.data[i].id == pageid)
{
resf.data[i]. access_token
}
});
And i try to upload the photo :
var buff = "data:image/jpeg;base64,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";
var body = 'My firstdfsfsfd';
FB.api(pageid + '/photos', 'post', { message: body, source: buff, }, function (resf) {
if (!resf || resf.error) {
console.log(!resf ? 'error occurred' : resf.error);
return;
}
console.log( resf);
res.send(resf);
});
And i have this error :
{
"error": {
"message": "(#324) Requires upload file",
"type": "OAuthException",
"code": 324
}
}
This call is working :
var body = 'My firstdfsfsfd';
FB.api(pageid + '/photos', 'post', { message: body, url: 'url_image', }, function (resf) {
if (!resf || resf.error) {
console.log(!resf ? 'error occurred' : resf.error);
return;
}
console.log( resf);
res.send(resf);
});
What did i forget ?
Does multipart upload is allowing with this module : https://github.com/Thuzi/facebook-node-sdk/
It does not appear to support multipart. You could do it manually with the request module:
var request = require('request');
// ....
var access_token = 'abc123',
pageid = 'me',
fburl = 'https://graph.facebook.com/'
+ pageid
+ '/photos?access_token='
+ access_token,
req,
form;
req = request.post(fburl, function(err, res, body) {
if (err)
return console.error('Upload failed:', err);
console.log('Upload successful! Server responded with:', body);
});
form = req.form()
// append a normal literal text field ...
form.append('message', 'My photo!');
// append a file field by streaming a file from disk ...
form.append('source', fs.createReadStream(path.join(__dirname, 'photo.jpg')));
// or append a Buffer ...
form.append('source', someBuffer);
// or append the contents of a remote url ...
form.append('source', request('http://google.com/doodle.png'));
Example (from mscdex) above works for:
form.append('source', requestLib('<imageURL>'));
Gives response:
{"id":"756317401077924","post_id":"100000990137087_756310827745248"}
Also works for:
form.append('source', fs.createReadStream('<imagepath>'));
Gives response:
{"id":"756328687743462","post_id":"100000990137087_756310827745248"}
This is probably all I need. Thanks mscdex, very helpful. But out of curiosity, when I replaced it with an image buffer:
form.append('source', imageBuffer);
It gives the same error as OP (even when using the same image string as OP):
{"error":{"message":"(#324) Requires upload file","type":"OAuthException","code":324}}
Why? My guess is Facebook wants a specific format for an encoded image.

How to make remote REST call inside Node.js? any CURL?

In Node.js, other than using child process to make CURL call, is there a way to make CURL call to remote server REST API and get the return data?
I also need to set up the request header to the remote REST call, and also query string as well in GET (or POST).
I find this one: http://blog.nodejitsu.com/jsdom-jquery-in-5-lines-on-nodejs
but it doesn't show any way to POST query string.
Look at http.request
var options = {
host: url,
port: 80,
path: '/resource?id=foo&bar=baz',
method: 'POST'
};
http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
}).end();
How about using Request — Simplified HTTP client.
Edit February 2020: Request has been deprecated so you probably shouldn't use it any more.
Here's a GET:
var request = require('request');
request('http://www.google.com', function (error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body) // Print the google web page.
}
})
OP also wanted a POST:
request.post('http://service.com/upload', {form:{key:'value'}})
I use node-fetch because it uses the familiar (if you are a web developer) fetch() API. fetch() is the new way to make arbitrary HTTP requests from the browser.
Yes I know this is a node js question, but don't we want to reduce the number of API's developers have to memorize and understand, and improve re-useability of our javascript code? Fetch is a standard so how about we converge on that?
The other nice thing about fetch() is that it returns a javascript Promise, so you can write async code like this:
let fetch = require('node-fetch');
fetch('http://localhost', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: '{}'
}).then(response => {
return response.json();
}).catch(err => {console.log(err);});
Fetch superseeds XMLHTTPRequest. Here's some more info.
Look at http://isolasoftware.it/2012/05/28/call-rest-api-with-node-js/
var https = require('https');
/**
* HOW TO Make an HTTP Call - GET
*/
// options for GET
var optionsget = {
host : 'graph.facebook.com', // here only the domain name
// (no http/https !)
port : 443,
path : '/youscada', // the rest of the url with parameters if needed
method : 'GET' // do GET
};
console.info('Options prepared:');
console.info(optionsget);
console.info('Do the GET call');
// do the GET request
var reqGet = https.request(optionsget, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
// console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('GET result:\n');
process.stdout.write(d);
console.info('\n\nCall completed');
});
});
reqGet.end();
reqGet.on('error', function(e) {
console.error(e);
});
/**
* HOW TO Make an HTTP Call - POST
*/
// do a POST request
// create the JSON object
jsonObject = JSON.stringify({
"message" : "The web of things is approaching, let do some tests to be ready!",
"name" : "Test message posted with node.js",
"caption" : "Some tests with node.js",
"link" : "http://www.youscada.com",
"description" : "this is a description",
"picture" : "http://youscada.com/wp-content/uploads/2012/05/logo2.png",
"actions" : [ {
"name" : "youSCADA",
"link" : "http://www.youscada.com"
} ]
});
// prepare the header
var postheaders = {
'Content-Type' : 'application/json',
'Content-Length' : Buffer.byteLength(jsonObject, 'utf8')
};
// the post options
var optionspost = {
host : 'graph.facebook.com',
port : 443,
path : '/youscada/feed?access_token=your_api_key',
method : 'POST',
headers : postheaders
};
console.info('Options prepared:');
console.info(optionspost);
console.info('Do the POST call');
// do the POST call
var reqPost = https.request(optionspost, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
// console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('POST result:\n');
process.stdout.write(d);
console.info('\n\nPOST completed');
});
});
// write the json data
reqPost.write(jsonObject);
reqPost.end();
reqPost.on('error', function(e) {
console.error(e);
});
/**
* Get Message - GET
*/
// options for GET
var optionsgetmsg = {
host : 'graph.facebook.com', // here only the domain name
// (no http/https !)
port : 443,
path : '/youscada/feed?access_token=you_api_key', // the rest of the url with parameters if needed
method : 'GET' // do GET
};
console.info('Options prepared:');
console.info(optionsgetmsg);
console.info('Do the GET call');
// do the GET request
var reqGet = https.request(optionsgetmsg, function(res) {
console.log("statusCode: ", res.statusCode);
// uncomment it for header details
// console.log("headers: ", res.headers);
res.on('data', function(d) {
console.info('GET result after POST:\n');
process.stdout.write(d);
console.info('\n\nCall completed');
});
});
reqGet.end();
reqGet.on('error', function(e) {
console.error(e);
});
Axios
An example (axios_example.js) using Axios in Node.js:
const axios = require('axios');
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
app.get('/search', function(req, res) {
let query = req.query.queryStr;
let url = `https://your.service.org?query=${query}`;
axios({
method:'get',
url,
auth: {
username: 'the_username',
password: 'the_password'
}
})
.then(function (response) {
res.send(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
});
var server = app.listen(port);
Be sure in your project directory you do:
npm init
npm install express
npm install axios
node axios_example.js
You can then test the Node.js REST API using your browser at: http://localhost:5000/search?queryStr=xxxxxxxxx
Similarly you can do post, such as:
axios({
method: 'post',
url: 'https://your.service.org/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
SuperAgent
Similarly you can use SuperAgent.
superagent.get('https://your.service.org?query=xxxx')
.end((err, response) => {
if (err) { return console.log(err); }
res.send(JSON.stringify(response.body));
});
And if you want to do basic authentication:
superagent.get('https://your.service.org?query=xxxx')
.auth('the_username', 'the_password')
.end((err, response) => {
if (err) { return console.log(err); }
res.send(JSON.stringify(response.body));
});
Ref:
https://github.com/axios/axios
https://www.twilio.com/blog/2017/08/http-requests-in-node-js.html
I have been using restler for making webservices call, works like charm and is pretty neat.
To use latest Async/Await features
https://www.npmjs.com/package/request-promise-native
npm install --save request
npm install --save request-promise-native
//code
async function getData (){
try{
var rp = require ('request-promise-native');
var options = {
uri:'https://reqres.in/api/users/2',
json:true
};
var response = await rp(options);
return response;
}catch(error){
throw error;
}
}
try{
console.log(getData());
}catch(error){
console.log(error);
}
Warning: As of Feb 11th 2020, request is fully deprecated.
One another example - you need to install request module for that
var request = require('request');
function get_trustyou(trust_you_id, callback) {
var options = {
uri : 'https://api.trustyou.com/hotels/'+trust_you_id+'/seal.json',
method : 'GET'
};
var res = '';
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
res = body;
}
else {
res = 'Not Found';
}
callback(res);
});
}
get_trustyou("674fa44c-1fbd-4275-aa72-a20f262372cd", function(resp){
console.log(resp);
});
const http = require('http');
const url = process.argv[2];
http.get(url, function(response) {
let finalData = "";
response.on("data", function (data) {
finalData += data.toString();
});
response.on("end", function() {
console.log(finalData.length);
console.log(finalData.toString());
});
});
I didn't find any with cURL so I wrote a wrapper around node-libcurl and can be found at https://www.npmjs.com/package/vps-rest-client.
To make a POST is like so:
var host = 'https://api.budgetvm.com/v2/dns/record';
var key = 'some___key';
var domain_id = 'some___id';
var rest = require('vps-rest-client');
var client = rest.createClient(key, {
verbose: false
});
var post = {
domain: domain_id,
record: 'test.example.net',
type: 'A',
content: '111.111.111.111'
};
client.post(host, post).then(function(resp) {
console.info(resp);
if (resp.success === true) {
// some action
}
client.close();
}).catch((err) => console.info(err));
If you have Node.js 4.4+, take a look at reqclient, it allows you to make calls and log the requests in cURL style, so you can easily check and reproduce the calls outside the application.
Returns Promise objects instead of pass simple callbacks, so you can handle the result in a more "fashion" way, chain the result easily, and handle errors in a standard way. Also removes a lot of boilerplate configurations on each request: base URL, time out, content type format, default headers, parameters and query binding in the URL, and basic cache features.
This is an example of how to initialize it, make a call and log the operation with curl style:
var RequestClient = require("reqclient").RequestClient;
var client = new RequestClient({
baseUrl:"http://baseurl.com/api/", debugRequest:true, debugResponse:true});
client.post("client/orders", {"client": 1234, "ref_id": "A987"},{"x-token": "AFF01XX"});
This will log in the console...
[Requesting client/orders]-> -X POST http://baseurl.com/api/client/orders -d '{"client": 1234, "ref_id": "A987"}' -H '{"x-token": "AFF01XX"}' -H Content-Type:application/json
And when the response is returned ...
[Response client/orders]<- Status 200 - {"orderId": 1320934}
This is an example of how to handle the response with the promise object:
client.get("reports/clients")
.then(function(response) {
// Do something with the result
}).catch(console.error); // In case of error ...
Of course, it can be installed with: npm install reqclient.
You can use curlrequest to easily set what time of request you want to do... you can even set headers in the options to "fake" a browser call.
Warning: As of Feb 11th 2020, request is fully deprecated.
If you implement with form-data, for more info (https://tanaikech.github.io/2017/07/27/multipart-post-request-using-node.js):
var fs = require('fs');
var request = require('request');
request.post({
url: 'https://slack.com/api/files.upload',
formData: {
file: fs.createReadStream('sample.zip'),
token: '### access token ###',
filetype: 'zip',
filename: 'samplefilename',
channels: 'sample',
title: 'sampletitle',
},
}, function (error, response, body) {
console.log(body);
});
I found superagent to be really useful,
it is very simple
for example
const superagent=require('superagent')
superagent
.get('google.com')
.set('Authorization','Authorization object')
.set('Accept','application/json')
Update from 2022:
from node.js version v18 on you can use the globally available fetch API (see https://nodejs.org/en/blog/announcements/v18-release-announce/)
There is also an example usage included on their announcement page:
const res = await fetch('https://nodejs.org/api/documentation.json');
if (res.ok) {
const data = await res.json();
console.log(data);
}