Fetch and postman response are different - reactjs

I am writing my react flask-rest site and and encountered unusual behavior ... of something. So when i create a get request at the address domain/api/users/1, where 1 = id of deleted db element in postman my response consist of one null element(as written in the code). But when i create this request in fetch i get error 410. I have a check for the existence of an element in the code, but this response does not allow my code to execute and all the logic of the program breaks. Moreover, when using a fetch, information about such a request does not even appear in the flask log (when using postman, everything is fine). So maybe I write a lot of unnecessary information, but I really dont understand what is wrong
python code:
def get(self, id):
u = User.query.filter_by(id=id).first()
if u:
return {
'id': u.id,
'username': u.username,
'email': u.email}
if id is not exist return null (works with IDs that never existed)
js-react code:
const [user, setUser] = useState({});
useEffect(() => {
fetch(`/api/users/${match.params.id}`)
.then((res) => res.json())
.then((data) => setUser(data))
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (!user) {
return <h1>Same user dont exists</h1>;
}
return (
<>
<h1 className="mb-3">{user.username}</h1>
<div>{user.email}</div>
</>
);

Not sure if this solves your problem, but you can try adding an else: block in case the user id does not exist and return an empty dictionary
def get(self, id):
u = User.query.filter_by(id=id).first()
if u:
return {
'id': u.id,
'username': u.username,
'email': u.email}
else:
return {}
# alternatively:
# return {"message": "User does not exist"}, 404
I dont know why this works for you one way but not the other, but it seems like not returning anything at all might break your code. Alternatively, return a 404 not found if the user doesnt exist, and handle the case separately based on the status code.
Also; I dont know why or how your server returns a 410 GONE. If I test a route with no explicit return, I get a 200 OK and the response body is "null". There might be more code involved than you posted in your question.

Related

Can URL API endpoint self-correct?

I am using fetch API inside a React application to retrieve and display some quiz questions.
This is my url endpoint: https://opentdb.com/api.php?amount=${amount}&difficulty=${difficulty}&type=multiple
I have noticed that:
-when I misspell part of the URL before "?" then the response doesn't get back.
example:https://opentdb.com/api.ph?amount=${amount}&difficulty=${difficulty}& (missing "p" of php)
-when I misspell part of the url after "?" then, sometimes I get an empty array back, sometimes I get the data back. How can I get data back with a wrong URL?
example: https://opentdb.com/api.php?amoun=${amount}&difficulty=${difficulty}&type=multiple (missing "t" in amount)
I haven't deployed the application yet, I am using vsc and run npm start to develop the application.
Is it possible that the URL auto-corrects? or maybe it gets cached?
my code:
export const fetchQuizQuestions = async (
amount: number,
difficulty: Difficulty
) => {
const endPoint = `https://opentdb.com/api.php?amount=${amount}&difficulty=${difficulty}&type=multiple`;
try {
const response = await fetch(endPoint);
console.log(response);
const data = await response.json();
console.log(data);
if (data.results.length === 0) {
throw new Error("The part after ? contains some mistake");
}
//below I create the new property "all_answers" and make sure the answers order is never the same
return data.results.map((question: Question) => ({
...question,
all_answers: shuffleArray([
...question.incorrect_answers,
question.correct_answer,
]),
}));
} catch (error: any) {
console.log(error.name);
console.log(error.message);
}
};
Before the ? It's the url. So if you make a mistake there, basically it's like sending a letter to a different adress, so you will not get any answers.
After the ? it's the query string. So you're asking for a result, with some parameters (your query)
So if you're saying like "ok, send me back answers with amount = XXX" but you misspell amount, it's just like "ok send me back answers" because you're not asking for amount anymore (but amoun which is nothing for the endpoint)

Django views not returning a value from a multiple parameter request?

I've been using vanilla Django as a backend to my React frontend. I'm trying to make a POST request using axios that passes a dictionary of 2 values to my django view, and so far on my front end the values are valid, the connection to the django url is made, but the only issue is the actual data being processed in the view. If I try to print the value, it returns as None. Heres what I have so far:
Relevant Code
views.py
def render_data(request):
reddit_url = request.POST.get('reddit_url')
sort = request.POST.get('sort')
print(reddit_url, sort)
users_data, count = run_data(reddit_url, sort)
data = {
'users_data': users_data,
'count': count,
}
return JsonResponse(data)
component.jsx
const APIcall = () => {
axios
.post(
`http://127.0.0.1:8000/reddit_data/`,
{
reddit_url: location.state.link,
sort: location.state.sort,
},
{
headers: {
"Content-Type": "application/json",
"X-CSRFToken": location.state.token,
},
withCredentials: true, //cors requests
}
)
.then((res) => {
console.log("YESSIR");
setLoading(false);
});
};
Expected/actual output
Ideally, the output would print the values from the request, but the actual result is just None, None.
What I tried
I tried using request.POST['reddit_url'] with no different results
Double checking the frontend values to make sure the POST call is going through with the correct values
I'll be honest I havent tried much I really cant understand this one
Turns out, my QueryDict was returning empty in my Django console while trying to print it, and I simply solved it by using var formData = new FormData(); appending my values, then using it as a parameter in my axios post to make a POST request.

React Query handling response status codes

this is related to this question:
Handling unauthorized request in react-query
I understand the point that React-Query doesnt care about responses codes because there is no error. So for example if the server respond with a 400 "Bad Request", do i have to check for this on the data returned by the muate function?
const handleFormSubmit = async (credentials) => {
const data = await mutateLogin(credentials);
// Do i have to check this data if for example i wanna show an error message
// "Invalid Credentials"?
};
I need to save the user on the cache.
const useMutateLogin = () => {
return useMutation(doLogin, {
throwOnError: true,
onSuccess: data => // Do i have to check here again if i receive the user or 400 code
})
}
Thanks.
react-query does not take care of the requests and it is completely agnostic of what you use to make them as long you have a Promise. From the documentation we have the following specification for the query function:
Must return a promise that will either resolves data or throws an error.
So if you need to fail on specific status codes, you should handle that in the query function.
The confusion comes because popular libraries usually take care of that for you. For example, axios and jQuery.ajax() will throw an error/reject if the HTTP status code falls out of the range of 2xx. If you use the Fetch API (like the discussion in the link you posted), the API won't reject on HTTP error status.
Your first code snippet:
const handleFormSubmit = async (credentials) => {
const data = await mutateLogin(credentials);
};
The content of data depends on the mutateLogin function implementation. If you are using axios, the promise will reject to any HTTP status code that falls out of the range of 2xx. If you use the Fetch API you need to check the status and throw the error or react-query will cache the whole response as received.
Your second code snippet:
const useMutateLogin = () => {
return useMutation(doLogin, {
throwOnError: true,
onSuccess: data => // Do i have to check here again if i receive the user or 400 code
})
}
Here we have the same case as before. It depends on doLogin implementation.

Redux how I should handle update with API call

I have an application that triggers many update and I would like to know more about the best way to update the app properly.
In my app, I have 5 slots to fill with books (can be managed by drag and drop). When the app launches, the filled book for the user are loaded and are stored in the state.
Problem : when I update a book, like if I switch the position of 2 books in my list, I must do some operations to say "this book belongs here now and the other one belongs here now, switch!"
I feel like I'm doing some tedious actions because if I just return the whole data (get, after updating) from my API call and call the "load" function (as I do when I launch the app) I will not have to handle the update of the operation.
Plus, it could create bug If I'm loading correctly, but not updating correctly (if I miss position of a book for example)
The benefit I see in a functional update is that I only update the 2 books I need, instead of reload all of them again and again.
What way would be better? Should I get rid of those updates functions and just reload the data entirely? I think there could be also some libraries that cache it to only re-render modified books
Thanks you
Without code it is difficult to fully understand the problem but getting the data from the server has 2 advantages.
You are sure the ui shows the data as it is on the server
Your client code does not need to contain the logic of what needs to happen, the server has this logic. When the logic is refactored in some way they don't go out of sync.
Because of this I usually choose to get the data as is on the server.
One problem with fetching data based on user interaction is that fetching is async so the following can happen:
User does action A, request made for A, user Does action B, request made for B, B request resolves and UI is set to result of request B, request made for A resolves and UI is set to result of A.
So the order the user does the actions does not guarantee the order in which the requests are resolved.
To solve this you can use a helper that resolves only if it was last requested, in the example above when A request resolves the UI does not need to be set with anything because it has already been replaced with another request.
In the example below you can type search value, when the value is 1 character long it'll take 2 seconds to resolve so when you type ab the ab request will resolve before the a request. but because the function making the request is wrapped with the last helper when a resolves it'll will be rejected because it has been replaced with the newer request ab.
//constant to reject with when request is replaced with a
// more recent request
const REPLACED = {
message: 'replaced by more recent request',
};
//helper to resolve only last requested promise
const last = (fn) => {
const check = {};
return (...args) => {
const current = {};
check.current = current;
return Promise.resolve()
.then(() => fn(...args))
.then((result) => {
//see if current request is last request
if (check.current === current) {
return result;
}
//was not last request so reject
return Promise.reject(REPLACED);
});
};
};
const later = (howLong, value) =>
new Promise((resolve) =>
setTimeout(() => resolve(value), howLong)
);
const request = (value) =>
later(value.length === 1 ? 2000 : 10, value).then(
(result) => {
console.log('request resolved:', result);
return result;
}
);
const lastRequest = last(request);
const App = () => {
const [search, setSearch] = React.useState('');
const [result, setResult] = React.useState('');
React.useEffect(() => {
//if you use request instead of lastRequest here
// you see it will break, UI is updated as requests
// resolve without checking if it was the last request
lastRequest(search)
.then((result) => setResult(`result:${result}`))
.catch((err) => {
console.log(
'rejected with:',
err,
'for search:',
search
);
if (err !== REPLACED) {
//if the reject reason is not caused because request was
// replaced by a newer then reject this promise
return Promise.reject(err);
}
});
}, [search]);
return (
<div>
<label>
search
<input
type="text"
value={search}
onChange={(e) => setSearch(e.target.value)}
></input>
</label>
<div>{result}</div>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

how to append the multiple api's

I'm having multiple of api's. how to i get the output.here i'm added the sample snippet. in that abc is the component. next component xyz, pqr like that.
let str1="http://localhost:ip/abc?text="+this.state.content;
fetch(str1, {
method: "GET",
})
.then(res => res.json())
.then(res => {
this.setState({
res: res.abc
});
});
I'm going to make some assumptions. Assuming you want to make 3 different API requests at the same time, and use the results for React setState, you can do so with Promise.all:
const reqA = fetch(`http://localhost:ip/abc?text=${this.state.content}`);
const reqX = fetch(`http://localhost:ip/xyz?text=${this.state.content}`);
const reqP = fetch(`http://localhost:ip/pqr?text=${this.state.content}`);
Promise.all([reqA, reqX, reqP]).then(function(allResults) {
Promise.all(allResults.map(res => res.json())).then(function(
jsonResults
) {
console.log("Results", jsonResults);
// Parse, and call `setState` here
});
});
The snippet above will make XHR calls to the 3 URLs at the same time, collect its result, attempt to parse the response to JSON for all 3 of the responses, and collect the results of that. At this point, you can parse, and set the response in the state.
Note that this does not include logic for dealing with errors in any of the 3 requests. You should account for that. If your request URLs are as similar as the code snippet above, then perhaps you can define a function for constructing a URL given a "component". The snippet above also does not account for the possibility that your component may become unmounted while requests are still in-flight.

Resources