Getting 400 error Bad request using axios - reactjs

I am using axios and getting a 400 bad request error. I am using react-redux and trying to send a post request to localhost:3000/posts. Here is the code that I am using.
import axios from 'axios';
import {
GET_ALL_POSTS,
GET_POST,
CREATE_POST,
DELETE_POST,
UPDATE_POST
} from './types';
const ROOT_URL = 'http://localhost:3000';
export function createPost({content, title}, cb) {
return function(dispatch) {
axios.post(`${ROOT_URL}/posts`, {content, title})
.then((response) => {
console.log(response);
dispatch({
type: CREATE_POST,
payload: response
});
})
.then(() => cb())
.catch((error) => {
console.log("Problem submitting New Post", error);
});
}
}

i was also getting this error, the issue was not with server or with axios or proxy url.
The issue was i wasn't sending the correct data from my react application.
For Example
i supposed to send:
{ email: 'ib2#gmail.com', password: 'asdf' }
what i was sending is:
{ name: 'ib2#gmail.com', password: 'asdf' }
this caused api don't understand name field, as i provided email as the key in api.
so if you are still facing the issue try to check if you are sending the correct data.

For every post request, the client first sends an OPTIONS request to check whether the server is ready to accept the connection. You should also allow the server to accept options request. If you have not allowed use the below lines in case of node server
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
next();
});

Related

CORS error while trying to post data with Axios on AWS REST API configuration using a node.js Lambda function

I'm posting data to a DynamoDB table with axios in a React front-end.
The API is set up through a serverless configuration with an API Gateway and Lambda on AWS.
While the request goes through and I see the added item on the database I still get a CORS error https://i.stack.imgur.com/m7yMG.jpg
This is the axios method:
import axios from "axios";
export const sendItemToDB = async (_data) => {
if (!_data) { return };
try {
const res = await axios({
method: "POST",
url: process.env.REACT_APP_QUERY_API,
data: _data,
headers: {
"Content-Type": "text/plain"
},
});
console.log("data returned from api", res);
} catch (error) {
console.log("Error sending File to db: ");
console.log(error);
}
};
And the API method on Lambda:
const createRecord = async (event) => {
const response = { statusCode: 200 };
try {
const body = JSON.parse(event.body);
const params = {
TableName: process.env.DYNAMODB_TABLE_NAME,
Item: marshall(body || {}),
};
const createResult = await db.send(new PutItemCommand(params));
response.body = JSON.stringify({
message: "Successfully created record.",
createResult,
});
} catch (e) {
console.error(e);
response.statusCode = 500;
response.body = JSON.stringify({
message: "Failed to create record.",
errorMsg: e.message,
errorStack: e.stack,
});
}
return response;
};
I based this configuration on this tutorial : https://github.com/jacksonyuan-yt/dynamodb-crud-api-gateway
I solved this following amazon documentation and reconfiguring the serveless deployment yml.
Serverless documentation on api gateway and lambda proxy integration here
Adding the missing headers to all lambda functions was essential.
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Headers" : "Content-Type",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
};
Also testing that OPTIONS is working for the preflight:
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-test-cors.html
Just as Stavros noticed, the problem is that this is not a simple cross-origin POST method request (because it contains custom headers), so you need to tweak CORS settings of AWS API Gateway by adding
"POST, GET & OPTIONS" for Access-Control-Allow-Methods
"content-type" for Access-Control-Allow-Headers
You can do it through console like this
You also might need to add those headers in lambda like this
and it will work.

my app is taking localhost:3000 as the server. but i have localhost:4000 as the server

My problem is that iam using axios to communicate with backend.axios had done perfect job till now. but when i wrote a code for register, my console says that
POST http://localhost:3000/api/v1/register 500 (Internal Server Error)
so till now it responded very good.but now it thrwing an error like this.
userAction.js :
export const register = (userData) => async (dispatch) => {
try {
dispatch({ type: REGISTER_USER_REQUEST });
const config = { headers: { "Content-Type": "multipart/form-data" } };
const { data } = await axios.post("/api/v1/register", userData, config);
dispatch({ type: REGISTER_USER_SUCCESS, payload: data.user });
} catch (error) {
dispatch({
type: REGISTER_USER_FAIL,
payload: error.response.data.message,
});
}
};
iam using localhost:4000 as server. but it showing me localhost:3000 which means my app url
Because you did not specify the host in your post url.Then it may be work.
/api/v1/register => http://localhost/api/v1/register
The if you have cors issue add this to the nodejs backend app.js file (as you using nodejs):
const cors = require('cors');
app.use(cors())

How to catch axios api call error 401 in reactjs?

I am using axios to make apis calls in react. If there is no token provided or token got expired server sends the 401 status. I want to check that status on reactjs side.
But if i check err object in catch the status field is null.
Here is the code
try {
MyService.getIntet(reqBody);
} catch (err) {
handleUnAuthorizedResponse(err);
}
error returns this
Service function:
import axios from "axios";
static getIntent(reqBody) {
const url = `${this.intentionBaseUrl}/process`;
const options = {
headers: {
"Content-Type": "application/json"
},
};
return axios
.post(url, reqBody, options)
.then((res) => res.data)
}
How to handle 401 error ?
You need to wrap the trycatch in async function and await MyService.getIntet(reqBody) to catch the error. The status code is in err.response.status.
You could also just MyService.getIntet(reqBody).catch(handleUnAuthorizedResponse) if you don't want to wrap it in async function.
You can use .catch chaining function after .then to catch all errors.
Error object will contain a response object which will contain actual response received by API response with all meta information. But make sure to put a condition while accessing this object as errors caught from the then block will not have response key.
import axios from "axios";
static getIntent(reqBody) {
const url = `${this.intentionBaseUrl}/process`;
const options = {
headers: {
"Content-Type": "application/json"
},
};
return axios
.post(url, reqBody, options)
.then((res) => res.data)
.catch(error => console.log(error.response.status))
}

ReactJS aws blocked by CORS preflight policy

I've been trying to make a simple post request api so that my reactJS frontend can make posts, and have them populate in a table in DynamoDB. I've created the a dynamoDB table, given a lambda function permission to make requests to this table, and an API gateway to use a url to make the rest api requests. I originally did not have the intergration request in API gateway set to lambda proxy, but from the advice of aws support, I've enabled it.
This is the code I'm using in my lambda function (with the api gateway (REST API) as the trigger):
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region: "us-east-1"});
exports.handler = (event, context, callback) => {
console.log("Processing...");
const {name} = JSON.parse(event.body);
const params = {
TableName: "serverlessAppTest",
Item: {
date: Date.now(),
name: name,
},
};
let responseBody = {
name: name,
}
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
"Access-Control-Allow-Headers" : "Content-Type",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
body: JSON.stringify(responseBody)
};
docClient.put(params, function(err, data) {
if(err){
callback(err, null);
} else {
callback(null, data);
}
})
console.log("response: " +JSON.stringify(response))
return response;
};
When I try to reach the post api with the following body in the test area in lambda:
{
"body": "{\"name\": \"Value from Lambda\"}"
}
I got a 200 OK, and the data is populated in the dynamoDB table. It also works correctly in postman, a 200 OK and data uploaded.
When I try in my reactjs code, I get the following response:
Access to XMLHttpRequest at 'https://{apivalhere}.execute-api.us-east-1.amazonaws.com/default/serverlessAPICalls' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here's my reactjs function to make the call with a button push.
import React from "react";
import axios from "axios";
function FormHook() {
const apiURL =
"https://{apivalhere}.execute-api.us-east-1.amazonaws.com/default/serverlessAPICalls";
const submitHandler = (e) => {
e.preventDefault();
console.log("did it");
const headerData = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": true,
"Access-Control-Allow-Headers":
"Origin, Content-Type, X-Auth-Token",
"Access-Control-Allow-Methods":
"GET, POST, PATCH, PUT, DELETE, OPTIONS",
};
axios
.post(
apiURL,
{
name: "Hello from reactjs!",
message: "this is the message field.",
},
{
headers: headerData,
}
)
.then((res) => {
console.log(res);
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
};
return (
<div>
<form onSubmit={submitHandler}>
<button type="submit">Send</button>
</form>
</div>
);
}
export default FormHook;
I've gone through about a dozen or more docs on stackoverflow and aws support trying to resolve this issue, and I keep getting blocked with this cors issue. I've tried specifically stating "application/json" in my headers, along with specifically allowing 'localhost:3000', then tried '*' in the Control Allow Origin for both the lambda node.js code, and reactjs post method. I'm at a complete loss at what I could do to fix this and could use some help. I'm relatively new with making my own functions to handle api requests, so any guidance or suggestions would be much appreciated.
edit:
I received the same CORS error with the following as well.
import React from "react";
import axios from "axios";
function FormHook() {
const apiURL =
"https://{apivalhere}.execute-api.us-east-1.amazonaws.com/default/serverlessAPICalls";
const submitHandler = (e) => {
e.preventDefault();
console.log("did it");
axios
.post(
apiURL,
{
name: "Hello from reactjs!",
message: "this is the message field.",
},
)
.then((res) => {
console.log(res);
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
};
return (
<div>
<form onSubmit={submitHandler}>
<button type="submit">Send</button>
</form>
</div>
);
}
export default FormHook;
For my setup in particular, the issue was in my api gateway configuration and process in lambda. I was not handling the OPTIONS request, which was causing the bad gateway (502 error). To fix this, in the api gateway I'd set an OPTIONS methods integration request type to MOCK. This causes the api gateway to just chuck out whatever OPTIONS request it gets, and allows the following post request to come through.
This is definitely not best practice and will be updated to handle the OPTIONS request more gracefully, but it's working now.
This great article explains the solution: AWS CORS Policy with React
You have to go through to every detail, I also read it several times to realise how to set the headers for every request right.

How to fix the unauthorized axios/react response

Unauthorized axios/react response
Hi there friends, I'm trying to connect to an api through Axios and React but an error message appears saying that I don't have access here's my action:
import {SHOW_PROMOTIONS} from './action-types';
import axios from 'axios';
export const showPromo = () => async dispatch =>{
const url= 'https://payment-promotions-dev.travelit.com.ar/api/promotions/packages/';
let config = {
"Content-type": "application/x-www-form-urlencoded",
"Authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtdW5kaWdlYSIsImp0aSI6ImQ0ODE1ZDk4LTJlYmQtNDRjYS04NGViLTU4N2JjNTY5NzgzZCIsImlhdCI6MTU1NTM0ODUwMCwibm9tYnJlIjoiTXVuZGlnZWEiLCJhcHBsaWNhdGlvbklkIjoiMSIsInBhaXNJZCI6IjEiLCJ0aXBvQXBsaWNhY2lvbklkIjoiMSIsImFjdGl2YSI6IlRydWUiLCJuYmYiOjE1NTUzNDg1MDAsImV4cCI6MTU1NTk1MzMwMCwiaXNzIjoiVHJhdmVsSVQiLCJhdWQiOiJUcmF2ZWxJVCJ9.o4Tv6Cw1Mj5xmHIQQ7abm6k6Ean6s6eQ3IDEkHY6Frk"
};
axios.get('http://<host>:<port>/<path>', url,config)
.then((res) => {
console.log("RESPONSE RECEIVED: ", res);
})
.catch((err) => {
console.log("AXIOS ERROR: ", err);
})
const respuesta = await axios.get(url,config);
dispatch({
type: SHOW_PROMOTIONS,
payload: respuesta.data
})
}
When I execute the component, this error appears: (See following image https://imgur.com/LuKnBv9)
The token is at it's respective header, I don't seem to recognize wat I'm doing wrong.
I even tried to do the request with Postman and it throughs 200: (See image2 https://imgur.com/7UFksPR)
Thanks for the help guys!
You currently aren't actually specifying headers for the request. You would need to add headers property to the config object and put the desired headers into that property. Also, as the comments have you stated, you would also need to specify the type for the Authorization request headers, such as Bearer:
const config = {
headers: {
"Content-type": "application/x-www-form-urlencoded",
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJtdW5kaWdlYSIsImp0aSI6ImQ0ODE1ZDk4LTJlYmQtNDRjYS04NGViLTU4N2JjNTY5NzgzZCIsImlhdCI6MTU1NTM0ODUwMCwibm9tYnJlIjoiTXVuZGlnZWEiLCJhcHBsaWNhdGlvbklkIjoiMSIsInBhaXNJZCI6IjEiLCJ0aXBvQXBsaWNhY2lvbklkIjoiMSIsImFjdGl2YSI6IlRydWUiLCJuYmYiOjE1NTUzNDg1MDAsImV4cCI6MTU1NTk1MzMwMCwiaXNzIjoiVHJhdmVsSVQiLCJhdWQiOiJUcmF2ZWxJVCJ9.o4Tv6Cw1Mj5xmHIQQ7abm6k6Ean6s6eQ3IDEkHY6Frk"
}
};
Hopefully that helps!

Resources