I would like to send an API request to https://api-test.onlineszamla.nav.gov.hu/invoiceService/queryTaxpayer and they expect an XML, as a sample provided below. What is the appropriate syntax in Node.js that processes this request? Unfortuantely I couldn't find this out from the API documentation.
EDIT: part of the XML contents will be from user data, part of it from input fields.
<?xml version="1.0" encoding="UTF-8"?><QueryTaxpayerRequest xmlns="http://schemas.nav.gov.hu/OSA/1.0/api">
<header>
<requestId></requestId>
<timestamp></timestamp>
<requestVersion></requestVersion>
<headerVersion></headerVersion>
</header>
<user>
<login></login>
<passwordHash></passwordHash>
<taxNumber></taxNumber>
<requestSignature></requestSignature>
</user>
<software>
<softwareId></softwareId>
</software>
<taxNumber></taxNumber>
</QueryTaxpayerRequest>
Use XML parser and then Set the response type as XML like below :
var xml = require('xml');
response.set('Content-Type', 'text/xml');
response.send(xml(YOUR_XML_OBJECT));
in the above I have used XML as the parser, you should be able to use any other available packages.
You can use a library like xmlbuilder to make creating xml string easier.
var builder = require('xmlbuilder');
var obj = {
root: {
xmlbuilder: {
repo: {
'#type': 'git', // attributes start with #
'#text': 'git://github.com/oozcitak/xmlbuilder-js.git' // text node
}
}
}
};
var xml = builder.create(obj).end({ pretty: true});
console.log(xml);
And then you can use any library to make the request and use the xml string above in the body.
This works for me awesome.
var Request = require("request");
const express = require("express");
const app = express();
app.use(express.urlencoded({extended: true}));
app.use(express.text())
app.post("/api/getXML", (req, res) => {
Request.post({
"headers": { "content-type": "text/plain; charset=utf-8"},
"url": "<url which return xml response>",
"body": req.body
}, (error, response, body) => {
if(error) {
console.error(error);
res.send(error)
}
console.log("XML body :",body);
res.send(body);
});
});
The idea got from the link https://www.thepolyglotdeveloper.com/2017/10/consume-remote-api-data-nodejs-application/
Related
I am having an API Service build on node js running on port 3001 and a web UI using REACT & running on port 3000. I have to POST details from Web page to the API in JSON Format. I am able to hit the API, however I could not get the JSON on the API. Its being received as {}. However the API is working fine from postman.
Could some one please share light on where i am missing.
Source code of API
const util = require('util')
const request = require("request");
const express = require('express')
const app = express();
const port = 3001
app.use(express.json());
app.use(express.urlencoded( {extended: false}));
const bodyParser = require('body-parser');
const { json } = require('express/lib/response');
app.post('/PostPatronDetailsone',(req,res) => {
async function run() {
try {
console.log('Request received from REACT ONE');
// parse application/json
app.use(bodyParser.json())
console.log(req.body);
// Respond back
res.send('Transaction Sent');
} finally {
// Ensures that the client will close when you finish/error
}
}
run().catch(console.dir);
});
app.listen(port, () => console.log('Server is listening at port ' + port));
Code Snippet of Web making the HTTP POST
import React from 'react';
class Signup extends React.Component {
constructor(props) {
super(props);
this.state = {
postId: null
};
}
async componentDidMount() {
// Simple POST request with a JSON body using fetch
let payload = {'first_name': 'TEST' };
var data = new FormData();
data.append( "json", JSON.stringify( payload ) );
const requestOptions = {
method: 'POST',
mode: 'no-cors',
headers: { 'Content-Type': 'application/json','Accept':'application/json' },
body: data,
redirect: 'follow'
};
var response = await fetch('http://localhost:3001/PostPatronDetailsone', requestOptions);
var data1 = await response.json();
var data2 = data1.text();
alert(data2);
//this.setState({ postId: data1.insertedid });
}
render() {
const { postId } = this.state;
return (
<div className="card text-center m-3">
<h5 className="card-header">Simple POST Request</h5>
</div>
);
}
}
export default Signup;
Console Output of API Service
Server is listening at port 3001
Request received from REACT ONE
{}
Request received from REACT ONE
{}
It is because you send formData, instead stringify the object and send it to body like this:
async componentDidMount() {
// Simple POST request with a JSON body using fetch
let payload = {first_name: 'TEST' };
const requestOptions = {
method: 'POST',
mode: 'no-cors',
headers: { 'Content-Type': 'application/json','Accept':'application/json' },
body: JSON.stringify(payload ),
redirect: 'follow'
};
var response = await fetch('http://localhost:3001/PostPatronDetailsone', requestOptions);
var data1 = await response.json();
var data2 = data1.text();
alert(data2);
//this.setState({ postId: data1.insertedid });
}
Please change the code as follows:
let payload = {'first_name': 'TEST' };
fetch('http://localhost:3001/PostPatronDetailsone',{
body:JSON.stringify(payload),
method:'post',
mode: 'no-cors',
headers: {
"Content-Type": "application/json"
},
}).then((res)=>res.json()).then((data)=>console.log(data));
And from controller in backend remove that line as you are already using express.json() which is equivalent to that line:
app.use(bodyParser.json()) // remove it
You have 3 key problems here:
You are posting a FormData object (which gets converted to a multipart/form-data encoding) and not JSON
You are setting no-cors mode which causes the browser to silently discard any instructions to do anything that would require CORS permission (such as setting the application/json content-type or reading the response)
There won't be a text() method on anything parsed from JSON
const data = {'first_name': 'TEST' };
const payload = JSON.stringify(data)
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json','Accept':'application/json' },
body: payload,
redirect: 'follow'
};
const response = await fetch('http://localhost:3001/PostPatronDetailsone', requestOptions);
const parsed_json = await response.json();
console.log(parsed_json);
You will also need to change the server-side code to grant permission to the JavaScript to read the response and send the JSON formatted request. Use the cors module for that.
app.use(cors());
Also note that body parsing middleware needs to be set up when the application starts and not in the middle of a route. The body-parser module has been obsoleted as Express has its features built-in now.
The following is good:
app.use(express.json());
The following is bad:
const bodyParser = require('body-parser');
and
app.use(bodyParser.json())
Your route code doesn't need to be any more complex than:
app.post('/PostPatronDetailsone', async (req,res) => {
console.log('Request received from REACT ONE');
console.log(req.body);
res.json('Transaction Sent');
});
Note that since you are trying to parse the response as JSON in the client side code, I've had to change send to json so that the server outputs JSON instead of plain text.
Ok, so i need to proxy file array upload from my express node app, to remote PHP Api.
Ideally i would use something close to Nginx proxy since it has same modules with node.
If not,i would emulate form resend.
Can you help find the best way for doing this?
So, i did not found execaly how to proxy request itself, as it would do nginx, but at least i figured out how to redirect request with all it's data to different source.
So, here we use express-fileupload to get our file data from req, and form-data to create a form and send data.
import app from '#app';
import { authMw as checkJwtAndAddToRequest } from '#middleware/Auth';
import { Router } from 'express';
import fileupload, { UploadedFile } from "express-fileupload";
import FormData from 'form-data';
//add this MW to add files to you'r req
app.use(checkJwtAndAddToRequest)
app.use(fileupload());
app.post('/upload', (req, res) => {
const uploadableFiles: UploadedFile[] | UploadedFile | undefined = req.files?.formFieldName;
if(!uploadableFiles) {
throw Error('Pls add files to upload them');
}
//Transorm single file to same form as an array of files
const files: UploadedFile[] = Array.isArray(uploadableFiles) ? uploadableFiles : Array<UploadedFile>(uploadableFiles);
//create form
const form = new FormData();
//add files
files.forEach(
file => form.append('files[]', file.data.toString(), file.name)
)
//Submit
form.submit({
protocol: 'http:',
host: process.env.API_URL,
path: '/api-path-for/file/upload',
method: 'POST',
headers: {
//Add auth token if needed
authorization: `Bearer ${String(req.body.jwtToken)}`
}
}, (err, response) => {
if(err) {
//handle error
res.status(503).send('File server is currently unavailable');
}
//return remote response to original client
response.pipe(res)
});
});
I need to send BLOB to the server in order to make an image on same.
I am using axios on reactJs client and sending data by using this code.
/**
* Returns PDF document.
*
*/
getPDF = (blob) =>
{
let formatData = new FormData();
formatData.append('data', blob);
return axios({
method: 'post',
url: 'http://172.18.0.2:8001/export/pdf',
headers: { 'content-type': 'multipart/form-data' },
data: {
blob: formatData
}
}).then(response => {
return {
status: response.status,
data: response.data
}
})
}
I tried to console.log this blob value on client and there is regular data.
But on server request body is empty.
/**
* Exports data to PDF format route.
*/
app.post('/export/pdf', function (request, response) {
console.log(request.body.blob);
response.send('ok');
});
If I remove headers still empty body when sending blob, but if I remove blob and send some string, a server receives data.
But when the blob is sent server has an empty body.
NodeJS natively does not handle multipart/form-data so you have to use external module eg :- multer
Code Example(Not Tested):
var upload = multer({ dest: __dirname + '/public/uploads/' });
var type = upload.single('upl');
/**
* Exports data to PDF format route.
*/
app.post('/export/pdf', type, function (request, response) {
// Get the blob file data
console.log(request.file);
response.send('ok');
});
you can read about multer here
I hope this will work for you.
Are you using body-parser?
body-parser doesn't handle multipart bodies, which is what FormData is submitted as.
Instead, use a module like multer
let multer = require('multer');
let upload = multer();
app.post('/export/pdf', upload.fields([]), (req, res) => {
let formData = req.body;
console.log('Data', formData);
res.status(200).send('ok');
});
I had 2 problems that I had to solve for this. 1 firebase functions has a bug that doesn't allow multer. 2 you may be getting a blob back from response.blob() and that doesn't seem to produce a properly formatted blob for firebase functions either.
Im trying to replicate a facebook messenger bot but keep getting request is not defined.
Same code as facebook:
function callSendAPI(messageData) {
request({
uri: 'https://graph.facebook.com/v2.6/me/messages',
qs: { access_token: PAGE_ACCESS_TOKEN },
method: 'POST',
json: messageData
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
var recipientId = body.recipient_id;
var messageId = body.message_id;
console.log("Successfully sent generic message with id %s to recipient %s",
messageId, recipientId);
} else {
console.error("Unable to send message.");
console.error(response);
console.error(error);
}
});
}
My node server.js looks like this:
const express = require('express');
const bodyParser = require('body-parser');
//const request = express.request;
const PAGE_ACCESS_TOKEN = 'abc';
let app = express();
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
[...]
function sendTextMessage(recipientId, messageText) {
var messageData = {
recipient: {
id: recipientId
},
message: {
text: messageText
}
};
callSendAPI(messageData);
}
function callSendAPI(messageData) {..}
[...]
Am I missing something with express? Thanks
This example is making use of third-party Request module.
You could also use the native request like so: require('http').request(), if you want to, but I would say, that the request module is very common, and a good tool to use.
Your request, which is commented out, points to express.request. If used like request() will throw an error, since it's not a function. So, you should really use the Request module, or adjust the code to use native http.request.
Update 2020
The request module is deprecated now, so if you are reading this answer, use the native module or find a popular third-party library like Axios or others.
You have not installed request module.
First install it npm install --save request and then include it var request = require('request');
I got the same error but in a different context than yours; when I tried importing
import { Request } from 'express'
export class UserRequest extends Request {
user: UserEntity;
}
the problem was caused because of using class instead of interface
I want to send plain html instead of a json response for one of my routes in restify. I tried setting the contentType and header property of the response but it doesn't seem to set the contentType in the header (the browser tries to download the file rather than render it).
res.contentType = 'text/html';
res.header('Content-Type','text/html');
return res.send('<html><body>hello</body></html>');
Quick way to manipulate headers without changing formatters for the whole server:
A restify response object has all the "raw" methods of a node ServerResponse on it as well.
var body = '<html><body>hello</body></html>';
res.writeHead(200, {
'Content-Length': Buffer.byteLength(body),
'Content-Type': 'text/html'
});
res.write(body);
res.end();
If you've overwritten the formatters in the restify configuration, you'll have to make sure you have a formatter for text/html. So, this is an example of a configuration that will send json and jsonp-style or html depending on the contentType specified on the response object (res):
var server = restify.createServer({
formatters: {
'application/json': function(req, res, body){
if(req.params.callback){
var callbackFunctionName = req.params.callback.replace(/[^A-Za-z0-9_\.]/g, '');
return callbackFunctionName + "(" + JSON.stringify(body) + ");";
} else {
return JSON.stringify(body);
}
},
'text/html': function(req, res, body){
return body;
}
}
});
Another option is to call
res.end('<html><body>hello</body></html>');
Instead of
res.send('<html><body>hello</body></html>');
It seems like the behaviour #dlawrence describes in his answer has changed since when the answer was posted. The way it works now (at least in Restify 4.x) is:
const app = restify.createServer(
{
formatters: {
'text/html': function (req, res, body, cb) {
cb(null, body)
}
}
})