I'm creating two APIs with NodeJS, Express, and TypeScript. One API will take a request with a content type of multipart/form-data, and will use the body in the request to make another request to a second API.
I'm using Postman, so the chain of request looks something like this
Postman -> First API -> Second API
I use node-fetch to make a request from the first API to the second one. The body of the request is a FormData, which contains some files and key-value pairs.
const form = new FormData();
// File for profile picture
const profilePictureBuffer = await (await fetch(user.profilePicture)).buffer();
form.append('profilePicture', profilePictureBuffer);
// File for ID Card
const idCardBuffer = await (await fetch(user.idCardUrl)).buffer();
form.append('idCard', idCardBuffer);
// This part iterats over the obsect of 'user',
// which contains other key-value pairs
Object.entries(user).forEach((data) => {
form.append(data[0], data[1]);
});
// Make POST request to second API
const pinterUser = await fetch(secondAPIURL, {
method: 'post',
body: form,
headers: form.getHeaders()
});
I ran both of the APIs on localhost so that I can monitor the logs for any bugs. As I make a request from Postman to the first API, then the first API make another request to the second API, I got the following error log in the terminal for the second API
TypeError: Cannot read property '0' of undefined
After some investigation, I found out that, in the second API, the req.body and req.files are empty objects. This means that Express did not parse the incoming request. Note that I've also already a multer middleware to handle the files in the request.
Furthermore, I have added the following lines of code in my server.ts file for the second API
/** Parse the body of the request */
router.use(express.urlencoded({ extended: true }));
router.use(express.json());
However, when I tried making the request from Postman, it returns a successful response.
I'm not really sure what's going on here. I've tried looking for some answer regarding this similar issue, but most of them suggest adding urlencoded and json, or using some other library to handle parsing form data.
In my case, the first suggestion doesn't solve my problem since I already added them from the start, and the latter is what I'm trying to avoid.
I wonder if anybody could point out what I was missing here? Thanks in advance
Related
I have this project I’m working on and I am using node/express + Axios to retrieve data from a third-party API.
I am attaching an image of the response I am getting from my postman but,
I am having an issue figuring out a way to access and manipulate a specific set of data.
If there are any resources anyone could share that would help I would appreciate it.
as of now I just have:
axios.get('apiUrl')
.then((response) => {
const cardData = response.data;
res.send(cardData);
}
This is the response I get:
for example, I’d like to access the “abilities” property.
Since that property is within the “0" object within the response object, I’m a bit confused as to how to navigate this in the code.
I’ve tried response.data.0 but that doesn’t seem to work.
function retrieve(callback){
//I don't get why you are using request.send here. Are you routing the response elsewhere?
//If you are just consuming a service, use Axios with a callback instead.
//If you're not routing it you won't need Express.
axios.get('apiUrl').then(response => callback(response));
}
function clbk(response){
let obj = JSON.parse(response); //In case you are receiving a stringified JSON
//Do whatever you want with the data
//If you have a number as a key, access it by using []. So, considering your example:
response.data[0]
}
//CALL:
retrieve(clbk);
Im new in backend development (using NodeJs Express).
Its very basic question (I didn't find any good tutorial about it)
Question is:
I have this line of code:
app.get('/test', function (req ,res){
res.send('test');
});
What I wanna do is: BackEnd only sends res to FrontEnd, if FrontEnd send some JSON first.
Like Backend will show Something to FrontEnd, only if FrontEnd send JSON first;
How to handle it? What code to write?
Or what to type in google search to find this kind of tutorial
You are building a REST API with node. In REST we don't keep states. When we receive a request we process and respond. In the Front end, you can do wait until the response is received. use promises, async-await or callbacks to wait until the response in the Front end. Use these methods to connect with back end from front-end axios, fetch. To process the incoming JSON body use body-parser. Based on the request body you can process and send the response. PS: Every request should be given a response. That's how REST behaves.
In Query
yourbackend.com/test?message=welcomeToStackOverflow
This is how you can access with in query:
const {message} = req.query;
console.log(message);
// welcomeToStackOverflow
In Params
yourbackend.com/test/:message
This is how you can access with in params :
const {message} = req.params;
console.log(message);
// welcomeToStackOverflow
Here you have working example : https://codesandbox.io/s/trusting-rosalind-37brf?file=/routes/test.js
When sending the first request to the calendarView API, the request does not return or timeout. This only happens to some of the requests and seems to happen only on the first request (perhaps because the first request has larger response sizes).
An example request:
GET /me/calendarView/delta?startDateTime=2019-06-27T22:00:00.000Z&endDateTime=2019-09-08T13:17:30.659Z
The current solution I found was reducing the odata.maxpagesize to a very small number (currently 2 is the highest number which works for all calendars I have tested).
The requests are sent using the nodejs client "#microsoft/microsoft-graph-client": "1.7.0".
// Initialize client with credentials
const client = graph.Client.init({
authProvider: done => {
done(null, credentials.access_token);
}
});
const url = "/me/calendarView/delta?startDateTime=2019-06-27T22:00:00.000Z&endDateTime=2019-09-08T13:17:30.659Z
console.log("Request start")
const result = await oAuth2Client
.api(url)
.header("prefer", "odata.maxpagesize=10")
.get();
console.log("Got result", result);
Here the last console.log is never called.
The expected result is that the request returns, at least with an error code. I also expect the API to be able to handle a lot more items than 2 per page.
The current solution with setting a small maxpagesize works temporarily, however, I expect that there is another root cause issue.
Any idea what is wrong, and how this can be resolved?
After a lot of debugging i traced the issue to the node library. When asking for a raw response from the API, I got back the result regardless of page size.
The solution was to manually parse the response myself, after asking for the raw response from the library. This was based on the implementation in the library at https://github.com/microsoftgraph/msgraph-sdk-javascript/blob/dev/src/GraphResponseHandler.ts#L98
I could not find the root cause issue in the library, and ended up just parsing it on my end. I also analysed the raw response from the API, but the content-type header was correctly application/json, and the response status was 200 OK.
const rawResponse = client.api(url).response(ResponseType.RAW).get()
const parsedResponse = await rawResponse.json()
I'm facing an issue when I want to pass some data through http.post from my angular client to my node.js server.
Here is the thing, passing text with JSON.stringify(my text) works fine, but given that I want to pass a file + my text, I would like to use formData.
When I try to get back the data in the server side, my req.body is empty, and i'm not able to retrieve the data.
Here is my client side code :
[...]
var formData = new FormData();
formData.append('name', product.name);
formData.append('benefits_detail', product.benefits_detail);
formData.append('sections', product.sections);
formData.append('image', product.image); // image is my file
return this.http.post('http://localhost:3000/product', formData, {headers: headers}).map(........)
Then my server, where I try to get back my data :
router.post('/', function (req, res, next) {
console.log('req.body');
console.log(req.body);
console.log(req.body.formData);
...
Here the console.log are empty like showing : {}
Anybody can help with this ?
Thanks you
It looks like you're not using any body parsing middleware, which is required.
From the Express documentation for req.body
Contains key-value pairs of data submitted in the request body. By default, it is undefined, and is populated when you use body-parsing middleware such as body-parser and multer.
Try using body-parser
For uploading images to a server, you could try to use the Ng File Upload directive. It has a directive to select the file in HTML and then to Upload the file to the server. If you are already selecting the image, I believe you can just use the Uploading part in JS to send the image (have never tried using the Upload without the file selector in HTML, but It should work).
However, this solution would require you to send two requests though, one for the data and another for the image.
I'm creating an API using Express 4.0.0 and one of the routes takes a POST. Currently I'm just trying to have it echo a name sent in the request parameters. The response is a JSON object, but the request expects form fields.
users.post '/user', (req, res) ->
res.json name: req.params.name
My test sets the type() to form which should allow send() to pass the hash as POST parameters/fields.
describe 'POST /user', ->
it 'should echo the name sent', (done) ->
request app
.post '/user'
.type 'form'
.send name: 'Foo'
.expect '{"name":"Foo"}'
.end done
Regardless, my test fails and in Express, my req.params is empty, req.param('name') comes up undefined and req.body is also empty.
Is there some req.fields attribute I'm not aware of, or is my test flawed somehow?
tl;dr: You need to parse the body to get that, you can do app.use(require('body-parser')()) and then change your code with name: req.param('name').
So express(and actually node.js http server) will call the request call whenever a http request header have been received and not the body of the request. You have to explicitly read and wait for the body to come and parse it yourself.
Luckily there are express middleware modules that parses the body for you. In this case you are sending a urlencoded/form body, so you need to parse it as such. Use any of these modules according to their examples:
body-parser
body
Assuming you use body-parser, then if you want it to parse the body for all routes then just do app.use(require('body-parser')(). If you want it to parse the body for a particular route then do this:
bodyParser = require('body-parser')()
app.post '/user', bodyParser, (req, res) ->
res.json name: req.param('name')
Once you got the body parsing right, then you can access it either through req.body(for example req.body.name) property or req.param function(for example req.param('name')). The latter will also search through query string and url parameters.
Note that if you want to parse a body with attached files(for uploading files) you need a multipart parser and not just a urlencoded one:
connect-multiparty
connect-busboy