Axios GET request sends empty req.body to server - node.js

I'm trying to make a GET request in my React app but Axios seems to send an empty request body for some reason. I know there's (most likely) nothing wrong in the backend as I'm able to make the requests perfectly fine with Insomnia. I've tried the following till now and none of the seem to work:
const response = await axios.get(URL, { email })
const response = await axios({
method: "get",
url: URL,
data: { email }
})
I'm using the express.json() middleware in the backend.

From the RFC 7231
A payload within a GET request message has no defined semantics;
sending a payload body on a GET request might cause some existing
implementations to reject the request.
So do not rely on body data for GET request and use appropriate HTTP method like POST, PUT etc.
Moreover, if you want to send Query params with your GET request, both code snippets you shared above will not work. Instead do it like below.
// using get method
const response = await axios.get(URL, {
params: {
ID: 12345
}
});
// using Axios API
const response = await axios({
method: "get",
url: URL,
params: {
ID: 12345
}
});

Related

Body of a request is empty [duplicate]

I have a React application where I am changing POST method to GET with the request body as it is. It works fine with POST request however when I change the method to GET, it gives me error-
message: "org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public
My Front End Code-
export const setData = (getData) => dispatch => {
axios({
method: 'GET',
url: 'http://localhost:8080/api',
headers: {
'Content-Type': 'application/json'
},
data: getData
})
.then (response => {
dispatch({
type: API_DATA,
payload: response.data
})
dispatch({
type: SET_SEARCH_LOADER,
payload: false
})
})
.catch(function(error) {
})
}
Can someone let me know what I am missing here. As per my understanding, http allows to have a request body for GET method.
As per my understanding, http allows to have a request body for GET method.
While this is technically true (although it may be more accurate to say that it just doesn't explicitly disallow it), it's a very odd thing to do, and most systems do not expect GET requests to have bodies.
Consequently, plenty of libraries will not handle this.
The documentation for Axois says:
// `data` is the data to be sent as the request body
// Only applicable for request methods 'PUT', 'POST', and 'PATCH'
Under the hood, if you run Axios client side in a web browser, it will use XMLHttpRequest. If you look at the specification for that it says:
client . send([body = null])
Initiates the request. The body argument provides the request body, if any, and is ignored if the request method is GET or HEAD.
If you want to send parameters with get request in axios, you should send parameters as params.
If you want to set "Content-type":"application/json" and send params with get request, you should also send an empty data object.
For example:
const AUTH_TOKEN = 'Bearer token'
const config = {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': AUTH_TOKEN,
},
data: {},
params: {
"post_id": 1
}
}
axios.get("http://localhost/api/v1/posts/", config)
This is not axios, the error origniates from the java backend you're talking to. The public field in your request body is missing.
If you just want to send the data as parameters (which would be odd), pass it using params instead of data (as shown here: https://github.com/axios/axios#example).
I personally don't think your API should support GET with a request body (talk to the devs and ask for documentation).

Sending FormData through 2 API's (NextJS)

So I'm sending some formdata, including images to my backend. To obfuscate/secure my backend even more - I'm learning that it's good practice to take advantage of the NextJS api (send calls from client to NextJS server/api, NextJS api acts as a middleman and sends data to backend api). I'm also using Auth0 - and the most secure way to get tokens is via the NextJS api itself.
I have no issues reading the data on my backend when I make an api call directly from client to backend. However, I'm having issues actually getting the data (primarily the images/files) OUT of the request on my NextJS api for repackaging and sending to my actual backend. I can't use FormData within the NextJS api either, so I'm just confused all around.
Client submit function:
const handleSubmit = async (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("title", brand.name);
formData.append("slug", brand.slug);
formData.append("bio", brand.bio);
formData.append("logo", brand.logo[0]);
const response = await fetch("/api/brands", {
method: "post",
body: formData,
});
});
NextJS api code (does not work - I am getting an access token perfectly, it's just the sending of the formdata/files I'm stuck on)
import { getAccessToken, withApiAuthRequired } from "#auth0/nextjs-auth0";
export default withApiAuthRequired(async function products(req, res) {
const { accessToken } = await getAccessToken(req, res, {});
const response = await fetch("http://localhost:5000/brands", {
method: "post",
headers: {
Authorization: `Bearer ${accessToken}`,
},
body: {
title: req.body.title,
slug: req.body.slug,
bio: req.body.bio,
logo: req.file,
},
});
const products = await response.json();
res.status(200);
});
You might be missing the "Content-Type: multipart/form-data" on the 2nd API call that you make. On the client side it's inferred from the FormData object, but on the server side you have to specify it manually. Altough, I couldn't find a way to do that on the server. This could indicate that the use case is wrong, I think making another request to your own server is a no-no. Next.js is meant to use this function called "withApiAuthRequired" as a wrapper, from which you call your services, or business logic. There is no need to make a second HTTP Request here.

What is the Axios equivalent of req.pipe(request()) / Pipe express request data into Axios request

Using request you can forward a POST multipart/form-data request from express to another server without modifying the body/parameters of the initial request and then return the response from the other server to express. With axios this feature appears to be missing.
CODE:
header
const request = require('request');
const axios = require('axios');
const express = require('express');
const app = express();
app.listen(3000);
const FORWARD_URL = 'https://example.com/'
Working example using request
app.post('/test/0', (req, res) => {
req.pipe(request(FORWARD_URL)).pipe(res);
})
Attempt #1
app.post('/test/1', (req, res) => {
req.pipe(axios.post(FORWARD_URL)).pipe(res);
})
// internal/streams/readable.js:827
// dests[i].emit('unpipe', this, { hasUnpiped: false });
// ^
// TypeError: dests[i].emit is not a function
// at IncomingMessage.Readable.unpipe (internal/streams/readable.js:827:16)
// at unpipe (S:\_Work\[REDACTED]\node_modules\unpipe\index.js:47:12)
// at send (S:\_Work\[REDACTED]\node_modules\finalhandler\index.js:306:3)
// at Immediate.<anonymous> (S:\_Work\[REDACTED]\node_modules\finalhandler\index.js:133:5)
// at Immediate.<anonymous> (S:\_Work\[REDACTED]\node_modules\express\lib\router\index.js:635:15)
// at processImmediate (internal/timers.js:466:21)
Attempt #2
app.post('/test/2', (req, res) => {
req.pipe(axios({
url: FORWARD_URL,
method: 'POST',
responseType: 'stream'
})).pipe(res);
})
// SAME ERROR AS ABOVE
Attempt #3
app.post('/test/3', async (req, res) => {
const axiosRequest = await axios({
url: FORWARD_URL,
method: 'POST',
responseType: 'stream',
data: req
})
axiosRequest.data.pipe(res);
})
// server at FORWARD_URL receives improperly formatted request body, changing request content-type headers has no affect
// ------WebKitFormBoundaryc4BjPwpdR4mG7CFN
// Content-Disposition: form-data; name="field_name"
//
// field_value
// ------WebKitFormBoundaryc4BjPwpdR4mG7CFN--
A similar issue has been addressed here, the accepted answer, while not very clear, does answer the question, however, only covers GET & POST application/x-www-form-urlencoded requests, This is regarding POST multipart/form-data requests.
Ideally I'm looking for a solution that functions identically to the request example using axios, this works great for my use case as it includes file uploads, because of this, I want to avoid parsing the body and instead just forwarding it onto the next server.
Testing of the above routes was performed with postman
Changing the Axios request headers to the equivalent ones obtained from the original request, resolved the error for me.
Code:
const axiosRequest = await axios({
url: FORWARD_URL,
method: 'POST',
responseType: 'stream',
data: req
})
I have just copied the original request headers to the new request
const axiosRequest = await axios({
url: FORWARD_URL,
method: 'POST',
responseType: 'stream',
data: req,
headers: {
...req.headers
}
})
The following code worked for me for POSTing streams with content type multipart/form-data:
app.post('/test/0', async (req, res) => {
const response = await axios.post(FORWARD_URL, req, {
headers: {
'content-type': req.headers['content-type'],
},
});
return res.send(response.data);
})
In my case I did not need to set the responseType header to stream. This might depend on the response you are getting from the API.
What is important is:
posting the entire request object (not just the body!)
setting the content-type header of the outgoing request to the same value as the incoming request
Passing just the body of the incoming request to the outgoing request will result in the API (the reader of the stream) endpoint receiving an empty object (which it will initialise with default values).
Passing the body of the incoming request and setting the content-type header will result in the API endpoint receiving a null body.

axios multipart request failing

Im trying to send a post request for convert doc to pdf using a service. The service is working fine with postman, y can send the doc to the endpoint and it return me the pdf, nice.
But i cant make the request from my nodejs server, im using axios to make the request and it fails with this is the error:
{"time":"2019-09-24T14:39:46.89404124Z","id":"","remote_ip":"000.00.000.00","host":"pdf-doc-convert.example","method":"POST","uri":"/convert/office","user_agent":"axios/0.19.0","status":500,"error":"getting multipart form: no multipart boundary param in Content-Type","latency":221460,"latency_human":"221.46µs","bytes_in":0,"bytes_out":36}
This is the service documentation, is a simple post with a multipart/form-data request (come with a curl example):
https://thecodingmachine.github.io/gotenberg/#office
And this is my request with axios:
async function request() {
const endpoint =
"http://pdf-doc-convert.example/convert/office";
const data = new FormData();
data.append('files', fs.createReadStream("my/file/path/example.docx"));
const config = {
headers: {
"content-type": "multipart/form-data"
}
};
const pdf = await axios.post(endpoint, data, config);
}
How can i make the request?
Maybe the quickest way to debug this would be to intercept the call you're making with the Axios request using Postman Intercept and to compare the cURL request info from the one that's working to the one that's not. It could be either a headers issue or file encoding issue.
I've encountered something similar previously and this could be related to the formData headers which require additional configuration in Axios as mentioned here: https://github.com/axios/axios/issues/789#issuecomment-508114703
const data = new FormData();
data.append("firstFile", fs.createReadStream(firstFilePath), { knownLength: fs.statSync(firstFilePath).size });
const headers = {
...data.getHeaders(),
"Content-Length": data.getLengthSync()
};
const endpoint = "http://pdf-doc-convert.example/convert/office";
const pdf = await axios.post(endpoint, data, config);

POST request working on Postman but not on JS

Been trying for a couple of days but can't get this request to work on NodeJS, used several request modules (axios, request, node-fetch) but the returned body is blank, same goes for postman if raw option is not selected for body.
Here is how I need to format the body on postman for the request to work:
And this is my last iteration of the request, using node-fetch:
const rawResponse = await fetch(
urlRenfe,
{
method: 'POST',
headers: {
"Cookie": cookie,
"Referer": "https://venta.renfe.com/vol/infoPuntualidadTrenes.do",
"Accept": "*/*",
},
body: `callCount=1
windowName=
c0-scriptName=infoPuntualidadTrenesSvcAjax
c0-methodName=getInfoPuntualidadTrenes
c0-id=0
c0-e1=string:71500
c0-e2=string:X7090115
c0-param0=Object_Object:{cdgoEstacion:reference:c0-e1, terminal:reference:c0-e2}
batchId=1
instanceId=1
page=%2Fvol%2FinfoPuntualidadTrenes.do
scriptSessionId=6ngaztWVMGx8q6B16ABXAlLU1Om/LwA22Om-u7tpxIlXl`
}
);
const response = await rawResponse.text();
I know 100% the headers, url and method are ok, it has to be the body, either on the library or my configuration for it.
Thanks a lot if you give me a hint on how to solve this.

Resources