React fetch error/response catching not working - java

I built a signup page that needs to check whether an inputted email is already taken.
When a duplicate email is taken, it gets stopped in the java spring api backend and returns a status of "400".
(I've also tried using the spring annotation #column(unique=true) but could not get the 422 error to catch, either.)
I then have a catch for that status, which should then set an error (for which a field exists); when any error is set, the page won't continue. If there are no errors, the page automatically signs in and reroutes to the homepage.
I've tried catching the error as error, error status, error response, and response. (since technically a received exception from the backend isnt an error.) I just can't seem to get it to catch.
I'd appreciate if anyone knows what's wrong here and how to fix it.
the signup code, in which I'm leaving the various methods by which I've tried to catch the response:
const signUp = () => {
axios
.post('http://localhost:8080/signup', {
email,
password,
firstName,
lastName
// address,
// phoneNumber,
// image
})
// eslint-disable-next-line consistent-return
.catch((err) => {
if (err.status) {
setEmailUsedError('Already in use. ');
}
})
.then(() => {
post('/login', null, {
email,
password
}).then((data) => {
if ('token' in data) {
sessionStorage.token = data.token;
const { sub } = JSON.parse(atob(data.token.split('.')[1]));
sessionStorage.email = sub;
onLogin();
history.push('/');
}
})
.catch((err) => {
if (err.res.status === 422) {
setEmailError('Already in use. ');
} else setServerError(true);
});
});
};
then the uncaught error message in the browser:
Update: I changed .then((res)... to `.catch
.then((res) => {
if (res.status) {
setEmailUsedError('Already in use. ');
}
in the signUp function to .catch((err)...
Now it's showing the error is caught, but isn't setting the error as is coded. Not sure why.
Same result when I tried .catch((res)...

While there may be other factors in play, based on the console message it is your call to the /signup endpoint that is returning 422, rather than /login (as shown in the code sample). You may wish to check if the enclosing block calling it is itself chained with a catch statement.
Based on the assumption that /signup is called immediately before /login, you'll need a catch block on the same indent level as the .then(() => {post()...}.

Related

Avoid refreshing and saving token multiple times in a cache during parallel https calls to service

I am currently in the process of replacing the blocking HTTP calls from one of my projects with Asynchronous/reactive calls. The saveOrderToExternalAPI is an example of the refactor I have done that replaced the blocking HTTP call and now using reactive WebClient.
The function saveOrderToExternalAPI calls an endpoint and returns an empty MONO in case of success. It also retries when the API returns 401 Unauthorized error which happens when the token is expired. If you notice the retryWith logic, you will see the code is renewing the token (tokenProvider.renewToken()) before actually retrying.
The tokenProvider.renewToken() for now is a blocking call that fetches a new token from another endpoint and saves it to a Cache so that we don't have to renew the token again and subsequent calls can just reuse it. Whereas the tokenProvider.loadCachedToken() function check and return token if it is not Null, otherwise renew and then return it.
public Mono<ResponseEntity<Void>> saveOrderToExternalAPI(Order order) {
log.info("Sending request to save data.");
return webclient.post()
.uri("/order")
.headers(httpHeaders -> httpHeaders.setBearerAuth(tokenProvider.loadCachedToken()))
.accept(MediaType.APPLICATION_JSON)
.bodyValue(order)
.retrieve()
.toBodilessEntity()
.doOnError(WebClientResponseException.class, logHttp4xx)
.retryWhen(unAuthorizedRetrySpec())
.doOnNext(responseEntity -> log.debug("Response status code: {}",
responseEntity.getStatusCodeValue()));
}
private RetryBackoffSpec unAuthorizedRetrySpec() {
return Retry.fixedDelay(1, Duration.ZERO)
.doBeforeRetry(retrySignal -> log.info("Renew token before retrying."))
.doBeforeRetry(retrySignal -> tokenProvider.renewToken())
.filter(throwable -> throwable instanceof WebClientResponseException.Unauthorized)
.onRetryExhaustedThrow(propagateException);
}
private final Consumer<WebClientResponseException> logHttp4xx = e -> {
if (e.getStatusCode().is4xxClientError() && !e.getStatusCode().equals(HttpStatus.UNAUTHORIZED)) {
log.error("Request failed with message: {}", e.getMessage());
log.error("Body: {}", e.getResponseBodyAsString());
}
}
// -------- tokenProvider service
public String loadCachedToken() {
if (token == null) {
renewToken();
}
return token;
}
Everything is working fine because for now, the saveOrderToExternalAPI is eventually doing a blocking call in the Service layer.
for (ShipmentRequest order: listOfOrders) {
orderHttpClient.saveOrderToExternalAPI(order).block();
}
But, I would like this to be changed and refactor the service layer. I am wondering would happen if I keep using the existing logic of token renewal and process the saveOrderToExternalAPI parallelly as below.
List<Mono<ResponseEntity<Void>>> postedOrdersMono = listOfOrders.stream()
.map(orderHttpClient::saveOrderToExternalAPI)
.collect(Collectors.toList());
Mono.when(postedOrdersMono).block();
Now the calls will be done parallelly and the threads would try to update token cache at the same time (in case of 401 unauthorized) even though updating it once is enough. I am really new to reactive and would like to know if there's any callback or configuration that can fix this issue?

user.permissionsBoundary returns NULL while retrieving information from AWS using Java SDK

I am using AWS Java SDK v2 to list users using the code defined here on the AWS GitHub repo.
public static void listAllUsers(IamClient iam) {
try {
boolean done = false;
String newMarker = null;
while (!done) {
ListUsersResponse response;
ListUsersRequest request;
if (newMarker == null) {
request = ListUsersRequest.builder().build();
} else {
request = ListUsersRequest.builder()
.marker(newMarker).build();
}
response = iam.listUsers(request);
for (User user : response.users()) {
System.out.format("\n Retrieved user %s", user.userName());
System.out.println("\nPermission Boundary: " + user.permissionsBoundary());
}
if (!response.isTruncated()) {
done = true;
} else {
newMarker = response.marker();
}
}
} catch (IamException e) {
System.err.println(e);
System.exit(1);
}
}
It returns NULL for user.permissionsBoundary(). Here is the output for print statements in the above code.
Retrieved user jamshaid
Permission Boundary: null
Retrieved user luminadmin
Permission Boundary: null
Retrieved user test
Permission Boundary: null
When I run the following command in AWS CloudShell on AWS console, it returns the PermissionBoundary for the users it is defined.
aws iam get-user --user-name test
Here is the sample output from AWS CloudShell.
I am using the same account to make both requests.
I have confirmed this behavior by setting a permission boundary on an IAM user in the AWS Management Console. I changed the ListUsers example to include this code:
for(User user : response.users()) {
System.out.format("\n Retrieved user %s", user.userName());
AttachedPermissionsBoundary permissionsBoundary = user.permissionsBoundary();
if (permissionsBoundary != null)
System.out.format("\n Permissions boundary details %s", permissionsBoundary.permissionsBoundaryTypeAsString());
}
...
The permissionsBoundary() method does return null - even though the permission is set. This is a bug.
My advice here is to log a Github issue here:
https://github.com/aws/aws-sdk-java-v2
I also tested this with Kotlin SDK. Same result.
suspend fun listAllUsers() {
IamClient { region = "AWS_GLOBAL" }.use { iamClient ->
val response = iamClient.listUsers(ListUsersRequest { })
response.users?.forEach { user ->
println("Retrieved user ${user.userName}")
val permissionsBoundary = user.permissionsBoundary
if (permissionsBoundary != null)
println("Permissions boundary details ${permissionsBoundary.permissionsBoundaryType.toString()}")
}
}
}
I do not think it is an issue, but the programmed behavior. From the API docs:
IAM resource-listing operations return a subset of the available attributes
for the resource. For example, this operation does not return tags, even
though they are an attribute of the returned object. To view all of the
information for a user, see GetUser.
This is stated as well in the API javadocs.
In the console you are using get-user, not list-users, and this is why the command is returning all the information about the user, PermissionsBoundary within it.
Please, try instead using:
aws iam list-users
and check the output, it should match the result you obtained with the Java SDK, it will not contain PermissionsBoundary either.
If you want to obtain the same results that you are currently getting with the command aws iam get-user --user-name test from Java code, you can use the getUser method in IamClient. Try Something like:
GetUserRequest request = GetUserRequest.builder()
.userName("test")
.build()
;
GetUserResponse response = iam.getUser(request);
User user = response.user();
System.out.println("\nPermission Boundary: " + user.permissionsBoundary());
The User class is reused in both operations, get and list, but only in the former all the fields are populated.

isRequestedSessionIdValid returning false after successful login

I'm implementing LDAP authentication on Java web app, and I'm getting the following:
try {
System.out.println(servletRequest.isRequestedSessionIdValid()); //prints true
servletRequest.login(lUser, lPassword);//successfully logs in
System.out.println(servletRequest.isRequestedSessionIdValid()); //prints false
} catch (ServletException se) {
logger.error("Error authenticating user", se);
return STATE_INPUT;
}
Meaning: login method, successfully executed, renders the session invalid... Anyone knows why this happens and how to fix it?
Asking because later the app validades if servletRequest.isRequestedSessionIdValid() == true and as shown in the code above the login method makes it false.

Conversation ID leads to unkown path in graph-api

I have a code that fetches conversations and the messages inside them (a specific number of pages). It works most of the time, but for certain conversations it throws an exception, such as:
Exception in thread "main" com.restfb.exception.FacebookOAuthException: Received Facebook error response of type OAuthException: Unknown path components: /[id of the message]/messages (code 2500, subcode null)
at com.restfb.DefaultFacebookClient$DefaultGraphFacebookExceptionMapper.exceptionForTypeAndMessage(DefaultFacebookClient.java:1192)
at com.restfb.DefaultFacebookClient.throwFacebookResponseStatusExceptionIfNecessary(DefaultFacebookClient.java:1118)
at com.restfb.DefaultFacebookClient.makeRequestAndProcessResponse(DefaultFacebookClient.java:1059)
at com.restfb.DefaultFacebookClient.makeRequest(DefaultFacebookClient.java:970)
at com.restfb.DefaultFacebookClient.makeRequest(DefaultFacebookClient.java:932)
at com.restfb.DefaultFacebookClient.fetchConnection(DefaultFacebookClient.java:356)
at test.Test.main(Test.java:40)
After debugging I found the ID that doesn't work and tried to access it from graph-api, which results in an "unknown path components" error. I also attempted to manually find the conversation in me/conversations and click the next page link in the graph api explorer which also lead to the same error.
Is there a different way to retrieve a conversation than by ID? And if not, could someone show me an example to verify first if the conversation ID is valid, so if there are conversations I can't retrieve I could skip them instead of getting an error. Here's my current code:
Connection<Conversation> fetchedConversations = fbClient.fetchConnection("me/Conversations", Conversation.class);
int pageCnt = 2;
for (List<Conversation> conversationPage : fetchedConversations) {
for (Conversation aConversation : conversationPage) {
String id = aConversation.getId();
//The line of code which causes the exception
Connection<Message> messages = fbClient.fetchConnection(id + "/messages", Message.class, Parameter.with("fields", "message,created_time,from,id"));
int tempCnt = 0;
for (List<Message> messagePage : messages) {
for (Message msg : messagePage) {
System.out.println(msg.getFrom().getName());
System.out.println(msg.getMessage());
}
if (tempCnt == pageCnt) {
break;
}
tempCnt++;
}
}
}
Thanks in advance!
Update: Surrounded the problematic part with a try catch as a temporary solution, also counted the number of occurrences and it only effects 3 out of 53 conversations. I also printed all the IDs, and it seems that these 3 IDs are the only ones that contain a "/" symbol, I'm guessing it has something to do with the exception.
The IDs that work look something like this: t_[text] (sometimes a "." or a ":" symbol) and the ones that cause an exception are always t_[text]/[text]
conv_id/messages is not a valid graph api call.
messages is a field of conversation.
Here is what you do (single call to api):
Connection<Conversation> conversations = facebookClient.fetchConnection("me/conversations", Conversation.class);
for (Conversation conv : conversations.getData()) {
// To get list of messages for given conversation
LinkedList<Message> allConvMessagesStorage = new LinkedList<Message>();
Connection<Message> messages25 = facebookClient.fetchConnection(conv.getId()+"/messages", Message.class);
//Add messages returned
allConvMessagesStorage.addAll(messages25.getData());
//Check if there is next page to fetch
boolean progress = messages25.hasNext();
while(progress){
messages25 = facebookClient.fetchConnectionPage(messages25.getNextPageUrl(), Message.class);
//Append next page of messages
allConvMessagesStorage.addAll(messages25.getData());
progress = messages25.hasNext();
}
}

How to save the response data return by Facebook in Java class using Spring MVC

I am trying to save the user data which is return by the Facebook response.
I am using Facebook Javascript.Response is in JSon format and I want to parse it first and then save it in to my database using java.
<script>
// This is called with the results from from FB.getLoginStatus().
function statusChangeCallback(response) {
console.log('statusChangeCallback');
console.log(response);
// The response object is returned with a status field that lets the
// app know the current login status of the person.
// Full docs on the response object can be found in the documentation
// for FB.getLoginStatus().
if (response.status === 'connected') {
// Logged into your app and Facebook.
/* var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
console.log("User id is" + uid);
console.log(accessToken); */
document.getElementById('accesstoken').value=response.authResponse.accessToken;
console.log(response.authResponse.accessToken);
testAPI();
} else if (response.status === 'not_authorized') {
// The person is logged into Facebook, but not your app.
document.getElementById('status').innerHTML = 'Please log ' +
'into this app.';
} else {
// The person is not logged into Facebook, so we're not sure if
// they are logged into this app or not.
document.getElementById('status').innerHTML = 'Please log ' +
'into Facebook.';
}
}
// This function is called when someone finishes with the Login
// Button. See the onlogin handler attached to it in the sample
// code below.
function checkLoginState() {
FB.getLoginStatus(function(response) {
statusChangeCallback(response);
});
}
window.fbAsyncInit = function() {
FB.init({
appId : 'xxxxxxxxxxxxxxxxxxxx',
cookie : true, // enable cookies to allow the server to access
// the session
xfbml : true, // parse social plugins on this page
version : 'v2.2' // use version 2.2
});
// Now that we've initialized the JavaScript SDK, we call
// FB.getLoginStatus(). This function gets the state of the
// person visiting this page and can return one of three states to
// the callback you provide. They can be:
//
// 1. Logged into your app ('connected')
// 2. Logged into Facebook, but not your app ('not_authorized')
// 3. Not logged into Facebook and can't tell if they are logged into
// your app or not.
//
// These three cases are handled in the callback function.
FB.getLoginStatus(function(response) {
statusChangeCallback(response);
});
};
// Load the SDK asynchronously
(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
// Here we run a very simple test of the Graph API after login is
// successful. See statusChangeCallback() for when this call is made.
function testAPI() {
// window.location="http://localhost:8080/SpringMvcHibernateJavaBased/list";
console.log('Welcome! Fetching your information.... ');
FB.api('/me', function(response) {
console.log('Successful login for: ' + response.name);
console.log(response);
document.getElementById('status').innerHTML =
'Thanks for logging in, ' + response.name + '!';
document.getElementById('usernamefb').value=response.name;
document.getElementById('userId').value=response.id;
document.getElementById('emailfb').value=response.email;
});
}
function checkLogoutState(){
FB.logout(function(response) {
FB.Auth.setAuthResponse(null, 'unknown');
});
};
function checkData()
{
return $.ajax({
})
}
</script>
I am using Spring MVC approach fully JAVA based not using any xml files.
I have searched lot but didn't get any solution
In "if (response.status === 'connected') {}" block you need to call another API of Facebook to fetch the user's details by passing user id and token and after receiving the data you can call your own controller through Ajax and save into DB if required.
Another solution can be, you may use "http://projects.spring.io/spring-social/" on server side itself.
Krish

Categories

Resources