to everyone, i have a problem about a request to the server. I get error 400, but i don't understand where is the problem, i checked my code thousand times and it looks like all good.
Basically, with this request i get the "order number".
This is the reducer:
const initialState = {
status: "STALE",
};
export const orderObjectReducer = (state = initialState, action) => {
if (action.type === "SEND_ORDER_FAILED") {
return { status: "FAILED" };
}
if (action.type === "SEND_ORDER_IS_LOADING") {
return {
status: "LOADING",
};
}
if (action.type === "SEND_ORDER_STALE") {
return {
status: "STALE",
};
}
if (action.type === "SEND_ORDER_SUCCESS") {
return {
status: "SUCCESS",
data: action.payload,
};
}
return state;
};
export const makeOrder = (ingredientsIds) => async (dispatch) => {
dispatch({
type: "SEND_ORDER_IS_LOADING",
});
const result = await fetch("https://norma.nomoreparties.space/api/orders", {
method: "POST",
body: JSON.stringify({ ingredients: ingredientsIds }),
})
.then((res) => res.json())
.catch(() => null);
if (!result || !result.success) {
dispatch({
type: "SEND_ORDER_FAILED",
});
return result;
}
dispatch({
type: "SEND_ORDER_SUCCESS",
payload: result,
});
};
The button that trigger the request:
<Button
disabled={selectedIngredientsIds.length === 0}
htmlType="button"
onClick={() => dispatch(makeOrder(selectedIngredientsIds))}
type="primary"
size="large"
extraClass="mr-4" >
Оформить заказ
</Button>
This is the component that get the result of the request:
export const OrderDetails = () => {
const { status, data } = useAppSelector((store) => store.orderObject);
const dispatch = useAppDispatch();
if (status === "STALE" || status === "LOADING") {
return null;
}
return (
<Modal onClose={() => dispatch({ type: "SEND_ORDER_STALE" })}>
{status === "FAILED" ? ("Ошибка") : (
<>
<p className={`${orderDetailsStyle.orderDetails__orderNumber} text text_type_digits-large mt-30 mb-8`}>{data?.order.number}</p>
<p className="text text_type_main-medium mb-15">идентификатор заказа</p>
<img src={done} alt="заказано" className={orderDetailsStyle.orderDetails__image}/>
<p className="text text_type_main-default mb-2">Ваш заказ начали готовить</p>
<p className="text text_type_main-default text_color_inactive mb-30">Дождитесь готовности на орбитальной станции</p>
</>
)}
</Modal>
);
};
How can i solve the problem?
A 400 Bad Request simply means the request was bad. The server is saying something is wrong with what you sent it.
To test this outside of your app, in Firefox I use a free extension called RESTED Client to simply test a POST to your URL (https://norma.nomoreparties.space/api/orders) with the a pseudo body of { ingredients: ["1", "2"]}. It returns the following:
{
"success": false,
"message": "Ingredient ids must be provided"
}
The problem is with the data you are sending. The reason I know this is because I repeated exactly what your app is doing here:
const result = await fetch("https://norma.nomoreparties.space/api/orders", {
method: "POST",
body: JSON.stringify({ ingredients: ingredientsIds }),
})
the code is right, i needed just to add to my request:
headers: {
"Content-Type": "application/json",
},
Related
I have a simple auth stack as follow
export default () => {
const { state } = useContext(AuthContext);
return (
<AuthProvider>
<NavigationContainer>
{state.token ? <MainNavigator /> : <AuthNavigator />}
</NavigationContainer>
</AuthProvider>
);
};
The initial state of token is defined as null in the AuthContext folder, code below. But when running the program i get the following error TypeError: undefined is not an object (evaluating '_useContext.state')
const authReducer = (state, action) => {
switch (action.type) {
case "error":
return { ...state, errorMessage: action.payload };
case "signin":
return { errorMessage: "", token: action.payload };
default:
return state;
}
};
const tokencheck = (dispatch) => async () => {
const token = await AsyncStorage.getItem("token");
if (token) {
dispatch({ type: signin, payload: token });
navigate("Home");
} else {
navigate("SignIn");
}
};
const signup =
(dispatch) =>
async ({ username, password }) => {
try {
const response = await tracker({
method: "post",
url: "/user",
data: qs.stringify({
username: username,
password: password,
}),
headers: {
"content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
});
await AsyncStorage.setItem("token", response.data.email);
// dispatch({ type: "signin", payload: response.data.access_token });
navigate("SignIn");
} catch (err) {
dispatch({
type: "error",
payload: "Something's not write, plz try again",
});
console.log(err);
}
};
const signin =
(dispatch) =>
async ({ username, password }) => {
try {
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",
},
});
await AsyncStorage.setItem("token", response.data.access_token);
dispatch({ type: "signin", payload: response.data.access_token });
navigate("Home");
} catch (err) {
console.log(err);
dispatch({
type: "error",
payload: "Start debuggin",
});
}
};
const signout = (dispatch) => {
return () => {};
};
export const { Provider, Context } = creatingContext(
authReducer,
{ signin, signout, signup, tokencheck },
{ token: null, errorMessage: "" }
);
The ternary logic is sound and I have defined the initial state then why is this error persisting.
While I was looking for state in token what i should look for is value.
The problem is simply solved with
{state.token != null : <nav/>?<auth/>}
I'm trying to delete an user, but the req.body in the backend is an empty object.
In the backend I have the following code:
const deleteUser = async (req, res) => {
console.log(req.body);
console.log(req.config);
const user = await User.findById(req.body.userId);
if (user) {
const deleteUser = await user.remove();
res.send({ message: "User Deleted", user: deleteUser });
} else {
res.status(404).send({ message: "User Not Found" });
}
};
Here the console log is an empty object, I must that the other functions work perfectly.
In the frontend, I'm using redux, I think I'm doing something wrong in the actions, but I can't find out what, I will post all my code for reference.
action.js:
export const deleteUser = (userId) => async (dispatch, getState) => {
dispatch({ type: USER_DELETE_REQUEST, payload: userId });
try {
const { data } = await Axios.delete(
"http://localhost:3030/v1/user/userProfile/deleteUser",
{
userId: userId,
}
);
dispatch({ type: USER_DELETE_SUCCESS, payload: data });
} catch (error) {
const message =
error.response && error.response.data.message
? error.response.data.message
: error.message;
dispatch({ type: USER_DELETE_FAIL, payload: message });
}
};
In the reducer:
export const userDeleteReducer = (state = {}, action) => {
switch (action.type) {
case USER_DELETE_REQUEST:
return { loading: true };
case USER_DELETE_SUCCESS:
return { loading: false, success: true };
case USER_DELETE_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
And I'm calling the action like that:
const userSignin = useSelector((state) => state.userSignin);
const { userInfo, loading, error } = userSignin;
<button
onClick={() => {
console.log(userInfo._id);
dispatch(deleteUser(userInfo._id));
props.onClose();
}}
className='deleteAccountModalButton'
>
Delete account!
</button>
I tried everything, but I can't find where the problem, can somebody tell me why the req.body is empty in the backend?
EDIT:
I managed to make it work by modifying the order of parameters in actions:
export const deleteUser = (userId) => async (dispatch, getState) => {
dispatch({ type: USER_DELETE_REQUEST, payload: userId });
const {
userSignin: { userInfo },
} = getState();
try {
const { data } = await Axios.delete(
"http://localhost:3030/v1/user/userProfile/deleteUser",
{
data: {
headers: { Authorization: `Bearer ${userInfo.token}` },
userId,
},
}
);
dispatch({ type: USER_DELETE_SUCCESS, payload: data });
} catch (error) {
const message =
error.response && error.response.data.message
? error.response.data.message
: error.message;
dispatch({ type: USER_DELETE_FAIL, payload: message });
}
};
I will leave this here in case somebody else will have this problem.
When I delete the order, sometimes the state is updated and sometimes not. It did not work 5 minutes and then started working correctly and I am wondering whether I've messed up something in my code.
action
export const deleteOrder = (token, id) => async dispatch => {
const headers = {
headers: {
Authorization: `Bearer ${token}`,
}
}
const response = await api.delete(`/orders/detail/${id}`, headers)
.catch(error => {
dispatch({ type: constants.PUSH_ERROR, payload: error })
})
if (response && (response.status === 204 || response.status === 301)) {
dispatch({ type: constants.DELETE_ORDER, payload: id });
}
};
reducer
case DELETE_ORDER:
return {
...state,
orders: state.orders.filter(o => o.id !== action.payload)
}
You can ask for more code.
Hi all I'm new to authentication. I was building an app where a user can login and create a story using an api, and the story is sent to the backend using a POST request. The app was authenticating fine, until I built the app. Now when I sign in and try to add a story, I get 401 Unauthorized and SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data in actions.js.
Then if I refresh the page, the errors go away and the app is working.
I am able to logout and login again normally.
I have no idea why that's happening. Any help will be appreciated.
The backend server does say Error in authorization JsonWebTokenError: jwt malformed
actions.js
import * as t from './actionTypes';
import { setUserSession } from '../utils/Common';
import { getToken } from '../utils/Common'
const token = getToken();
// this is what our action should look like which dispatches the "payload" to reducer
const setLoginState = (loginData) => {
return {
type: t.SET_LOGIN_STATE,
payload: loginData, //{ ...json, userId: email }
};
};
const setStoryState = (storyData) => {
return {
type: t.CREATE_STORY,
payload: storyData, //storyData is the object with summary, description, type, etc.
};
};
const getStoryState = (storyData) => {
return {
type: t.GET_STORIES,
payload: storyData, //storyData is the object with summary, description, type, etc.
};
};
const getSingleStoryState = (storyData) => {
return {
type: t.GET_STORY,
payload: storyData, //storyData is the object with summary, description, type, etc.
};
};
export const login = (loginInput) => { //our login action
const { email, password, isAdmin } = loginInput;
return (dispatch) => { // don't forget to use dispatch here!
return fetch('http://localhost:3000/api/v1/signin', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(loginInput),
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
// console.log(json)
dispatch(setLoginState({ ...json, userId: email, isAdmin: isAdmin })); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
setUserSession(json.token, json.lastName)
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
};
export const getStories = () => {
return (dispatch) => { // don't forget to use dispatch here!
return fetch('http://localhost:3000/api/v1/stories', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
dispatch(getStoryState( [...json ])); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
}
export const viewStory = id => {
return (dispatch) => { // don't forget to use dispatch here!
return fetch(`http://localhost:3000/api/v1/stories/${id}`, {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
dispatch(getSingleStoryState( {...json } )); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
}
export const roleChange = () => {
return {
type: t.SET_ROLE_STATE,
//payload: role
};
}
export const logout = () => {
return {
type: t.LOGOUT,
};
}
export const createStory = storyInput => {
console.log(token)
const { summary, description, type, complexity, time, cost } = storyInput;
return (dispatch) => { // don't forget to use dispatch here!
return fetch('http://localhost:3000/api/v1/stories', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`,
},
body: JSON.stringify(storyInput),
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
//dispatch(setStoryState( [...json ]));
dispatch(setStoryState({ // our action is called here with object as parameter, this is our payload
summary: summary,
description: description,
type: type,
complexity: complexity,
time: time,
cost: cost
})); // our action is called here
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Some error occured, please retry');
console.log(err);
});
};
}
export const addStory = story => {
return {
type: t.ADD_STORY,
payload: story,
}
}
export const setStatus = (id, status) => {
return (dispatch) => { // don't forget to use dispatch here!
return fetch(`http://localhost:3000/api/v1/stories/${id}/${status}`, {
method: 'PUT',
headers: {
Accept: 'application/json',
'Content-Type': 'text/html',
'Authorization': `Bearer ${token}`
},
})
.then((response) => response.json()) //json will be the response body
.then((json) => {
// if (json.msg === 'success') { // response success checking logic could differ
console.log(json)
// dispatch(getStoryState( {...json } )); // our action is called here with object as parameter, this is our payload
//we appended json object to our state
// } else {
// alert('Login Failed', 'Email or Password is incorrect');
// }
})
.catch((err) => {
alert('Login Failed', 'Some error occured, please retry');
console.log(err);
});
};
}
CreateStory.js
import React, { useState } from 'react'
import { createStory } from '../redux/actions'
import { useDispatch, useSelector } from "react-redux";
import history from '../utils/history';
import { withRouter } from 'react-router-dom';
const CreateStory = () => {
const [summary, setSummary] = useState("");
const [description, setDescription] = useState("");
const [type, setType] = useState("");
const [complexity, setcomplexity] = useState("");
const [time, setTime] = useState("");
const [cost, setCost] = useState(0);
const usedispatch = useDispatch();
const userCreateStory = (summary, description, type, complexity) => usedispatch(createStory({
'summary': summary,
'description': description,
'type': type,
'complexity': complexity,
'time': time,
'cost': cost
}));
const handleSummaryChange = e => {
setSummary(e.target.value)
}
const handleDescriptionChange = e => {
setDescription(e.target.value)
}
const handleTypeChange = e => {
setType(e.target.value)
}
const handleComplexityChange = e => {
setcomplexity(e.target.value)
}
const handleTimeChange = e => {
setTime(e.target.value)
}
const handleCostChange = e => {
setCost(e.target.value)
}
// const currStory = useSelector((state)=> state.storyReducer.story)
const handleSubmit = e => {
e.preventDefault();
userCreateStory(summary,description,type,complexity,time,cost)
setTimeout(()=> history.push("/userStories"), 1000 );
//setTimeout(()=> console.log(currStory) ,1000)
}
return (
<div>
<form className='create-story-form'>
<label for="summary">Summary:</label>
<input name="summary" type='text' onChange={handleSummaryChange}/>
<label for="desc">Description:</label>
<textarea name="desc" type='text' onChange={handleDescriptionChange}/>
<label for="type">Type:</label>
<select name="type" onChange={handleTypeChange}>
<option value="enhancement" defaultValue>Enchancement</option>
<option value="bugfix">Bugfix</option>
<option value="development">Development</option>
<option value="qa">QA</option>
</select>
<label for="complexity">Complexity:</label>
<select name="complexity" onChange={handleComplexityChange}>
<option value="low" defaultValue>Low</option>
<option value="mid">Mid</option>
<option value="high">High</option>
</select>
<label for="time">Estimated time for completion:</label>
<input name="time" type='text' onChange={handleTimeChange}/>
<label for="cost">Cost:</label>
<input name="cost" type='number' onChange={handleCostChange}/>
<button onClick={handleSubmit}>Submit</button>
</form>
</div>
)
}
export default withRouter(CreateStory);
Login.js
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { login, roleChange } from '../redux/actions' //OUR ACTIONS
import { useSelector } from 'react-redux'
import history from '../utils/history';
import { withRouter } from 'react-router-dom';
const Login = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [isAdmin, setIsAdmin] = useState(false);
const usedispatch = useDispatch();
const userLogin = (email, password, isAdmin) => usedispatch(login({'email': email, 'password': password, 'isAdmin': isAdmin }));
const handleRoleChange = e => {
setIsAdmin(true)
if(isAdmin)
setIsAdmin(false)
console.log(isAdmin)
}
const handleEmailChange = e => {
setEmail(e.target.value)
}
const handlePasswordChange = e => {
setPassword(e.target.value)
}
const handleSubmit = e => {
e.preventDefault();
userLogin(email, password, isAdmin)
setTimeout(()=> history.push("/user"), 1000 );
}
const disabled = () => {
return email === "" || password === ""
}
return (
<div>
<form className='login-form'>
<input type='email' name='email' placeholder='Email' onChange={handleEmailChange}/>
<input type='password' name='password' placeholder='Password' onChange={handlePasswordChange}/>
<button type='submit' disabled={disabled()} onClick={handleSubmit}>Login</button>
</form>
<button onClick={handleRoleChange}>Switch to {isAdmin ? 'user' : 'admin'}</button>
</div>
)
}
export default withRouter(Login);
reducers.js
import { initialState } from './initialState';
import * as t from './actionTypes';
export const loginReducer = (state = initialState, action) => {
switch (action.type) {
case t.SET_ROLE_STATE:
return {
...state,
isAdmin: true
};
case t.SET_LOGIN_STATE:
return {
...state,
...action.payload, // this is what we expect to get back from API call and login page input
isLoggedIn: true, // we set this as true on login
};
case t.LOGOUT:
return {
initialState
};
default:
return state;
}
};
export const storyReducer = (state = [], action) => {
switch (action.type) {
case t.CREATE_STORY:
return {
...state,
stories: [...state.stories, action.payload],
};
case t.GET_STORIES:
return {
...state,
stories: action.payload,
};
case t.GET_STORY:
return {
...state,
story: action.payload,
};
// case t.ADD_STORY:
// return {
// ...state,
// stories: [...state.stories, action.payload], //stories is an object
// };
case t.LOGOUT:
return {
stories: [{complexity: "",
cost: 0,
description: "",
summary: "",
time: "",
type: ""}]
};
default:
return state;
}
}
i am having exsiting service to make api call through axios in my react app,which i think is limited to one api request at a time,i wanted to make multiple request using axios.all,but i am not able to find way to modify the service,see below is the code
As in Action.js you can see that i combine two request which is wrong i guess so,please help me how to combine two request using axios.all,and please suggest api service implementation is correct or what can i do to improve it
APIService.js
import axios from 'axios';
import apiConfig from './apiConfig';
import UserSession from './userSession';
import history from '../utils/history/history';
const session = sessionStorage;
var axiosConfig = axios.create({
baseURL: apiConfig.baseUrl,
headers: {
Authorization: sessionStorage.getItem('token') != null ?
`Bearer ${sessionStorage.getItem('token')}` : null,
Accept: 'application/json',
'Content-Type': 'application/json'
},
timeout: 20000,
responseType: 'json'
});
axiosConfig.interceptors.request.use((config) => {
config.headers.Authorization =
sessionStorage.getItem('token') != null ? `Bearer
${sessionStorage.getItem('token')}` : null;
return config;
},(error) => Promise.reject(error));
const apiService = function(options) {
const onSuccess = function(response) {
if (response.status === 201) {
return Promise.resolve(
Object.assign(
{},
{
message: response.statusText
}
)
);
} else if (response.status === 200) {
if ((response.data && response.data !== null) || response.data !==
undefined || response.data !== '') {
return response.data;
} else {
return Promise.resolve(
Object.assign(
{},
{
message: response.statusText
}
)
);
}
} else if (response.data.length < 1) {
return Promise.reject(
Object.assign(
{},
{
message: 'No Data'
}
)
);
} else {
return response.data;
}
};
const onError = function(error) {
if (error.response) {
if (error.response.status === 401) {
sessionStorage.removeItem('token');
window.location = '/login';
return Promise.reject(error.response);
} else if (error.response.status === 404) {
return Promise.reject(
Object.assign(
{},
{
message: error.response.statusText
}
)
);
} else if (error.response.status === 500) {
return Promise.reject(
Object.assign(
{},
{
message: error.response.statusText
}
)
);
} else {
return Promise.reject(error.response.data);
}
} else if (error.request) {
// The request was made but no response was received
return Promise.reject(
Object.assign(
{},
{
message: error.message
}
)
);
//return Promise.reject(error.message);
} else {
// Something else happened while setting up the request
// triggered the error
return Promise.reject(
Object.assign(
{},
{
message: error.message
}
)
);
}
};
return axiosConfig(options).then(onSuccess).catch(onError);
};
export default apiService;
Request.js
import apiService from '../apiService';
export const FirstRequest = () => {
return apiService({
url: 'FirstURL',
method: 'get',
});
};
export const SecondRequest = () => {
return apiService({
url: 'SecondURL',
method: 'get',
});
};
Action.js
export const SomeHandler = () => (dispatch) => {
dispatch({
type: API_REQUEST
});
FirstRequest()
.then((res) => {
dispatch({
type: API_SUCCESS
});
SecondRequest().then((res) => {
dispatch({
type: API_SUCCESS
});
dispatch({ type: VIEW1, payload: res });
dispatch({ type: VIEW2, payload: res });
}).catch((err) => {
dispatch({
type: API_FAILURE,
payload: err
});
});
})
.catch((err) => {
dispatch({
type: API_FAILURE,
payload: err
});
});
};
This is not related to axios at all. You can combine two async functions together in an action method, using async library:
async.parallel([
getUsers,
getComments
],
function(err, results) {
// the results array will equal to [[], {'x': 'y'}] even though
// the second function had a shorter timeout.
// dispatch here
});
function getUsers(callback) {
callback(null, [])
}
function getComments(callback) {
callback(null, {'x': 'y'})
}
First off, not sure you want to do this in your componentWillMount, because your component will not render until all this is done, it's better to have it in componentDidMount and have some default states that will update once done with these requests. Second, you want to limit the number of setStates you write because they might cause additional re-renders, here is a solution using async/await:
async componentDidMount() {
const firstRequest = await axios.get(URL1);
const secondRequest = await axios.get(URL2);
const thirdRequest = await axios.get(URL3);
this.setState({
p1Location: firstRequest.data,
p2Location: SecondRequest.data,
p3Location: thirdRequest.data,
});
}
i'm working this way. you can use this
const token_config = {
headers: {
'Authorization': `Bearer ${process.env.JWD_TOKEN}`
}
}
const [ res1, res2 ] = await Axios.all([
Axios.get(`https://api-1`, token_config),
Axios.get(`https://api-2`, token_config)
]);
res.json({
info: {
"res_1": res1,
"res_2": res2
}
});