Empty response in API from Dio.Post method in Flutter - node.js

I have been trying to connect to a local Node JS API using Flutter Web. I am using the Dio dart Package with a GET and a POST method, however, the response of my POST method does not return anything. See below a few instances of code and what I am seeing:
On my Node JS app I am receiving information from flutter:
'Server is listening on port 8000'
Successfully connected
/login2
{}
The /login2 path and the {} are a console.log in my API from the Flutter incoming data. See now the Dio.post method:
Future post(String path, Map<String, dynamic> data) async {
try {
final result = await _dio.post(path, data: data);
return result.data;
} catch (e) {
print(e);
throw ('Error en el POST');
}
}
Also tried with HTTP, heres the piece of code:
Future post2(String id, String password) async {
print(id);
print(password);
final response = await http.post(
Uri.parse('http://localhost:8000/login2'),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode({'user': id, 'password': password}),
);
print(response);
}
I have tried with Postman and this is what I get:
/login2?user=10002&password=123456
{ user: '10002', password: '123456' }
That is both the path and the query {} from the same console.log that is empty from Flutter, meaning that my Node server is indeed receiving data.
Trying as per #Wali Kan suggestion with the Postman configuration:
Future post(String path, Map<String, dynamic> data) async {
final String formData = data.toString();
var headers = {'Content-Type': 'text/plain'};
var request =
http.Request('POST', Uri.parse('http://localhost:8000' + path));
request.body = formData;
print(request.body);
http.StreamedResponse response = await request.send();
print(response);
request.headers.addAll(headers);
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
} else {
print(response.reasonPhrase);
}
Still receiving /login2 and {} on the API side.
What I am missing is how to succesfully receive Flutter data so that I can complete the login process on my Node API and then redirect to the user profile page.
Any recommendations on what to test or check? If you need me to share any more pieces of the code let me know, been stuck here for many hours now... Thank you for your time.

headers
HttpHeaders.acceptHeader: "json/application/json",
HttpHeaders.contentTypeHeader: "application/x-www-form-urlencoded"
make sure not to use FormData.fromMap({}) just send your data as normal object and don't forget to include the application/x-www-form-urlencoded content type in your headers.
in case your server is running express make sure you have these middleware before processing the request
app.use(express.json())
app.use(express.urlencoded({ extended: true }));

Related

Nodejs + Axios Post returns undefined value

I am using React + NodeJS & Axios but have been trying to send a post request but experiencing difficulties.
The request seems to be posting successfully, but all actions at the nodejs server is returning in the "undefined" data value, even if the data is passed successfully shown in the console.
REACT
const fireAction = (data1, data2) => {
const data = JSON.stringify({data1, data2})
const url = `http://localhost:5000/data/corr/fire`;
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'AUTHCODE',
}
}
axios.post(url, data, config)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
fireAction("Oklahoma", "Small apartment")
NODE
app.post('/data/corr/fire', async (req, res) => {
try {
const data = req.body.data1;
console.log(data)
} catch(e) {
res.send({success: "none", error: e.message})
}
});
Result of node: "undefined"
I have added the following body parser:
app.use(express.json());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
I am not sure why this error is happening. I see there is similar questions to mine: however none of them are applicable as I'm using both express and body parser which is already suggested.
You're POSTing JSON with a content-type meant for forms. There's no need to manually set content-type if you're sending JSON, but if you want to manually override it, you can use 'Content-Type': 'application/json', and access the response in your route with req.body. If it does need to be formencoded, you'll need to build the form:
const params = new URLSearchParams();
params.append('data1', data1);
params.append('data2', data2);
axios.post(url, params, config);

form-data request body is empty

I'm trying to send an image and some data from an API to another. The image is stored in memory with multer. But when I want to send it, the body is just empty. I tried the same request with postman and it worked perfectly.
postman test
postman test image
server test
server test image
Here is some code. I removed some of it so you can read it better
export const saveImage = async ({ image, name, folder, options }: { image: any, name?: any, folder: string, options?: any }) => {
try {
const fd = new FormData();
fd.append("image", image.buffer, image.originalname);
if(options) {
fd.append("options[resize][height]", options?.resize?.height);
fd.append("options[resize][width]", options?.resize?.width);
}
if(name) fd.append("name", name);
fd.append("folder", folder);
fd.append("servideId", IMAGES_ID);
fd.append("serviceSecret", IMAGES_SECRET);
console.log(fd)
const formHeaders = fd.getHeaders();
const request = await axios.post(`${IMAGES_URL}/api/images`, {
headers: formHeaders,
body: fd
});
return request.data.id;
} catch (error) {
const { response } = error;
console.log(response.request.data)
if(error?.response?.data?.error) {
throw { statusCode: error.response.status, message: error.response.data.error }
}
console.error("Images API", error);
throw new InternalError("Something gone wrong");
}
}
When I log the FormData, I can see in _streams, the data that I'm sending, but the Images API receives an empty body.
FormData screenshot
If you need more information tell me, please! Thank you
The axios API for the post method is: axios.post(url[, data[, config]]). The second argument must always be the data you send along.
In your case axios thinks { headers: formHeaders, body: fd } is the body and the request ends up being application/json. To send a file with data using axios in Node.js, do the following:
const response = await axios.post(`${IMAGES_URL}/api/images`, fd, {
headers: {
...formHeaders,
'X-Custom-Header': 'lala', // optional
},
});
Your question inspired me to turn this answer into an article — Send a File With Axios in Node.js. It covers a few common pitfalls and you'll learn how to send files that are stored as a Buffer or coming from a Stream.
With Axios, you can directly use the form data without having to deal with headers.
axios.post("/api/images", fd)
If you wish to modify headers at some point in the future, you should pass the formData to the `data` field instead of `body`.
axios.post("/api/images", { headers: formHeaders, data: fd })
Correction in comments.
It can also be done using the Axios API syntax.
axios({method: 'post', url: 'url', data: fd, headers: {} })
In the backend, multer will add your files to req.file instead of req.body, if you have properly configured it to do so.

Problem with validating header/data fields from JQuery AJAX to Backend flask API

I'm trying to pass JWT token and data fields via Jquery and then consume those values in Flask.
So, my client side query looks like this:
function getData() {
var data = {
UserPoolId : 'AWS CognitoUser Pool Id',
ClientId : 'AWS CognitoUser client Id'
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(data);
var cognitoUser = userPool.getCurrentUser();
cognitoUser.getSession(function(err, session) {
if (err) {
alert(err);
return;
}
console.log('session validity: ' + session.isValid());
console.log(cognitoUser.signInUserSession.accessToken.jwtToken);
//
$.ajax({
url: "/api/v1/count",
type: "POST",
headers: { "X-Test-Header": cognitoUser.signInUserSession.accessToken.jwtToken },
// data: JSON.stringify(data),
data: JSON.stringify("{'UserPoolId': 'XXXX','ClientId': 'XXXX'}"),
contentType: 'application/json; charset=utf-8',
error: function(err) {
switch (err.status) {
case "400":
// bad request
break;
case "401":
// unauthorized
break;
case "403":
// forbidden
break;
default:
//Something bad happened
break;
}
},
success: function(data) {
console.log(data);
}
});
//
});
}
Now, in my serverside flask:
I tried to catch the token value using below: which is not working
#app.route("/api/v1/count", methods=["GET", "POST"])
def get_data_count():
if 'X-Test-Header' in request.headers:
headers = request.headers
app.logger.info(headers)
auth = headers.get("X-Test-Header")
app.logger.info('testing info log' + auth)
Also I tried to catch the data fields , using result = request.get_json() also not working.
I tried to inspect in chrome, and I don't see these values being added to the request header.
Can anyone suggest to me if I'm doing it correctly while passing the values from client to server? I also don't see console.log(cognitoUser.signInUserSession.accessToken.jwtToken) in the console log.
if not can anyone suggest to me, how to fix it?

Axios with react native not returning document and crashes app

Edit
Ok, so my method was just fine. For some reason, when I changed const response = await... to const res = await.. (or any other name besides "response" for that matter), it worked.. If this isn't a memory leak, then I have no idea what the heck this could have been. If anyone has any insight, I'd appreciate it.
I am making a request from my client:
const config = { headers: { "Content-Type": "application/json" } };
const data = JSON.stringify({ postId });
console.log('sending request'); // prints
const response = await axios.post(
`http://${GATEWAY}:5000/api/posts/single`,
data,
config
);
console.log("response received"); // never reached
But request received is never printed.
My backend route has this,
const post = await Post.findById(postId).populate("likes");
console.log(post); // prints post
return res.json(post);
And it appropriately find the post and logs it to the console. I'm not sure what's going on. No errors are printed anywhere and the app crashes after some time. It's probably waiting for the response.
Also, when I do
return res.json(null)
my client receives the response. But when I try to return the post or even if I try to
return res.json( { msg: "Hello World" } );
it hangs.
In addition, I do similar axios requests throughout the app -- they work and behave as expected. Not sure what I'm doing wrong here.
I've even tried,
const response = await axios.get(
`http://${GATEWAY}:5000/api/posts/${postId}`,
);
But it behaves and fails in the same way. If I let the request hang for too long, the app just gives up and crashes.
Note, also, I'm using axios instead of axios-react-native
Are you sure it is "http" not "https"
or
else try:
const url = `${apiBaseUrl}/someUrlText/someUrlText/`;
const headers = {headers: { "Content-Type": "application/json"}};
const body = JSON.stringify({ postId });
axios
.post(url, body, headers)
.then(res => {
console.log("request received",res);
})
.catch(err => console.log("TODO: Handle error axios", err));

Downloading Excel data using Axios from Laravel backend is not working

I am developing a Web application using React JS for the front-end and Laravel for the back-end API. Now, what I am trying to do is I am trying to fetch the Excel data from the backend using Axios and then download the file.
This is my Laravel API controller action method.
function downloadExcel(Request $request)
{
//other code goes here
return Excel::create($left_photo->id . "-" . $right_photo->id, function($excel) use ($excel_data)
{
// Set the spreadsheet title, creator, and description
$excel->setTitle('Mapping points');
$excel->setCreator('Laravel')->setCompany('Memento');
$excel->setDescription('Mapping points file');
// Build the spreadsheet, passing in the payments array
$excel->sheet('sheet1', function($sheet) use ($excel_data)
{
$sheet->fromArray($excel_data, null, 'A1', false, false);
});
})->download('xlsx');
}
I fetch the data from the react js application using Axios like this.
export const getHttpClientFileDownload = (path) => {
let accessToken = localStorage.getItem("access_token");
return Axios({
url: getApiBaseEndpoint() + path,
method: 'GET',
responseType: 'blob', // important
headers : { 'api-version': API_VERSION, 'Authorization': 'Bearer ' + accessToken }
})
}
exportExcel()//this is the download medthod in the component
{
let path = 'photos/matching-points/excel?left_photo_id=' + this.props.leftImageId + "&right_photo_id=" + this.props.rightImageId;
//let path = "curator/event/" +this.props.match.params.id + "/details";
getHttpClientFileDownload(path)
.then((response) => {
alert('Everything is alright')
})
}
As you can see in the above code, if the request success, it should alert a message, "Everything is alright". But it is not alerting the message. But in the browser, it is successful.
When I make the request to the link that is returning just normal JSON response, it is alerting the message as expected. Only it is not working as expected when I make the request to the aforementioned Excel API.
I cannot use direct download link because I am doing some authorization on the server-side.
I had the same problem and found a solution as below.
Steps:
Call API to Laravel backend. Create file and store the same in local driver on server.
Return the file name to client.
Create a public route in Laravel (In web.php) to download files from Local storage. This route will delete the file after download it.
From client side, redirect the user to this public URL with the file name.
My code looks like this. I used fetch API.
Client side code:
const response = await fetch("my_server_url.com/api/createFile", {
method: 'GET',
headers: {
Authorization: "Bearer " + this.$store.state.AccessToken,
"X-Requested-With": "XMLHttpRequest",
},
});
if (!response.ok) {
console.log(response)
throw new Error("Something went wrong!");
}
const data = await response.json();
window.open("my_server_url.com/downloadFile/name="+data, '_blank');
Code in my_server_url.com/api/createFile route: (api.php)
public function createFile()
{
$file_name= date('YmdHis').rand();
Excel::store(new myExport(), $file_name.'.xlsx', 'local');
return response()->json($file_name.'.xlsx', 200);
}
Code in my_server_url.com/downloadFile/name={file_name} route: (web.php)
public function downloadFile($file_name)
{
return response()->download(Storage::path($file_name))->deleteFileAfterSend(true);
}
This way, you can check authorization and logic, but yet using the API. Also, make sure to add use Illuminate\Support\Facades\Storage; in laravel controller.
You can simply use window.open(path) to download files

Resources