How to send x-www-form-urlencoded with axis? - javascript

here is the screen shot of working postman form type.
As you can see I am posting x-www-form-urlencoded data back.
So I search google and found multiple posts about how to send this data back with axios.
In my login screen, I have something like this.
const handleLogin = values => {
setLoading(true);
const params = new URLSearchParams();
params.append('username', values.username);
params.append('password', values.password);
params.append('grant_type', 'password');
dispatch(fetchToken(params))
.then(res => {
navigation.navigate('Home', {screen: 'HomePage'});
})
};
In my redux, I have something like this.
export function fetchToken(params) {
return async dispatch => {
function onSuccess(response) {
tokenData = response.data.Token;
dispatch({type: LOGGED_IN, payload: response.data});
return response;
}
try {
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
};
console.log(params)
const response = await axios.post('/token', params, config);
await AsyncStorage.setItem('token_local', JSON.stringify(response.data));
return onSuccess(response);
} catch (error) {
alert('Provided username and password is incorrect');
throw Error(error);
}
};
}
The thing is that I always get into catch error here. Even the username and password are the same. What am I doing wrong

Related

How to refresh token in axios?

My question is related to customAxios.interceptors.response.use . My purpose here is; if the token expired and I got a 401 error, make a request again where I got a 401 error and write the new token to the headers. On the other hand, if I get an error except for the 401 error, show me the error.response.data . Do you think this logic is set up correctly? I tried to test but I wasn't sure especially 401 error cases
import axios from "axios";
import { LoginAPI } from "../playwright/tests/login/login.api";
import { test } from "#playwright/test"
import {configEnv} from "../config/config"
test.beforeAll(async () => {
await LoginAPI.API.Signin.run()
});
const customAxios = axios.create({
baseURL: configEnv.apiBaseURL
});
customAxios.interceptors.request.use(
async (config) => {
if (config.headers) {
config.headers['Authorization'] = `Bearer ${LoginAPI.States.token}`;
return config;
}
return config;
},
(error) => {
Promise.reject(error);
}
);
customAxios.interceptors.response.use(
function(response) {
return response;
},
async function(error) {
if (401 === error.response.status) {
await LoginAPI.API.Signin.run()
customAxios.defaults.headers.common['Authorization'] = `Bearer ${LoginAPI.States.token}`
} else {
return Promise.reject(error.response.data);
}
}
);
export default customAxios
I would recommend you to store your token in a localStorage and then replace it after refresh. This way you can set a token in your API class in one place.
import axios from "axios";
export const ApiClient = () => {
// Create a new axios instance
const api = axios.create({
baseURL: "URL",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
});
// Add a request interceptor to add the JWT token to the authorization header
api.interceptors.request.use(
(config) => {
const token = sessionStorage.getItem("jwtToken");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// Add a response interceptor to refresh the JWT token if it's expired
api.interceptors.response.use(
(response) => response,
(error) => {
const originalRequest = error.config;
// If the error is a 401 and we have a refresh token, refresh the JWT token
if (
error.response.status === 401 &&
sessionStorage.getItem("refreshToken")
) {
const refreshToken = sessionStorage.getItem("refreshToken");
let data = JSON.stringify({
refresh_token: refreshToken,
});
post("/refreshToken", data)
.then((response) => {
sessionStorage.setItem("jwtToken", response.token);
sessionStorage.setItem("refreshToken", response.refresh_token);
// Re-run the original request that was intercepted
originalRequest.headers.Authorization = `Bearer ${response.token}`;
api(originalRequest)
.then((response) => {
return response.data;
})
.catch((error) => {
console.log(error);
});
// return api(originalRequest)
})
.catch((err) => {
// If there is an error refreshing the token, log out the user
console.log(err);
});
}
// Return the original error if we can't handle it
return Promise.reject(error);
}
);
const login = (email, password) => {
return api
.post("/authentication_token", { email, password })
.then(({ data }) => {
// Store the JWT and refresh tokens in session storage
sessionStorage.setItem("jwtToken", data.token);
sessionStorage.setItem("refreshToken", data.refresh_token);
})
.catch((err) => {
// Return the error if the request fails
return err;
});
};
const get = (path) => {
return api.get(path).then((response) => response.data);
};
const post = (path, data) => {
return api.post(path, data).then((response) => response.data);
};
const put = (path, data) => {
return api.put(path, data).then((response) => response.data);
};
const del = (path) => {
return api.delete(path).then((response) => response);
};
return {
login,
get,
post,
put,
del,
};
};
Best,
Chris

How to throw a server error when fetching JS

I'm new in JavaScript and i have a task to post an email input from form to a node server,everything works fine,but i should implement this functionality:
When an email is forbidden#gmail.com, the server responds with the 422 status code and payload which contains the information about the error. Use browser developer tools to examine the response for this scenario. Display the error message in the browser using window.alert().
I created a customException,it gives me the error in the console,but the server still responds with the 200 status code,but as i understand,it should give an error and the post should not work.How to do this task,i have no idea..?
Fetch functions:
import { validateEmail } from './email-validator.js'
export const sendSubscribe = (emailInput) => {
const isValidEmail = validateEmail(emailInput)
if (isValidEmail === true) {
sendData(emailInput);
// if (emailInput === 'forbidden#gmail.com'){
// throw new CustomException('422');
// }
}
}
const sendHttpRequest = (method, url, data) => {
return fetch(url, {
method: method,
body: JSON.stringify(data),
headers: data ? {
'Content-Type': 'application/json'
} : {}
}).then(response => {
if (response.status >= 400) {
return response.json().then(errResData => {
const error = new Error('Something went wrong!');
error.data = errResData;
throw error;
});
}
return response.json();
});
};
const sendData = (emailInput) => {
sendHttpRequest('POST', 'http://localhost:8080/subscribe', {
email: emailInput
}).then(responseData => {
console.log(responseData);
}).catch(err => {
console.log(err, err.data);
});
}
function CustomException(message) {
const error = new Error(message);
error.code = "422";
window.alert('Forbidden email,please change it!')
return error;
}
CustomException.prototype = Object.create(Error.prototype);
Validate function:
const VALID_EMAIL_ENDINGS = ['gmail.com', 'outlook.com', 'yandex.ru']
export const validateEmail = (email) => !!VALID_EMAIL_ENDINGS.some(v => email.includes(v))
export { VALID_EMAIL_ENDINGS as validEnding }
Please help.Thanks in advance!
Something like this should work:
Server code:
Simplify validate function.
export const isValid = (email) => {
if (email === 'forbidden#gmail.com') {
return false
}
return true
}
Then on your route, something like this, assuming expressjs behind.
app.post('/subscribe', (req, res, next) => {
const email = req.body.email
if (!isValid(email)) {
return res.status(433).send('Email is forbidden')
}
return res.status(200).send('Success')
})
In your frontend you can just post to /subscribe with the email payload
const sendHttpRequest = (method, url, data) => {
return fetch(url, {
method: method,
body: JSON.stringify(data),
headers: data ? {
'Content-Type': 'application/json'
} : {}
})
.then(response => response.json())
};
And in your sendData you can catch the error, like you're doing
const sendData = (emailInput) => {
sendHttpRequest('POST', 'http://localhost:8080/subscribe', {
email: emailInput
}).then(responseData => {
console.log(responseData);
}).catch(err => {
console.log(err); // Email is forbidden
window.alert('Boo!')
});
}
Sidenote: In most cases prototyping should be avoided in javascript.

Handling query in React and Express

Somewhere in my React application I used REST API to send request to the server. In my URL I want to use query (in the postIconsTransition method), but when I send a request to the server, server tells me could not found this URL (I build this error in my server). If I use this URL without any query the request in the postIconsTransition method works fine. postId and authContext.userId work fine, can anyone tell me what's wrong with my code?
In my component where I send request:
const likeHandler = async () => {
setLike(prevState => !prevState);
if (!like) {
try {
await postIconsTransition(props.postId, "inc");
} catch (error) {}
} else {
try {
await postIconsTransition(props.postId, "dec");
} catch (error) {}
}
};
In useHttp.js component:
const postIconsTransition = async (postId, addtionAddress) => {
return await transitionData(
`http://localhost:5000/post/${postId}/${authContext.userId}?t=${addtionAddress}`,
"POST",
null,
{ Authorization: `Bearer ${authContext.token}` }
);
};
transitionData method:
const transitionData = useCallback(
async (url, method = "GET", body = null, headers = {}) => {
setIsLoading(true);
const abortController = new AbortController();
activeHttpRequest.current.push(abortController);
try {
const response = await fetch(url, {
method,
body,
headers,
signal: abortController.signal
});
const responseData = await response.json();
activeHttpRequest.current = activeHttpRequest.current.filter(
reqCtrl => reqCtrl !== abortController
);
if (!response.ok) {
throw new Error(responseData.message);
}
setIsLoading(false);
return responseData;
} catch (error) {
modalContext.err(error);
setIsLoading(false);
throw error;
}
},
[modalContext.err]
);
In Express:
router.post(
"/:postId/:userId?t=inc",
tokenChecker,
postController.updateLikesComments
);
router.post(
"/:postId/:userId?t=dec",
tokenChecker,
postController.updateLikesComments
);
All of them work fine but when I use query in my URL, it's not working any more.
You don't specify query parameters in express routes like that. Just send them. Express can read it.
router.post(
"/:postId/:userId",
tokenChecker,
postController.updateLikesComments
);
// Notice that you don't need the other one.
and in your controller check the parameter
// controller's code
const t = req.query.t;
if (t === 'inc') {
// do what you want here
}
if (t === 'dec') {
// do what you want here
}

How to check email overlap using Axios get and post for SignUp with React?

I'm trying to filter overlap validation for SignUp email.
in my api.js
const token = JSON.parse(localStorage.getItem('token'));
const api = axios.create({
baseURL: baseURL, // already set our base URL
headers: {
Authorization: `Bearer ${token}`,
'Access-Control-Allow-Origin': '*',
}
});
and in my authService.js
const register = (countryCode, name, email, password) => {
return axios
.post('/auth/signup', {
countryCode,
name,
email,
password,
})
.then((response) => {
if (response.headers.authorization) {
console.log(response);
localStorage.setItem('user', JSON.stringify(response.headers.authorization));
}
return response.headers.authorization;
});
};
const login = (email, password) => {
api
.post('/auth/signin', {
email,
password,
})
.then((response) => {
if (response.headers.authorization) {
localStorage.setItem('user', JSON.stringify(response.headers.authorization));
}
return response.data;
});
};
const checkEmail = (email) => {
return api.get('/public/email', { email }).then((response) => {
if (response.data.exist === true) {
return localStorage.getItem('user', JSON.stringify(response.data));
}
return response.data;
});
};
This checkEmail will be in the SignUp.js
for onChange={emailChange}
const onChangeEmail = (e) => {
const email = e.target.value;
if (!email.includes('#')) {
setEmailError('Invalid email');
} else if (email.includes('#')) {
setEmailError(null);
}
AuthService.checkEmail(email).then(
(response) => setEmailError('Already Registered Email'),
(error) => {
console.log(error);
}
);
setEmail(email);
};
after this code,
in the console
it error
Error: Request failed with status code 401
at createError (createError.js:16)
at settle (settle.js:17)
at XMLHttpRequest.handleLoad (xhr.js:62)
I think inn the api.get(URl, {something})
that {something} is wrong but I don't have any idea for hours...
what can I do for this error??
you can't send body parameter in GET , for that POST,PUT will work,
to send with GET then attach data to the GET url.
example
if your using node server at backend then
api.get('/public/email/'+email).then((resp)=>{
log(resp);
}
collect the data using
router.get("public/email/:youremail",(req,res)=>{
req.param.youremail
}

Why am I getting an error of Unexpected token < in JSON at position 0

I am creating a MERN app, I am new to this. I tried following some tutorials on the net but I have encountered some error.
I am submitting the post request like this. As you can see I am not specifying the content type because I know that if you are using the 'multipart/form-data it will automatically append it to the headers. I am using a react hook here which is why I am not directly using the fetch method.
const formData = new FormData();
formData.append("email", formState.inputs.email.value);
formData.append("name", formState.inputs.name.value);
formData.append("password", formState.inputs.password.value);
formData.append("image", formState.inputs.image.value);
const responseData = await sendRequest(
`${process.env.REACT_APP_BACKEND_BASE_URL}/api/users/signup`,
"POST",
formData
);
meanwhile my signup route is like this, UNDER user-routes.js
router.post(
"/signup",
fileUpload.single("image"),
[
check("name").not().isEmpty(),
check("email")
.normalizeEmail() // Test#test.com => test#test.com
.isEmail(),
check("password").isLength({ min: 6 }),
],
usersController.signup
);
as you can also see, I am catching it in the route by using the fileUpload.single("image")
if you need to see my hook that I am using here it is, but I am pretty sure that the hook works fine. and it has no issues whatsoever, so here it is: this is a react hook
export const useHttpClient = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState();
const activeHttpRequests = useRef([]);
const sendRequest = useCallback(
async (url, method = "GET", body = null, headers = {}) => {
setIsLoading(true);
const httpAbortCtrl = new AbortController();
activeHttpRequests.current.push(httpAbortCtrl);
try {
const response = await fetch(url, {
method,
body,
headers,
signal: httpAbortCtrl.signal,
});
const responseData = await response.json();
// console.log("Response: ", response);
// console.log("Data: ", responseData);
activeHttpRequests.current = activeHttpRequests.current.filter(
(reqCtrl) => reqCtrl !== httpAbortCtrl
);
if (!response.ok) {
throw new Error(responseData.message);
}
setIsLoading(false);
return responseData;
} catch (err) {
setError(err.message);
setIsLoading(false);
throw err;
}
},
[]
);
const clearError = () => {
setError(null);
};
useEffect(() => {
return () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
activeHttpRequests.current.forEach((abortCtrl) => abortCtrl.abort());
};
}, []);
return { isLoading, error, sendRequest, clearError };
};
I will include the signup here from my users.controller:
const signup = async (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return next(
new HttpError("Invalid inputs passed, please check your data.", 422)
);
}
const { name, email, password } = req.body;
let existingUser;
try {
existingUser = await User.findOne({ email: email });
} catch (err) {
const error = new HttpError(
"Signing up failed, please try again later.",
500
);
return next(error);
}
if (existingUser) {
const error = new HttpError(
"User exists already, please login instead.",
422
);
return next(error);
}
let hashedPassword;
try {
hashedPassword = await bcrypt.hash(password, 12);
} catch (err) {
const error = new HttpError(
"Could not create user, please try again.",
500
);
return next(error);
}
//res.json({ message: "AFTER HASHING" });
const createdUser = new User({
name,
email,
image: req.file.path,
password: hashedPassword,
places: [],
});
try {
await createdUser.save();
} catch (err) {
const error = new HttpError(
"Signing up failed, please try again later.",
500
);
return next(error);
}
let token;
try {
token = jwt.sign(
{ userId: createdUser.id, email: createdUser.email },
process.env.JWT_KEY,
{ expiresIn: "1h" }
);
} catch (err) {
const error = new HttpError(
"Signing up failed, please try again later.",
500
);
return next(error);
}
res
.status(201)
.json({ userId: createdUser.id, email: createdUser.email, token: token });
};
You may want to use JSON.Parse() around your responseData
When ever I run into this bug it is because I either,
parsed an already parsed object
Stingified a string
Used a string as an object
This link goes into more depth about the bug and common ways of dissecting the issue.
Try console.log() in your hook before you send the data and also log what the responseData looks like after it retrieves the data

Categories

Resources