CustomStringRequest customStringRequest = new CustomStringRequest(requestMethod.ordinal(), serverUrl,
result -> {
Log.d(TAG, "headers: " + result.headers);
Log.d(TAG, "response: " + result.response);
createTaskItem(result);
},
error -> {
Log.d(TAG, "error: " + error);
})
error is in JSON string, I tried to get error like this:
new String(error.networkResponse.data, "utf-8");
new String(error.networkResponse.data);
none of the above method works, i always get empty string, don't know why :(
as you can see bytes in picture, the error response is actually this:
{
"error": [
"Wrong Credentials!"
],
"email_exists": false
}
I am using:
implementation 'com.android.volley:volley:1.1.1'
You can convert your response to json object using GSON ,
val customPojo = CustomPojo()
val gson = Gson()
gson.toJson(myPojo)
CustomPojo should be your response model class.
oh, i was just evaluating error response in debug mode
new String(error.networkResponse.data, "UTF-8");
and it returns empty string in result.
I just tried to print error response and it worked!. Thanks.
Related
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.
Heres my code of Volley Fetching API Request How do i parse?
i wanted somethinf like : $response[0]
val sq = StringRequest(Request.Method.GET, url,
Response.Listener<String> { response ->
//print the response
Log.i("GoogleIO","Response is : $response")
}, Response.ErrorListener {
//Log the error
Log.i("GoogleIO","That din't work")
})
//Add the request to the RequestQueue
Volley.newRequestQueue(this).add(sq)
Lets suppose you have this json string in response
{
name: "John",
age: 31,
city: "New York"
}
you can parse this string like this
try {
JSONObject obj=new JSONObject(response);
String name=obj.getString("name");
int age=obj.getInt("age");
String city=obj.getString("city");
} catch (JSONException e) {
e.printStackTrace();
}
You can use Gson for that:
First put the dependency in your app level build.gradle file.
implementation 'com.google.code.gson:gson:2.8.6'
Then you can add this:
var gson = new Gson()
var st = gson.toJson(response)
Log.i("GoogleIO","Response is : $st")
So I made an api in laravel and it returns a response like this:
{
"message": "The given data was invalid.",
"errors": {
"email": [
"The email has already been taken."
],
"mobile": [
"The mobile has already been taken."
]
}
}
Can somebody show me how to get the specific values from errors?
You may create model representing your error json and use Gson to parse it. Here is some short example.
data class Errors(
val email: List<String>,
val phone: List<String>
)
data class YourErrorModel(
val message: String,
val errors: Errors
)
fun parseError(response: Response<*>): YourErrorModel? {
val errorBody = response.errorBody()?.string() ?: return null //No error body present
return Gson().fromJson(errorBody, YourErrorModel::class.java)
}
Also don't forget to handle nullable types in your response. And i suggest you to return just string, not array if that is exact error for field.
How about this :
JSONObject errorObject = yourJSONObject.optJSONObject("errors");
if (errorObject != null){
JSONArray emailMsgArray = errorObject.getJSONArray("email");
JSONArray mobileMsgArray = errorObject.getJSONArray("mobile");
String emailMsg= emailMsgArray.getString(0);
String mobileMsg= mobileMsgArray .getString(0);
}
From my research, there isn't much help translating Android code to Swift code. With some help, we were able to translate or convert some of the code but it's not quite finished. When I run the code, I get an error:
Response could not be serialized, input data was nil or zero length.
responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.inputDataNilOrZeroLength)
Android code needing converting to Swift code:
public static final MediaType MEDIA_TYPE = MediaType.parse("application/json");
ProgressDialog progress;
private void payoutRequest() {
progress = new ProgressDialog(this);
progress.setTitle("Processing your payout ...");
progress.setMessage("Please Wait .....");
progress.setCancelable(false);
progress.show();
// HTTP Request ....
final OkHttpClient client = new OkHttpClient();
// in json - we need variables for the hardcoded uid and Email
JSONObject postData = new JSONObject();
try {
postData.put("uid", FirebaseAuth.getInstance().getCurrentUser().getUid());
postData.put("email", mPayoutEmail.getText().toString());
} catch (JSONException e) {
e.printStackTrace();
}
// Request body ...
RequestBody body = RequestBody.create(MEDIA_TYPE, postData.toString());
// Build Request ...
final Request request = new Request.Builder()
.url("https://us-central1-myapp.cloudfunctions.net/payout")
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("cache-control", "no-cache")
.addHeader("Authorization", "Your Token")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// something went wrong right off the bat
progress.dismiss();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
// response successful ....
// refers to response.status('200') or ('500')
int responseCode = response.code();
if (response.isSuccessful()) {
switch(responseCode) {
case 200:
Snackbar.make(findViewById(R.id.layout),
"Payout Successful!", Snackbar.LENGTH_LONG)
.show();
break;
case 500:
Snackbar.make(findViewById(R.id.layout),
"Error: no payout available", Snackbar
.LENGTH_LONG).show();
break;
default:
Snackbar.make(findViewById(R.id.layout),
"Error: couldn't complete the transaction",
Snackbar.LENGTH_LONG).show();
break;
}
} else {
Snackbar.make(findViewById(R.id.layout),
"Error: couldn't complete the transaction",
Snackbar.LENGTH_LONG).show();
}
progress.dismiss();
}
});
}
Swift code used from the above Android code:
let url = "https://us-central1-myapp.cloudfunctions.net/payout"
let headers: HTTPHeaders = [
"Content-Type": "application/json",
"cache-control": "Your Token"]
Alamofire.request(url, method: .get, headers: headers).validate().responseJSON { (response) in
switch response.result {
case .success(let value):
// you fall here once you get 200 success code, because you use .validate() when you make call.
print(value)
// parse your JSON here.
let parameters : [String: Any] =
["uid": FIRAuth.auth()!.currentUser!.uid,
"email": self.paypalEmailText.text!]
let postData = try! JSONSerialization.data(withJSONObject: parameters, options: [])
case .failure(let error):
if response.response?.statusCode == 500 {
print("Error no payout available")
print(error.localizedDescription)
} else {
print("Error: couldn't complete the transaction")
print(error.localizedDescription)
}
}
}
How can I convert the Android code into the Swift code or discover what it is I am doing wrong? This code is used to post to the function I have created for Firebase.
Edit
With the help of supplied code in this post, I was able to come up with this code but it is still coming up with the same error:
===========Error===========
Error Code: 4
Error Messsage: Response could not be serialized, input data was nil or zero length.
response FAILURE: responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.inputDataNilOrZeroLength)
updated swift code
let url = "https://us-central1-myapp.cloudfunctions.net/payout"
let headers: HTTPHeaders = [
"Content-Type": "application/json",
"cache-control": "Your Token"]
let params : [String: Any] = [
"uid": FIRAuth.auth()!.currentUser!.uid,
"email": self.paypalEmailText.text!]
Alamofire.request(url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers).validate().responseJSON { (response) in
switch response.result {
case .success(let JSON):
print("Success with JSON: \(JSON)")
if (response.result.value as? [String:AnyObject]) != nil {
// Access your response here
print(response.result.value!)
}
break
case .failure(let error):
if response.response?.statusCode == 500 {
print("Error no payout available")
print(print("Request failed with error: \(error.localizedDescription)"))
} else {
print("Error: couldn't complete the transaction")
print("\n\n===========Error===========")
print("Error Code: \(error._code)")
print("Error Messsage: \(error.localizedDescription)")
}
}
print("response \(response)")
}
EDIT #2
I edited my method:
let url = "https://us-central1-myapp.cloudfunctions.net/payout"
let headers: HTTPHeaders = [
"cache-control": "no-cache",
"Authorization": "Your Token",
"Content-Type": "application/json"]
let parameters : [String: Any] = [
"uid": uid,
"email": self.paypalEmailText.text!
]
Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers).validate(statusCode: 200..<600).responseJSON { (response) in
print("Request: \(String(describing: response.request))") // original url request
print("Result: \(response.result)") // response serialization result
if response.response?.statusCode == 200 {
print("Success with JSON: \(String(describing: response.result.value))")
} else {
let error = (response.result.value as? [[String : AnyObject]])
print(error as Any)
}
print("response \(response)")
}
The response and print outs are:
Request: Optional(https://us-central1-myapp.cloudfunctions.net/payout)
Result: FAILURE
Success with JSON: nil
response FAILURE: responseSerializationFailed(reason: Alamofire.AFError.ResponseSerializationFailureReason.inputDataNilOrZeroLength)
Keep in mind, in my url, my app is not called "myapp" it is just there for protection.
I think there are two issues in the code:
In the Android code, you are setting the parameters uid and email in the request body, whereas in the Swift code, you are setting these parameters in the response body, which is wrong (because by the time you got the response, the request is already completed without the params).
If you want to set a body for the request, the HTTP method (the second parameter to Alamofire.request should be post instead of get.
What you need to do is set the parameters in the request body and set the HTTP method as post, as follows:
let parameters: [String: Any] =
["uid": FIRAuth.auth()!.currentUser!.uid,
"email": self.paypalEmailText.text!]
Alamofire.request(url, method:.post, parameters:parameters,
encoding: JSONEncoding.default, headers:headers)
Try it out and see if it works.
So I'd do it like this here:
let url = "https://us-central1-myapp.cloudfunctions.net/payout"
let headers: HTTPHeaders = [
"Content-Type": "application/json",
"cache-control": "Your Token"
]
Alamofire.request(url,
method: .get,
encoding: JSONEncoding.default,
headers: headers).responseJSON
{ response in
switch response.result {
case .success(let JSON):
print("Success with JSON: \(JSON)")
// parse your JSON here something like
if let json = response.result.value as? [String:AnyObject] {
// Access your response here
}
break
case .failure(let error):
print("Request failed with error: \(error)")
}
}
In the success part you should be able to access the JSON and are able to parse it. Can you comment how your reponse object looks like, then I'll comment how you parse it and access the correct elements. I can otherwise only guess.
I have an below array of objects to be passed in the service call.
[
{
"ParkingSpace": {
"sid": "WorldSensing.vhu6lom3sovk6ahpogebfewk5kqadvs4.5385fc250cf2497dfe5679d1"
}
},
{
"ParkingSpace": {
"sid": "WorldSensing.vhu6lom3sovk6ahpogebfewk5kqadvs4.5385ff2f0cf2497dfe567c0c"
}
},
{
"ParkingSpace": {
"sid": "WorldSensing.vhu6lom3sovk6ahpogebfewk5kqadvs4.5385fd700cf2e65ecf6330c6"
}
}, {
"ParkingSpace": {
"sid": "WorldSensing.vhu6lom3sovk6ahpogebfewk5kqadvs4.5385fefe0cf2497dfe567bee"
}
}, {
"ParkingSpace": {
"sid": "WorldSensing.vhu6lom3sovk6ahpogebfewk5kqadvs4.5385ff690cf2497dfe567c3f"
}
}, {
"ParkingSpace": {
"sid": "WorldSensing.vhu6lom3sovk6ahpogebfewk5kqadvs4.55e972d21170d0c2fd7d15b1"
}
}]
I am trying like below:
private String generateParkingspaceBody(final List<String> listOfsIds) {
//sids array
JSONArray sidsArray = new JSONArray();
for (String sId: listOfsIds) {
//creating sidObject and object
JSONObject sIdObject = new JSONObject();
JSONObject object = new JSONObject();
try {
sIdObject.put("sid", sId);
object.put("ParkingSpace",sIdObject);
sidsArray.put(object);
} catch (JSONException e) {
CPALog.e(TAG,e.getMessage());
}
}
return sidsArray.toString();
}
Sending this string into the service call like:
Response getNearByParkingSpaces(#Header("Authorization") String accessToken,
#Header("Content-Type") String contentType,
#Body String arrayOfSids);
But in request showing in the logact is :
"[{\"ParkingSpace\":{}},{\"ParkingSpace\":{}},{\"ParkingSpace\":{}},{\"ParkingSpace\":{}},{\"ParkingSpace\":{}},{\"ParkingSpace\":{}},{\"ParkingSpace\":{}},{\"ParkingSpace\":{}},{\"ParkingSpace\":{}},{\"ParkingSpace\":{}},{\"ParkingSpace\":{}},{\"ParkingSpace\":{}},{\"ParkingSpace\":{}}]"
Please help me, how to send this request?
Thanks in advance.
You don't need to convert your object to a JSONArray, Retrofit will do it automatically for you.
Simply change your API method declaration to:
#Headers({
"Content-type: application/json"
})
Response getNearByParkingSpaces(#Header("Authorization") String accessToken,
#Body List<String> arrayOfSids);
I encounter same issue solve this by adding this dependencies:
implementation 'com.squareup.retrofit2:converter-scalars:$version'
There are multiple existing Retrofit converters for various data formats. You can serialize and deserialize Java objects to JSON or XML or any other data format and vice versa. Within the available converters, you’ll also find a Retrofit Scalars Converter that does the job of parsing any Java primitive to be put within the request body. Conversion applies to both directions: requests and responses.
https://futurestud.io/tutorials/retrofit-2-how-to-send-plain-text-request-body
then you can use your generateParkingspaceBody as value to post.
generateParkingspaceBody.toString() as your request body