My react native code:
const signin =
(dispatch) =>
async ({ username, password }) => {
try {
console.log(username, password);
const response = await tracker.post(
"/login",
(data = { username, password }),
(headers = {
"content-type": "application/x-www-form-urlencoded",
})
);
await AsyncStorage.setItem("token", response.data.token);
dispatch({ type: "signin", payload: response.data.token });
console.log(response.data.token);
} catch (err) {
console.log(err);
dispatch({
type: "error",
payload: "This is an error, start debugging",
});
}
};
Curl request to FastAPI backend:
curl -X 'POST' \ 'https://fastest.herokuapp.com/login/' \ -H 'accept: application/json' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=&username={email}&password={password}&scope=&client_id=&client_secret=
whenever I try to create a new user or sign in with an existing user I keep getting following error:
[AxiosError: Request failed with status code 422]
Is there a better way to send a POST request with curl to signup or login using axios?
Now, I know this is a well documented error on internet, but, somehow, I am unable to find the error and debug it. Any feedback as to what I am doing wrong?
Edit:
FastAPI endpoint code:
#router.post("/",response_model=schemas.Token)
def getLogin(user_Credentials:OAuth2PasswordRequestForm=Depends(),db: Session=Depends(database.get_db)):
user = db.query(models.User).filter(models.User.email == user_Credentials.username).first()
if not user:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=f"wrong credentials")
if not utils.verify(user_Credentials.password,user.password):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=f"wrong credentials")
access_token = oauth2.create_access_token(data={"user_id": user.id})
return {"access_token":access_token, "token_type":"bearer"}
For full code:
Backend FastAPI: here
Frontend react native: here
Error Changed
After adding qs.stringify() according to https://axios-http.com/docs/urlencoded and updating the code as follows:
const signin =
(dispatch) =>
async ({ username, password }) => {
try {
console.log(username, password);
const response = await tracker({
method: "post",
url: "/login",
data: qs.stringify({
username: username,
password: password,
}),
headers: {
"content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
});
console.log(response.data.token);
await AsyncStorage.setItem("token", response.data.token);
dispatch({ type: "signin", payload: response.data.token });
} catch (err) {
console.log(err);
dispatch({
type: "error",
payload: "Start debuggin",
});
}
};
the problem arises now is that token is undefined, but the when I enter same credentials on /docs I get the token.
Final update: got the endpoint wrong for token access
As per Javascript documentation:
A variable that has not been assigned a value is of type undefined.
A method or statement also returns undefined if the variable that is
being evaluated does not have an assigned value. A function returns
undefined if a value was not returned.
In your case, you attempt to retrieve an attribute, namely token, from the JSON repsonse returned by your FastAPI backend. However, such an attribute does not exist in that JSON object. Your API endpoint returns "access_token": access_token, hence, you should instead use response.data.access_token.
Also, for future reference, a response having status code 422 (unprocessable entity) will have a response body that specifies the error message, telling exactly which part of your request is missing or doesn’t match the expected format. This will guide you to fix the error in your code.
Please try to send your authentication data as FormData.
let bodyFormData = new FormData();
bodyFormData.append("username", "value");
bodyFormData.append("password", "value");
then send it as you did:
const response = await tracker.post(
"/login",
(data = bodyFormData),
(headers = {
"content-type": "application/x-www-form-urlencoded",
})
);
It should be mentioned that I didn't do much with react-native, but I guess this work for your case.
Related
I am Trying to execute a GET API request from protractor for which I have to Use the bearer token generated from another POST response . I am able to run the POST request successfully ,but unable to use the generated token in GET request in headers . Below is the code-snippet which I tried , Can anyone provide the proper syntax on this approach .
Note : URL and credentials are masked as they are confidential
var Request = require("request");
describe('post user request', () => {
it('create user test', (done) => {
//1. create user (POST)
Request.post({
// method: 'POST',
"url": "http://example.com",
"body" : {
"username": "abc",
"password": "abc1",
}
}).then((res)=>{
console.log(JSON.stringify(res))
}).then((res) =>{
const token1 = res.token
//2. get user (GET)
Request.get({
// method: 'GET',
"url": "http://example.com`[enter code here][1]`/xyz",
"headers": {
"Authorization" : "Bearer " + token1
}
}).then((res)=>{
console.log(res)
done();
})
})
})
})
Error message :
F
post user request
× create user test
- Failed: Argument error, options.body.
Failures:
1) post user request create user test
Message:
Failed: Argument error, options.body.
Stack:
Error: Argument error, options.body.
at setContentLength (D:\Protractor\node_modules\request\request.js:437:28)
at Request.init (D:\Protractor\node_modules\request\request.js:442:5)
at new Request (D:\Protractor\node_modules\request\request.js:127:8)
at request (D:\Protractor\node_modules\request\index.js:53:10)
at Function.post (D:\Protractor\node_modules\request\index.js:61:12)
at UserContext.<anonymous> (D:\Protractor\Specs_Map\APIfile.spec.js:8:21)
at D:\Protractor\node_modules\jasminewd2\index.j
}).then((res)=>{ console.log(JSON.stringify(res)) this is where your error comes from.
Here you log the result, but don't return it, so the following then won't get any value.
Try the following:
}).then((res)=>{ console.log(JSON.stringify(res)); return res;
I have the following method from my vuex action block where I send user email and password to backend server and get userId and token on success.
async signIn ({ commit }, formData) {
const graphqlQuery = {
query: `
query{
loginData(
email: "${formData.email}",
password: "${formData.password}"
) {userId, token}
}
`
}
const res = await this.$axios.post('http://localhost:8080/graphql', graphqlQuery, {
headers: {
'Content-Type': 'application/json'
}
})
console.log(res.data) //works
console.log(res.data.loginData.token) //doesn't work
commit('loadUserData', true, res.data.loginData.token, res.data.loginData.userId)
return res.status
}
I can confirm that I'm getting the response data with console.log(res.data). The response data I get is:
But when I console.log(res.data.loginData) I get undefined. And blank on console.log(res.data.loginData.token) and console.log(res.data.loginData.token).
How do I extract the required data token and userId ?
I'm using webstorm as my IDE and it shows loginData as method refering to my backend graphql resolver method.
My frontend is made on Nuxt js, backend on node js with graphql.
Does anyone have any idea to overcome this issue ?
When making the following fetch request on my front-end I'm getting my desired type and id values.
export const getUserProfile = () => {
return (
fetch(
"https://api.spotify.com/v1/me", {
headers: {"Authorization": "Bearer " + user_id}
})
.then(response => {
return response.json()
})
.then(data => {
console.log(data.type)
console.log(data.id)
})
)
}
Knowing you can't use fetch api in Node I used the npm install request package to get the data on my node server.
request.post(authOptions, function(error, response, body) {
var access_token = body.access_token
let postInfo = {
url: 'https://api.spotify.com/v1/me',
headers: {
"Authoriztion": "Bearer " + access_token
},
json: true
}
request.post(postInfo, function(error, response, body) {
const route = body.type
const current_user_id = body.id
console.log(body)
let uri = process.env.FRONTEND_URI || `http://localhost:3000/${route}/${current_user_id}`
res.redirect(uri + '?access_token=' + access_token)
})
})
The purpose of doing this is so when the res.redirect gets called it sends the client to the user's home page. However when the client gets redirected the url is http://localhost:3000/undefined/undefined?accesss_token={some token}
when looking why the values are undefined I console.log(body) and I get
{
error: {
status: 401,
message: 'No token provided'
}
}
but I can see when logging the response that the token is included
_header: 'POST /v1/me HTTP/1.1\r\nAuthoriztion: Bearer {some token}=\r\nhost: api.spotify.com\r\naccept: application/json\r\ncontent-length: 0\r\nConnection: close\r\n\r\n'
I can see why my values are undefined but why am I getting an unauthorized status in node but not on the client using fetch api? Also I noticed that the url access_token doesn't match the server logged token.
Here are the docs I'm using:
https://www.npmjs.com/package/request
https://developer.spotify.com/documentation/web-api/reference/users-profile/get-current-users-profile/
Github file: https://github.com/ryansaam/litphum-server/blob/master/server.js
If you use node-fetch in your server code, you have a similar API as fetch.
I am using a fetch() request from the client to PUT updated user data to the backend, to then be saved into a DB. So far, the all of the route is working fine, verified and tested in Postman.
In this User Update route, there is an if statement that checks for an error when searching for the user in the database, and if this error is thrown, it sends a response of 404 and a message to the client.
When I make the fetch() request from the client to this route, regardless if there is an error, the response is always a status 200, and does not include any response from my route. I need the client to be able to handle the potential errors the routes might produce. For example with this user update route, if the user is not found in the database for whatever reason, an error and message is returned, so the client needs to know this.
Here is some code:
Client-side:
fetch(`http://localhost:3000/users/${userId}`, {
method: "put",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(userData)
}).then(response => console.log(response))
.catch(err => console.log(err));
Here in the client, I am using console.log() to visualize everything. When the response returns, I get back:
Response {type: "basic", url: "http://localhost:3000/users/accounts/", redirected: false, status: 200, ok: true, …}
Server-side route controller:
exports.user_update = (req, res) => {
const { params, body } = req;
const { userid } = params;
User.findByIdAndUpdate({ _id: userid }, body, { new: true }, (err, user) => {
if (err)
res.send({
status: 404,
message:
"There was an issue finding and updating the user on the server."
});
else
res.send({
status: 200,
user
});
});
};
Now here on the server, I anticipated the response of the fetch() to be either the 404 error or the 200 success along with their payloads. Neither are returned in a response from the server. Instead as mentioned above, I am getting a generic 200 ok response simply letting me know the fetch() made a connection to the route. This route(along with the others) has been tested in Postman, and all work as anticipated returning the expected responses.
What am I not understanding here? Is my idea of using a fetch() request in this manner wrong? I feel like I might be close, but that's just my ignorant guess. Thank for reading!
I figured out the solution.
The fetch request was wrong, here is the update:
fetch(`http://localhost:3000/users/${userId}`, {
method: "put",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(userData)
}).then(response => response.json())
.then(response => console.log(response))
.catch(err => console.log(err));
I had to call response.json() to parse the response as a JSON object.
According to express documentation you sent status as a field of JSON. To correctly send http status replace your res.send(...) with
res.status(404).send("There was an issue finding and updating the user on the server.");
and
res.send(user);
You are sending the status field inside your payload, which is not parsed by fetch API.
To solve this you could something as below
exports.user_update = (req, res) => {
const { params, body } = req;
const { userid } = params;
User.findByIdAndUpdate({ _id: userid }, body, { new: true }, (err, user) =>
{
if (err)
res.status(404).send({
message: "There was an issue finding and updating the user on the server."
});
else
res.status(200).send({
user
});
});
};
I'm trying to send a POST request locally with a username and password in the body through Axios.
I'm deploying a Flask app on http://127.0.0.1:5000/login, which handles the /login route. The POST request fails with the following error
POST http://127.0.0.1:5000/login 500 (INTERNAL SERVER ERROR)
Error: Request failed with status code 500
at createError (createError.js:16)
at settle (settle.js:18)
at XMLHttpRequest.handleLoad (xhr.js:77)
I researched a bit and thought it might be a problem with CORS, but this doesn't seem to be the case because I tried an Axios GET request and it worked fine (response logged properly). Here's part of my code
axios.get("http://127.0.0.1:5000").then(function(response) {
console.log(response);
}).catch(function(error) {
console.log(error);
})
axios.post("http://127.0.0.1:5000/login", {
username: this.state.username,
password: this.state.password
}).then(function(response) {
console.log(response);
}).catch(function(error) {
console.log(error);
})
Looking at Chrome DevTools, I can see that the POST request payload is properly populated. I then tried printing out the keys server-side in the Flask app using the following code, but I got nothing, empty. (which was expected since the POST request failed)
dict = request.form
for key in dict:
print('form key '+dict[key])
HOWEVER using Postman with the corresponding keys and values works properly and returns a response and prints out the keys (see above). Where is the failure coming from? Why would the POST request fail when a GET seems to work just fine?
Feb 2021. Wasted 2 hours on this. Not much help on this famous library on internet.
Solution:
In the catch block, the error which will always be 500 internal server error
so, use error.response.data instead of error.
Code:
try {
let result = await axios.post( // any call like get
"http://localhost:3001/user", // your URL
{ // data if post, put
some: "data",
}
);
console.log(result.response.data);
} catch (error) {
console.error(error.response.data); // NOTE - use "error.response.data` (not "error")
}
Update:
I ended up writing a common function for handing error:
File: common.app.js
export const errorUtils = {
getError: (error) => {
let e = error;
if (error.response) {
e = error.response.data; // data, status, headers
if (error.response.data && error.response.data.error) {
e = error.response.data.error; // my app specific keys override
}
} else if (error.message) {
e = error.message;
} else {
e = "Unknown error occured";
}
return e;
},
};
More info: https://github.com/axios/axios#handling-errors
So I also got stuck in the same problem and the solution that I found was something like this :
let data = JSON.stringify({
username: this.state.username,
password: password
});
const response = axios.post(url,data,{headers:{"Content-Type" : "application/json"}});
This solution worked for me.
Apparently Axios didn't take kindly to the raw JSON object
{username: this.state.username, password: password}
but passing the data into a FormData object seemed to work just fine!
After working 2 hours, I realized I made a mistake about the body and data. So, in the axios make sure you pass the data like this.
async function loadToken(){
try{
response = await axios({
url: ``,
headers: {
'Authorization': '',
'Content-Type': '',
},
data: '',
method: 'POST'
});
let data = response.data;
return {
tokenInfo:data,
timestamp:new Date().getTime()
}
} catch(err) {
console.log("err->", err.response.data)
return res.status(500).send({ret_code: ReturnCodes.SOMETHING_WENT_WRONG});
}
}
My previous code pass the data like this, which is wrong
async function refreshToken(){
try{
let headers = {
authorization: '',
'Content-Type': ''
}
let url = ``
let body = {
grant_type: '',
refresh_token: global.tokenInfo.refresh_token
}
data = await axios.post(url, body, {headers});
let data = response.data
console.log(data)
return {
tokenInfo:data,
timestamp:new Date().getTime()
}
} catch(err) {
console.log("err->", err.response)
return res.status(500).send({ret_code: ReturnCodes.SOMETHING_WENT_WRONG});
}
}
Simply try my first code, hope that solves your issue.
Most of the time it happens because of using wrong content type header.
Open postman and see "Body" tab. There you can find the content type of your post data. It's also accessible from "Headers" tab. There should be a Content-Type header. The correct format of data you send through a POST request depends on Content-Type header. for example, json content type requires a json (javascript object) data or form-data content type requires a FormData.
To set a header in axios, change the code like this:
axios.post("http://127.0.0.1:5000/login", {
username: this.state.username,
password: this.state.password
}, {
headers: {'Content-Type': 'application/json'}
}).then(function(response) {
console.log(response);
}).catch(function(error) {
console.log(error);
})
I had similar error i had the JSON capital and it should have been lowercase