I have a user registration API written in node but the API gives me three types of responses
If the registration is successful then the below JSON is the response
{
"message": "success",
"ccontent": {
"_id": "5ef7c4c414529241205fb590",
"email": "sam#gmail.com",
"password": "$2b$05$4TFPKJ83O7jSPhjtIIDj1ud5pjhS9GY.I0C.IFlBDyUFsd6i4E3Ci",
"__v": 0
}
}
If the user already exists it just gives me a string response
already-exists
If error occurred
error-occurred
I have a future function to get the response from the API
class RegistrationService {
String registrationUrl = 'http://192.168.1.6:8080/api/user/create';
Future userRegistration(email, password) async {
Response response = await post(registrationUrl,
body: {"email": email, "password": password});
var result = jsonDecode(response.body);
return RegistrationResponse.fromJson(result);
}
}
This works only when the user registration is a success but when it fails error occurs telling unhandled exception 'already-exists' or 'error-occurred'
How can I get all types of responses from the API in this future function?
Thanks in advance.
You could throw an exception in case response is already-exists or error-occurred
class RegistrationService {
String registrationUrl = 'http://192.168.1.6:8080/api/user/create';
Future<Map<String, dynamic> userRegistration(email, password) async {
Response response = await post(registrationUrl,
body: {"email": email, "password": password});
if (userAlreadyExist(response.body)) {
// already-exists response
throws UserAlreadyExistException();
}
else if (errorOccurred(response.body)) {
// error occurred response
throws SomeOtherException();
}
var result = jsonDecode(response.body);
return RegistrationResponse.fromJson(result);
}
}
You would need to implement methods userAlreadyExist and errorOccurred to detect this situation and decide what's the best exception type for every case. You would also need to cath the exception when you call userRegistration so you can react properly.
Related
This is My Flutter Code--
void send() async
{
var bb=json.encode(listModel.toJson());
var response = await http.post(Uri.parse(
"http://10.0.2.2:1066/api/Storedata/Add"),
body: bb,
headers: {"Content-type": "application/json"},);
if (response.statusCode == 201)
{
print("Done");
}
else
{
print(response.body);
print(response.statusCode);
}
}
In "bb" variable all data show in json format when i debugged. but show this error "HTTP Error 400. The request hostname is invalid". Please Help!!!!
I have a mysterious issue that I don't understand. I'd like to do an application that can send a Teams (Microsoft Teams) message to a specific user.
Furthermore, I can achieve this without trouble using the API (with Postman).
As you can see, I don't have any issue to do the request.
However, when I do this with my app (using Flutter) I get an error 400 with this message :
{
"error": {
"code": "BadRequest",
"message": "The provided '#microsoft.graph.aadUserConversationMember' for 'odata.type' is not valid for this operation., The provided '#microsoft.graph.aadUserConversationMember' for 'odata.type' is not valid for this operation.",
"innerError": {
"date": "2022-07-15T13:58:13",
"request-id": "99a5b654-d137-4c4f-9473-234747b32c42",
"client-request-id": "99a5b654-d137-4c4f-9473-234747b32c42"
}
}
}
Obviously, my access token is exactly the same as well as permissions to achieve this request. User's IDS are also the same.
What I am doing:
The request
headers: contains the token and the responseType
final url = Uri.https('graph.microsoft.com', "/v1.0/chats");
final body = ChatMemberDto(
personId: personId,
visitedPersonId: visitedPersonId)
.toJsonStr();
var response = await http.post(url, headers: _headers, body: body);
ChatMemberDto
I know, not well-designed ;)
class ChatMemberDto {
String personId;
String visitedPersonId;
ChatMemberDto({required this.personId, required this.visitedPersonId});
String toJsonStr() {
var data = {
"chatType": "oneOnOne",
"members": [
{
"#odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": ["owner"],
"user#odata.bind":
"https://graph.microsoft.com/v1.0/users('$personId')"
},
{
"#odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": ["owner"],
"user#odata.bind":
"https://graph.microsoft.com/v1.0/users('$visitedPersonId')"
}
]
};
return jsonEncode(data);
}
}
I have followed the documentation described here : https://learn.microsoft.com/en-us/graph/api/chat-post?view=graph-rest-1.0&tabs=http
I guess the issue come from my code, because I can do it with Postman. But I can’t understand why??
PS: I've tested it on Android Emulators and real Android devices
Thanks in advance for your help :)
I think the issue is with the conversion to string
Can you try like this and check if it is working
class ChatMemberDto {
String personId;
String visitedPersonId;
ChatMemberDto({required this.personId, required this.visitedPersonId});
String toJsonStr() {
var data = {
"chatType": "oneOnOne",
"members": [
{
"#odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": ["owner"],
"user#odata.bind": "https://graph.microsoft.com/v1.0/users($personId)"
},
{
"#odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": ["owner"],
"user#odata.bind":
"https://graph.microsoft.com/v1.0/users($visitedPersonId)"
}
]
};
return jsonEncode(data);
}
}
I've found my mistake. I post here in case someone gets the same error as me.
var headers = {
'Authorization': 'Bearer XXXXXXXXXXXXX',
'Content-Type': 'application/json'
};
var request = http.Request('POST', Uri.parse('https://graph.microsoft.com/v1.0/chats'));
request.body = '''{"chatType":"oneOnOne","members":[{"#odata.type":"microsoft.graph.aadUserConversationMember","roles":["owner"],"user#odata.bind":"https://graph.microsoft.com/v1.0/users(\'XX-XXX-XXXX-XXX\')"},{"#odata.type":"#microsoft.graph.aadUserConversationMember","roles":["owner"],"user#odata.bind":"https://graph.microsoft.com/v1.0/users(\'XX-XXX-XXXX-XXX\')"}]}''';
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
else {
print(response.reasonPhrase);
}
I've used another lib. Don't really know why it is working with this way and not with the other (see my question) ??
But anyway, this solves the problem!
I'm using Retrofit to make some requests to the API, and when I receive back the response it's usually received from the API in this format if the request is successful
Successful Response
{
"success": 1,
"error": [],
"data": [
// Some data..
]
}
And if there is an error, the response will go like this
Unsuccessful Response
{
"success": 0,
"error": [
"Password is incorrect"
],
"data": []
}
The problem now in case there is an unsuccessful request, it comes with error code 403, so Retrofit classifies it as an Exception and throws an HttpException, then i have no way to catch the password is incorrect message attached in the json response.
Is there any way I still can get the body response even if there is an HttpException?
Update
This is the sample code I'm using
ViewModel
viewModelScope.launch {
try {
val result = myApi.request(requestParam)
}catch (e: HttpException){
// Log the error
}
}
Well, I figured out a way to get back the response from the passed exception.
As I said in the question, this is the code I'm using
Old code sample
viewModelScope.launch {
try {
val result = myApi.request(requestParam)
}catch (e: HttpException){
// Log the error
}
}
However, I didn't know that the response body is passed with the exception, and you can receive it as a string using the errorBody() method as follows.
New code sample
viewModelScope.launch {
try {
val result = myApi.request(requestParam)
}catch (e: HttpException){
val response = e.response()?.errorBody()?.string()
}
}
And from there you can manipulate this string to extract the error message.
Take a look at the code below. This is server-side. I call the Google ReCaptcha API with bad secret key and bad user token response, as you can see. You know what? It works! More precisely: Google ReCaptcha API doesn't answer with exception (i.e.: my catch isn't reached). Why? This is not the expected behavior, right?
/**
* Verifies a Recaptcha filled by the user in his Android app.
* 1. Success: returns the JSON response
* 2. Failure: throws the error
**/
exports.verifyRecaptcha = functions.https.onCall((data, context) => {
const user_response_token = data.userResponseToken;
if(user_response_token === null || user_response_token === '') {
throw new functions.https.HttpsError('invalid-argument', 'The function must be called with an adequat user response token.');
}
const remote_url = 'https://recaptcha.google.com/recaptcha/api/siteverify';
const secret = '<MY_REAL_SECRET_KEY>'; // Original value: 'https://www.google.com/recaptcha/api/siteverify'; # Moises' value: https://recaptcha.google.com/recaptcha/api/siteverify
var options = {
method: 'POST',
uri: remote_url,
body: {secret: 'Foo', response: 'Bar'},
// body: {secret: secret, response: user_response_token},
json: true
};
return rp(options)
.then(parsedBody => {
return {code: 'Success', message: 'You are actually a human (this msg is for test purposes).'};
})
.catch(error => {
throw new functions.https.HttpsError('unknown', error);
});
});
And below is the Android app code:
final SafetyNetApi.RecaptchaTokenResponse response = task.getResult();
assert response != null;
final String userResponseToken = response.getTokenResult();
if (!userResponseToken.isEmpty()) {
final HashMap<String, String> the_data = new HashMap<>();
the_data.put("userResponseToken", userResponseToken);
FirebaseFunctions.getInstance()
.getHttpsCallable("verifyRecaptcha")
.call(the_data)
.continueWith(new Continuation<HttpsCallableResult, Void>() {
#Override
public Void then(#NonNull final Task<HttpsCallableResult> task) {
if(context.isDestroyed() || context.isFinishing()) {
return null;
}
if(!task.isSuccessful()) {
Exception e = task.getException();
if (e instanceof FirebaseFunctionsException) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
System.out.println(ffe.getMessage());
}
return null;
}
callback.onAsking();
return null;
}
});
} else {
callback.onFailureUserResponseTokenIsEmpty();
}
The docs suggest that errors such as invalid-input-secret/invalid-input-response will appear in the error-codes field of the response.
This information doesn't necessarily need to be translated into an HTTP error code (which would cause your catch block to execute); in this instance, Google apparently wanted to support multiple simultaneous error messages, and the HTTP response code pertains more to the conduct of the protocol at the HTTP level.
While we're looking at the docs, I should point out that you probably want to refer to the success field before presuming that your user is a human.
I'm working on a React Native app. We recently made a change to an API call, where it can respond with 500 and an error message detailing the problem so it can be presented to the user. The API response looks like:
{
"error": ["Renter contact info for User 1 missing"]
}
On the client, we're using the standard fetch() method to asynchronously make our request, and resolving the Promise in order to pull the response object out. When I log the response after a call that should trigger a 500, the object looks like:
{type: "default", status: 500, ok: false, statusText: undefined, headers: Headers…}
Here's our internal request() method we use for all API calls:
export function request(endpoint:string, parameters:Object, method:string = HTTP.get, timeout:number = 3000):Promise{
return new Promise(async (resolve, reject) => {
const payload = {
method,
headers: {
'Accept': CONTENT_TYPE,
'Content-Type': CONTENT_TYPE,
'Authorization': `Basic ${base64.encode(Config.API_TOKEN)}`,
'Auth-Token': await Agents.authToken,
},
body: JSON.stringify(parameters),
}
fetch(apiUrl(endpoint), payload)
.then(response => {
if(!response.ok) {
// ******************
// this is where the 500 error state is caught, but my response object doesn't contain the message sent from the server.
reject(response)
// ******************
}
return response
})
.then(resolve)
.catch(reject)
})
}
How can I ensure the response object contains the error message from the server so I can properly display it to my user?
fetch(apiUrl(endpoint), payload)
.then(response => {
if(!response.ok) {
response.json().then(function(data) {
console.log(data);// your error response
},function(error) {
//json error
});
reject(response)
// ******************
}
return response
})
response is a ReadableStream object. You need to use .json() to parse