Can not initialize jsonResponse in Flutter project - json

In my project I get my json string which later on i tried to assign to it a jsonResponse variable but I got an error like : The argument type 'Response' can't be assigned to the parameter type 'String'.
Here's my code:
Future getMahalle() async {
BaseOptions options = new BaseOptions(
baseUrl: globals.PROD_URL,
connectTimeout: 5000,
receiveTimeout: 3000,
);
Dio dio = new Dio(options);
dio.options.headers["Authorization"] = "Bearer ${globals.USER_TOKEN}";
try {
var response =
await dio.get(globals.SELECT_URL); //'api/hizlirapor/selects'
final jsonResponse = jsonDecode(response); //Here is the error line
MahalleModel mahalleList =
MahalleModel.fromJson(jsonDecode(response.data['mahalle']));
return mahalleList;
} on DioError catch (e) {
debugPrint("ERRORR!!!!!!!!!!!!! ${e.error.toString()}");
return null;
}
}
I'm trying to implement this article for example and got stuck. Thanks for help!

You don't have to decode json returned since you are using dio, dio does that for you.
// if it's a single value than try this.
MahalleModel mahalleList = response.data.map<MahalleModel>((mahalle) => MahalleModel.fromJson(mahalle));
// if it's a list than try this.
List<MahalleModel> mahalleList = response.data['mahalle'].map<MahalleModel>((mahalle) => MahalleModel.fromJson(mahalle)).toList();

Related

Flutter/Dart Error - NoSuchMethodError (NoSuchMethodError: Class 'String' has no instance method 'map'

I receive an error that has something to do with JSON receiver inside Flutter/Dart.
Had to share in a docs file since the full json response is pretty long. It had like 15 columns error log
Detail Class
class Detail {
String kodkursus;
String namakursus;
String kursusdescription;
Detail(
{required this.kodkursus,
required this.namakursus,
required this.kursusdescription});
factory Detail.fromJson(Map<String, dynamic> json) {
return Detail(
kodkursus: json['crs_code'] as String,
namakursus: json['crs_title_bm'] as String,
kursusdescription: json['crs_description_bm'] as String,
);
}
}
Code
Future<dynamic> generateDetailList() async {
var url = 'http://10.0.2.2:81/login_testing/kursus_display.php';
var data = {'usr_id': widget.username2};
var response = await http.post(url, body: json.encode(data));
var list = json.decode(json.encode(response.body));
List<Detail> _detail =
list.map<Detail>((json) => Detail.fromJson(json)).toList();
detailDataSource = DetailDataSource(_detail);
return _detail;
}
Return (full error log)
NoSuchMethodError (NoSuchMethodError: Class 'String' has no instance method 'map'...
I fairly new to this Flutter/Dart but I got the feeling it had something to do with the json, it just I cant get my head over it
Please check your API response because this error generates when there are difference in datatype.
this error says your app response it in String and you are accessing this as map so please check your API response or
try to replace this :
var list = json.decode(json.encode(response.body));
with :
var list = json.decode(response.body);
because json.encode method encodes all list data and that values datatype is String so it gives error.
Replace your function generateDetailList as such:
Future<List<Detail>?> generateDetailList() async {
Uri url = Uri.parse('http://10.0.2.2:81/login_testing/kursus_display.php');
Map<String, String> data = {'usr_id': 'widget.username2'};
http.Response response = await http.post(url, body: json.encode(data));
// var list = json.decode(json.encode(response.body));
var responseMap = await jsonDecode(response.body);
if (response.statusCode == 200) {
List<Detail> _details =
responseMap.map<Detail>((x) => Detail.fromJson(x)).toList();
return _details;
} else {
return null;
}
}
And try not to use var everywhere.

A common request method with decoder passed as parameter in Flutter using Dio

Not sure if what I'm trying to do is a foolish en-devour or ? In the app, I use rest API calls and I'm trying to implement API handling with Dio.
I have gone with an approach like so.
each API method has a generic function. ie: the POST method. goes like
Future<dynamic> postRequest({String? endPoint, dynamic decoder, data}) async {
// late String _fullURL = BaseOptions().baseUrl + endPoint!;
late int? _responseCode;
try {
final response = await _dio.post(
endPoint!, // APIEndpoints.postSignUp,
data: data, //jsonEncode(data),
);
//
// final String _responseString = response.data;
_responseCode = response.statusCode;
//
if (_responseCode == 200) {
final String _responseString = response.data;
final res = decoder(_responseString);
log("post success response ------------ ${res.toString()}");
return SuccessHandler().checkSuccess(res);
} else if (_responseCode == 201) {
log("post success no response ------------ ");
return HTTPResponse<dynamic>(
false,
null,
message: 'empty success',
code: _responseCode!,
//'Something went wrong! Please try again in a moment!',
);
} else {
log("post failed response ------------ ");
return null;
// return ErrorHandler().checkError(_responseCode, _responseString);
}
} on DioError catch (e) {
// print(e.message);
// throw Exception(e.message);
log("exception ------------ ${e.message}");
return HTTPResponse<dynamic>(
false,
null,
message: 'error: ${e.message}',
code: e.response!.statusCode!,
//'Something went wrong! Please try again in a moment!',
);
}
}
Where I try to pass the decoder to get the JSON response read out from the API response. Using a generated class like this
ValidateEmailModel validateEmailModelFromJson(String str) =>
ValidateEmailModel.fromJson(json.decode(str));
String validateEmailModelToJson(ValidateEmailModel data) =>
json.encode(data.toJson());
class ValidateEmailModel {
ValidateEmailModel({
this.email,
this.type,
this.code,
this.expire,
this.createdTime,
});
String? email;
String? type;
String? code;
dynamic expire;
dynamic createdTime;
factory ValidateEmailModel.fromJson(Map<String, dynamic> json) =>
ValidateEmailModel(
email: json["email"],
type: json["type"],
code: json["code"],
expire: DateTime.parse(json["expire"].toString()),
createdTime: DateTime.parse(json["createdTime"].toString()),
);
Map<String, dynamic> toJson() => {
"email": email,
"type": type,
"code": code,
"expire": expire!.toIso8601String(),
"createdTime": createdTime!.toIso8601String(),
};
}
In my method calls. i give the function its paramters like so
res = await APIHandler.instance.postRequest(
endPoint: APIEndpoints.postValidateCode,
decoder: validateEmailModelFromJson,
data: {
"code": val,
"email": _email,
},
)
And await the response to be passed to another common method SuccessHandler() so I can get the data object/s
class SuccessHandler {
dynamic successObject;
SuccessHandler({this.successObject});
Future<dynamic> checkSuccess(dynamic response) async {
return SuccessHandler(successObject: response);
}
}
so far when I try to debug the code. I do get the response.data from the Dio response. but gives me
Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'
can I achieve what I need to and how can I update the code? Please help me with this or just I think I'm trying to reinvent the wheel here.
validateEmailModelFromJson what this function will do is take a string convert it into json and will parse it you data model but in you postRequest function you are already get a json response from api call so no need to pass a decoder to you function.
where you are returning SuccessHandler().checkSuccess(res); directly return the _responseString so it should be like this,
if (_responseCode == 200) {
final String _responseString = response.data;
log("post success response ------------
${_responseString}");
return SuccessHandler().checkSuccess(_responseString);
}
now try directly using ValidateEmailModel.fromJson on _responseString, you will get the data

How do I decode this response body?

I have this response body from a http push
"{"identifier":"00000000-0000-0000-0000-00000000000"}"
I'd like to get the 000000... part as string
that's the relevant part of my code
.
.. async {
await http
.post(Uri.encodeFull(mainURL + registrEndPoint + _stuff))
.then((res) {
if (res.statusCode == 202) {
Map _body = jsonDecode(res.body);
// I checked debugging, the respons boy is ok
String _id =_body['identifier'];
return _id;
}...
I believe I'm missing something in the 'mapping'
and I suspect the combo 'quote-curlyBraces-quote'
defeat my jsonDecode;
any suggestion?
thanks in advance
By looking at the dart:convert documentation, you’ll see that jsonDecode() returns a
Map<String, dynamic>, meaning that you do not know the types of the values until runtime.
Map<String, dynamic> body = jsonDecode(jsonString);
print('Howdy, ${body['identifier']}!');
I solved the problem adding this line
String _body = res.body;
as described below,
await http
.post(Uri.encodeFull(mainURL + registrEndPoint + _qr))
.then((res) {
if (res.statusCode == 202) {
String _body = res.body; //<--- HERE!
Map _json = jsonDecode(_body);
String _id = _json['identifier'];
return _id ;
});
Thank you all for the help!

Angular HttpClient - how to convert from Http: JSON.parse(JSON.stringify(data))._body)?

Using the Http module, this construction is used:
Http service:
let tokenUrl1 = this.apiUrl + 'login';
let headers1 = new Headers({'Content-Type': 'application/json'});
return this.http.post(tokenUrl1, JSON.stringify(model), {headers: headers1});
Call of the service:
this.loginService.sendCredential(this.model).subscribe(
data => {
// Next statement ... how to convert this for use in an HttpClint environment??
localStorage.setItem("token", JSON.parse(JSON.stringify(data))._body);
The nice HttpClient module parses the http content body with JSON returning an object. Nice!
How can the marked statement, "JSON.parse(JSON.stringify(data))._body)" be rewritten to fit nicely in the HttpClient environment?
You can manipulate the return type to string - that is sufficient for e.g. tokens:
let tokenUrl2 = this.apiUrl + 'users';
let getHeaders = new HttpHeaders({'Authorization':'Bearer '+token});
return this.httpClient.get(tokenUrl2, { observe: 'body', responseType: 'text', headers: getHeaders})
You can add observe in your header.
let tokenUrl1 = this.apiUrl + 'login';
let headers1 = new Headers({'Content-Type': 'application/json'});
return this.http.post(tokenUrl1, JSON.stringify(model), {
headers: headers1,
observe: 'response'
});
And
this.loginService.sendCredential(this.model).subscribe(
data => {
console.log(data.body);
You can use response as JSON object directly to get value like this.
this.loginService.sendCredential(this.model).subscribe(
data => {
let res = data.json();
let tokenValue = res['token']; // based on your json response...
localStorage.setItem("token", tokenValue);
}
And If you are using api-call with type then...(From Angular Doc)
showConfig() {
this.configService.getConfig()
.subscribe((data: Response) => {
// like data.xyz properties of 'Reponse' class
// here you can get values from Your 'Reponse' class directly instead of parsing as above.
});
}
Hope this helps.
Ask me if any query.

Unexpected token in JSON at position 0 - Angular2 - Spring API

My REST API which has been written in SpringBoot has following method for the purpose of uploading a photo.
#RequestMapping(method = RequestMethod.POST, value = "/save-photo")
public ResponseEntity<?> uploadPhoto(#RequestPart("file") MultipartFile file){
if (file.isEmpty()) {
System.out.println("Attached file is empty");
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage("Attached file is empty");
return new ResponseEntity<ErrorResponse>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
String returnPath = null;
try {
byte[] bytes = file.getBytes();
String saveDate = new SimpleDateFormat("yyMMddHHmmssSSS").format(new Date());
Path path = Paths.get(UPLOAD_FOLDER + saveDate + "___" + file.getOriginalFilename());
Files.write(path, bytes);
returnPath = String.valueOf(path);
} catch (IOException e) {
//e.printStackTrace();
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setMessage(e.getMessage());
return new ResponseEntity<ErrorResponse> (errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
System.out.println("Before returning, return path = "+returnPath);
return new ResponseEntity<String>(returnPath, HttpStatus.OK);
}
Following is the code I have written to call the above method.
savePhoto(photoToSave: File) {
let formData: FormData = new FormData();
formData.append("file", photoToSave);
let savedPath = this._http
.post(this._endpointUrl + "/save-photo", formData)
.map(
res => {
return res.json();
}
)
.catch(handleError);
return savedPath;
}
File uploading process is fine. But Angular2 gives me the following error.
Unexpected token F in JSON at position 0
Note that the F is the starting letter of the path the server returns.
Why this happens? I think the server response is not a JSON. But why? Usually RestControllers return JSON. All other controller methods in my server works fine.
How to resolve this?
Response Captured from Browser console
Header:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://localhost:3000
Content-Length:88
Content-Type:application/json;charset=UTF-8
Date:Fri, 26 May 2017 04:33:05 GMT
Vary:Origin
Response:
F:\Work\Images\170526100305388___2.jpg
EDIT
Screen shots from the brwoser
Response:
Posting as a answer the workaround I used to get over the issue. Hope it might help somebody.
What I did was instead of returning a String ResponseEntity, I created a JSON object which encapsulates the string I want to return and returned as the response.
JSONObject obj = new JSONObject();
obj.put("savedPath", returnPath);
return new ResponseEntity<>(obj, HttpStatus.OK);
In the front end, I just return the response.json()
let savedPath = this._http
.post(this._endpointUrl + "tender/save-new/save-photo", formData)
.map(
res => {
return res.json();
}
)
.catch(handleError);
Now in the controller class, I can access the saved path in following way.
this._tendersService.savePhoto(files[0])
.subscribe(res => {
console.log("saved path = " + res.savedPath);
}
);