Parse FormData object in nest controller - json

I have a nest controller which accepts the following DTO, One of the parameters should be a buffer which is read from file
It suppose to read bin file
interface LoadFileRequest {
targetIp: string;
fileBuffer: Buffer;
user: User;
}
interface User {
username: string;
password: string;
}
#Controller('loader')
export class KeyLoaderController {
#Post('load')
async load(#Body() body: LoadFileRequest, #Req() request) {
console.log(body);
console.log(request);
}
}
My code for testing the controller:
import axios from "axios";
import fs from "fs";
import FormData from "form-data";
let headersList = {
Accept: "*/*",
};
let formdata = new FormData();
formdata.append("targetIP", "10.10.1.145");
formdata.append(
"user",
JSON.stringify({
username: "user",
password: "auth",
})
);
formdata.append("fileBuffer", fs.createReadStream("test.bin"));
let bodyContent = formdata;
const url = "http://localhost:3000/loader/load";
let reqOptions = {
url,
method: "POST",
headers: headersList,
data: { bodyContent },
};
axios.request(reqOptions).then(function (response) {
console.log(response.data);
});
At the controller this is the request body i get
{
bodyContent: {
_overheadLength: 380,
_valueLength: 48,
_valuesToMeasure: [ [Object] ],
writable: false,
readable: true,
dataSize: 0,
maxDataSize: 2097152,
pauseStreams: true,
_released: false,
_streams: [
'----------------------------092840744027446269037569\r\n' +
'Content-Disposition: form-data; name="targetIP"\r\n' +
'\r\n',
'10.10.1.145',
null,
'----------------------------092840744027446269037569\r\n' +
'Content-Disposition: form-data; name="user"\r\n' +
'\r\n',
'{"username":"user","password":"auth"}',
null,
'----------------------------092840744027446269037569\r\n' +
'Content-Disposition: form-data; name="fileBuffer"; filename="test.bin"\r\n' +
'Content-Type: application/octet-stream\r\n' +
'\r\n',
[Object],
null
],
_currentStream: null,
_insideLoop: false,
_pendingNext: false,
_boundary: '--------------------------092840744027446269037569'
}
}
How can i get the body in the form of object with only the attrbutes of the DTO?
Eventually i got a method which recived the same type of object and i want to call it like this:
#Controller('loader')
export class KeyLoaderController {
#Post('load')
async load(#Body() body: LoadFileRequest, #Req() request) {
return await loadFile(body);
}
}
EDIT:
I changed the code a bit and now if i send the request from VS code thunder client it works fine(sort of):
#Controller('loader')
export class KeyLoaderController {
#Post('load')
#UseInterceptors(FileInterceptor('fileBuffer'))
async load(#Body() body, #UploadedFile() file) {
console.log(body);
console.log(file);
}
}
When I send this way (The code on the right is the generated code by the extension, Which does not act the same way when I use it):
This is the body and file I get:
[Object: null prototype] {
targetIP: '10.10.1.145',
user: '{ "username": "user", "password": "0123456789"}'
}
{
fieldname: 'fileBuffer',
originalname: 'test.bin',
encoding: '7bit',
mimetype: 'application/octet-stream',
buffer: <Buffer ... ... 119 more bytes>, size: 169
}
But when i take the code i generated in VS code thunder client (which is at axios request in this post) I still get the body like before (again, as mention in the post)

If you're sending a multipart/form-data request, you need a form data body parser installed on the server. You can either use the FileInterceptor (or one of the derivatives of it), or bind multer as a middleware for the entire server. This will allow for the parsing of multipart/form-data requests.
In your axios call, remove the brackets around bodyContent so it becomes data: bodyContent. You aren't sending an object of form data you are just sending formdata itself

Related

How to set the Params with id having key and value and pass id dynamically from the server in calling the API

I am able to call the API ,I have set the params with id having key and values which needs to be pass dynamically as received from the server (ex:s1,s3,s4..these are sensor names received from the server) and I have to pass these sensor names dynamically .
.service.ts
export class DashboardService {
public sensors: any[];
constructor(private http: HttpClient, private router: Router) {
}
sensorstart(tokenstr) {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Token ' + tokenstr
}),
params: new HttpParams().set('id', JSON.stringify(this.sensors.map(itm => itm.name)))
};
this.http.get(environment.apiUrl + '/api/sensors/start?' + this.id, httpOptions).subscribe(
(senst: any[]) => {
// localStorage.setItem("senst",JSON.stringify(senst));
console.log('senst:', JSON.parse(localStorage.getItem('senst')));
this.router.navigate(['/dashboard']);
},
err => {
console.log('Error', err);
}
);
}
}
.component.ts
this.jammerstart();
--some code--
sensorstart(){
this.senst=JSON.parse(localStorage.getItem("senst"));
console.log("senst",this.senst)
}
But in console It is showing
{
"status": true,
"action": "sensor started"
}
But I want to show the sensor name in action what I have called dynamically in calling the API.
I want the below result which changes dynamically in console
{
"status": true,
"action": "sensor j3 started"
}
How can I Pass the id values (sensor names s1,s2,s3--)dynamically in calling the API.
The question seems to be how pass an dynamic array (like s1,s2,s3) to the server.
This is actually depending how the server API has been designed.
If you build the HttpParams like you did:
const sensors: any[] = [{name: 's1'},{name: 's2'},{name: 's3'}];
const httpOptions = {
params: new HttpParams().set('id', JSON.stringify(sensors.map(itm => itm.name)))
};
this.httpClient.get('api/sensors/start', httpOptions).subscribe();
The request url will be something like this:
/api/sensors/start?id=%5B%22s1%22,%22s2%22,%22s3%22%5D
Which is the encoded string for ["s1","s2","s3"]
If you want to send it like this
/api/sensors/start?id=s1&id=s2&id=s3
You may have to do this:
const sensors: any[] = [{name: 's1'},{name: 's2'},{name: 's3'}];
let httpParams = new HttpParams();
for (const sensor of sensors) {
httpParams = httpParams.append('id', sensor.name);
}
const httpOptions = {
params: httpParams
};
this.httpClient.get('api/sensors/start', httpOptions ).subscribe();
You have to adapt the way you are sending your array depending what the server side is accepting.
The server could also accept another shape:
/api/sensors/start?id[]=s1&id[]=s2&id[]=s3
or
/api/sensors/start?id%5B%5D=s1&id%5B%5D=s2&id%5B%5D=s3
or
/api/sensors/start?id=s1,s2,s3
https://medium.com/raml-api/arrays-in-query-params-33189628fa68

How to pass form field values in the body while making a http post service call

Working on Angular http post service call, and have the api from a java service, to get the response from this service i will have to pass data/request parameters to the url, which i am doing via giving a var called body and then passing this with url
I am using angular reactive forms, and from the form fields here i want to send the request parameters to the body
Like when the user fills the form he submits and this goes as a request and he gets a certain data after calculation from these fields as response
This is my service call where i am passing hard coded values, but here how could i pass the formcontrolname values to the body ???
getPoll(): Observable<PollData[]> {
const headers = new HttpHeaders({ 'Content-Type': 'application/json'});
let body = '{"auth": { "accesskey": "", "signature": "" }, "data": { "v_age": 0, "v_rto_name": "Delhi East: Anand Vihar", "aa_status": false, "tax_type":"IGST","debug_flag":false }}';
return this.http
.post<PollData[]>(this.apiUrl + this.premiumUrl, body, { headers: headers })
.pipe(
tap(data => console.log('getPoll: ' + JSON.stringify(data))),
catchError(this.handleError)
);
}
When i pass the hard coded values i get a response, but how could i make it dynamic to be loaded from the reactive form fields.
You can pass your form values as a parameter inside your component service call.
submitForm() {
this.yourService.getPoll(this.yourForm.value).subscribe(...);
}
Get the parameters in your getPoll function and
getPoll(yourFormValues): Observable<PollData[]> {
const headers = new HttpHeaders({ 'Content-Type': 'application/json'});
let body = '{"auth": { "accesskey": "", "signature": "" }, "data": { "v_age": yourFormValues.v_age, "v_rto_name": yourFormValues.v_rto_name, "aa_status": yourFormValues.aa_status, "tax_type":yourFormValues.tax_type,"debug_flag":false }}';
return this.http
.post<PollData[]>(this.apiUrl + this.premiumUrl, body, { headers: headers })
.pipe(
tap(data => console.log('getPoll: ' + JSON.stringify(data))),
catchError(this.handleError)
);
}

LinkedIn not reading JSON request

Trying to 'share' on LinkedIn: https://developer.linkedin.com/docs/share-on-linkedin
Which is basically a POST to 'https://api.linkedin.com/v1/people/~/shares?format=json'
in its simplest form is with json:
{
"comment": "Check out developer.linkedin.com! http://linkd.in/1FC2PyG",
"visibility": {
"code": "anyone"
}
}
This requires setting http headers:
Content-Type: application/json
x-li-format: json
I'm trying to do this using OAuth.io, but LinkedIn seems to be still reading the body in XML.
See my example here: https://jsfiddle.net/Lv3jtpkb/2/
I get the following error from it:
Invalid xml {Element 'share#http://api.linkedin.com/v1' with element-only content type cannot have text content.}
I have checked if from OAuth.io server to LinkedIn API endpoint the headers specified here at frontend were somehow altered and can confirm that they have not been.
You're almost there. There are 2 errors.
Your data are formatted as a JS object. The method you're using doesn't seem to be converting the object to JSON automatically.
This line of code isn't doing anything, and is causing exceptions:
.then(user => { console.log("next:",user) })
Remove it.
Working code snippet:
$('#linkedin-button').on('click', function() {
// Initialize with your OAuth.io app public key
OAuth.initialize('A5oDtHv-oUEVlR7q7hDolXxC7RE');
alert('init');
OAuth.popup('linkedin2').then(linkedin => {
alert('logged in');
linkedin.post({
url: "/v1/people/~/shares?format=json",
data: JSON.stringify({
"comment": "Hello world!",
"visibility": {
"code": "anyone"
}
}),
headers: {
"x-li-format": "json",
"Content-Type": "application/json"
}
}).then(data => {
console.log("success:", data);
}).fail(err => { console.log("err:",err) });
})
})
Success in console:

Node request module not setting Content-Type as application/json

I am having a strange issue with my NodeJS/Koa.js app where an HTTP request I am making is returning with this error message:
{"Message":"The request entity's media type 'application/x-www-form-urlencoded' is not supported for this resource."
Now, when I make the same request using postman I get correct results back so I have deduced that something is awry in my code. I just can't seem to figure it out. Here is my code to make the request and the payload.
// Content Type
if(options.contentType === 'json') {
headers['Content-Type'] = 'application/json';
}
// Content Length
if(options.contentLength) {
reqHeaders['Content-Length'] = options.contentLength
}
if(headers) {
for(let key in headers) {
if(!headers.hasOwnProperty(key)) {
continue;
}
reqHeaders[key] = headers[key];
}
}
const payload = {
headers : reqHeaders,
url : url,
method : requestType,
timeout : 10000,
form : vars,
followRedirect: true,
maxRedirects: 10,
body : '' || options.body
};
return new Promise(function(resolve, reject) {
request(payload, function(error, response, body) {
if(response) {
if(!error && response.statusCode === 200) {
resolve(response, body);
} else {
if(response.statusCode === 401) {
console.log('token expired');
}
reject(response, body);
}
}
});
});
Payload:
{
"headers": {
"Cookie": "XDEBUG_SESSION=PHPSTORM",
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJkZWdvdWxkLWxvZ2luLmRldiIsImFjY291bnQiOiI1OTY3NmFmZmYyOWE1NWI2MTViOWFiMWEiLCJhdXRoTGV2ZWwiOjAsImlhdCI6MTUwNTg5OTQ3MX0.r-XaeTsQTjSkab9SNjrHgnh6lrgNP0uJCaDIV22A6gM",
"Content-Type": "application/json"
},
"url": "http://54.***.***/api/Report/History",
"method": "POST",
"timeout": 10000,
"form": {
"AccountId": "59676afff29a55b615b9ab1a",
"StartDate": "2017-09-19T10:11:47.0266607+00:00",
"EndDate": "2017-09-19T10:11:47.0266607+00:00",
"VIN": "SALLAK"
},
"followRedirect": true,
"maxRedirects": 10
}
As you can see, I have the correct Content-Type headers in my headers object that is in the payload I pass to the request function but it still seeems as if it is sending as x-www-form-encoded. Can anyone see what may be going wrong here?
Thanks
The docs read:
form - when passed an object or a querystring, this sets body to a querystring representation of value, and adds Content-type:
application/x-www-form-urlencoded header.
and
json - sets body to JSON representation of value and adds Content-type: application/json header.
You are using form, so it overwrites the header. Try to use json instead. It will overwrite your header anyway, but the value will be 'application/json' which should be okay.
a couple of suggestions if I may:
You can use Object.assign to set the headers in the object.
Setting json: true will take care of putting the right content-type header.
You shouldn't have to set the content-length manually, it's a tricky thing to do. Let request deal with that.
If you want to return a promise, consider using request-promise with fullResponse enabled to check for token expiration.
if(headers) {
Object.assign(reqHeaders, headers);
}
const payload = {
headers: reqHeaders,
url: url,
method: requestType,
timeout: 10000,
json: true,
followRedirect: true,
maxRedirects: 10,
body: options.body || {},
fullResponse: true
};
return rp(payload).then(function(response) {
if (response.statusCode === 401) {
throw Error('Token expired');
}
return response.body;
});

How to return a JSON object from an Azure Function with Node.js

With Azure Functions, what do you need to do to return a JSON object in the body from a function written in node.js? I can easily return a string, but when I try to return a json object as shown below I appear to have nothing returned.
context.res = {
body: jsonData,
contentType: 'application/json'
};
Based on my recent testing (March 2017). You have to explicitly add content type to response headers to get json back otherwise data shows-up as XML in browser.
"Content-Type":"application/json"
res = {
status: 200, /* Defaults to 200 */
body: {message: "Hello " + (req.query.name || req.body.name)},
headers: {
'Content-Type': 'application/json'
}
};
Full Sample below:
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
context.log(context);
if (req.query.name || (req.body && req.body.name)) {
res = {
// status: 200, /* Defaults to 200 */
body: {message: "Hello " + (req.query.name || req.body.name)},
headers: {
'Content-Type': 'application/json'
}
};
}
else {
res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
context.done(null, res);
};
If your data is a JS object, then this should just work, e.g.
module.exports = function(context, req) {
context.res = {
body: { name: "Azure Functions" }
};
context.done();
};
This will return an application/json response.
If instead you have your data in a json string, you can have:
module.exports = function(context, req) {
context.res = {
body: '{ "name": "Azure Functions" }'
};
context.done();
};
Which will return an application/json response because it sniffs that it is valid json.
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
if (req.query.name || (req.body && req.body.name)) {
context.res = {
// status: 200, /* Defaults to 200 */
body: {"data":"Hello"},
headers: {
'Content-Type': 'application/json'
}
};
}
else {
// res = {
// status: 400,
// body: "Please pass a name on the query string or in the request body"
// };
}
context.done(null,res);
I would like to add one more point. Apart from making the body: a JSON object, the request should also contain proper headers telling server what content type we are interested in. I could see that same Azure function when just invoked via browser using URL gives XML response, but when invoking from script or tools like Postman it gives JSON.
I feel like the answer has been given but it hasn't been clearly presented so I thought I'd answer as well in case it will help anyone coming behind me. I too have created a function that most definitely returns a Javascript object but if I copy and paste the URL in the Azure Function UI and just open a new tab in Chrome and try to view the output, I actually get back an XML document that tells me there's an error (not surprising there's an error as many characters in the Javascript would have blown up the XML). So, as others have mentioned, the key is sending the appropriate headers with your request. When you copy/paste the URL into your browser, the browser is sending a request header that looks similar to this:
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
When that happens, you see the XML return as described in this link:
https://github.com/strongloop/strong-remoting/issues/118
In order to get around this problem and see what the data would look like with a JSON request, either use a utility like Postman:
https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en
Accept: application/json
Or use a CURL command and pass in the proper Accept header.
As you can see in the screenshot above, when I provided the proper header, I get back the JSON response I would expect.
You can also use JSON.stringify() to make a valid json string out of your js-object:
jsonData = { value: "test" }:
context.res = {
body: JSON.stringify(jsonData)
};