I am getting the following error at run time I am doing an http call and getting json back.
"_TypeError (type 'List' is not a subtype of type '() => void')"
Here is my code
class _ForumPostsState extends State<ForumPosts> {
List data;
String categoryID = 'D64D0737-746D-4562-8C10-6445F4069A92';
Future<String> getPostsByCategory() async {
var response = await http.post(
Uri.encodeFull("http://api/ForumPostsByCategory"),
headers: {"Content-Type": "application/json",
'Accept': 'application/json',},
body: json.encode({'categoryID' : categoryID }));
this.setState(
data = json.decode(response.body)
);
print(data[1]["title"]);
return "Success!";
}
The error is thrown on this line
data = json.decode(response.body)
While debugging I noticed that the JSON was there it just errors on the data = json.decode call.
Change this:
this.setState(
data = json.decode(response.body)
);
To this:
this.setState(() {
data = json.decode(response.body)
}
);
More info here: https://docs.flutter.io/flutter/widgets/State/setState.html
Related
Currently I am working on my flutter app using Dio package as my networking and I want to create test on the dio post (wrapped within appclient). Here my code for
app_client.dart
abstract class AppClient{
Future<Map<String, dynamic>> get(String path, {Map<String, String>? queryParameters, Map<String, String>? headers});
Future<Map<String, dynamic>> post(String path, dynamic data, {Map<String, String>? queryParameters, Map<String, String>? headers});
}
class AppClientImpl implements AppClient{
late Dio dio;
late Interceptors interceptors;
AppClientImpl({required this.dio}){
//get language code
String languageCode = StorageUtil.getSavedLanguage();
if(languageCode == "id-ID"){
languageCode = "id_ID";
}else{
languageCode = "en_US";
}
BaseOptions baseOptions = BaseOptions(
baseUrl: ServiceUrl.baseUrl,
headers: {
"Accept" : "application/json",
"Content-Type" : "application/json",
},
queryParameters: {
"language" : languageCode,
"channel" : "mobile"
}
);
dio.options = baseOptions;
interceptors = Interceptors();
interceptors.add(LogInterceptor(request: true, requestBody: true, requestHeader: true, responseBody: true, responseHeader: true));
//COMMENT BECAUSE FAILED WHEN TESTING
dio.interceptors.addAll(interceptors); // ERROR HERE!!!!
}
#override
Future<Map<String, dynamic>> get(String path, {Map<String, String>? queryParameters, Map<String, String>? headers}) async {
// return await dio.get(path, queryParameters: queryParameters);
throw UnimplementedError();
}
Future<Map<String, dynamic>> post(String path, dynamic data, {Map<String, String>? queryParameters, Map<String, String>? headers}) async{
Response response = await dio.post(path, queryParameters: queryParameters, data: Map<String, dynamic>.from(data));
if(response.statusCode == 200){
return jsonDecode(response.data);
}else{
throw Exception();
}
}
}
and here is my test class
class MockDio extends Mock implements Dio{}
void main(){
late MockDio mockDio;
late AppClientImpl appClient;
setUp((){
mockDio = MockDio();
appClient = AppClientImpl(dio: mockDio);
});
final tResponse = jsonDecode(fixture("token/token_success.json"));
final tData = {};
group("post method", (){
test(
"should return data when status code is 200",
()async{
when(
() => mockDio.post(any(), queryParameters: any(named: "queryParameters"), data: any(named: "data"))
).thenAnswer(
(invocation) async => Response(requestOptions: RequestOptions(path: "/sample"), data: fixture("token/token_success.json"), statusCode: 200)
);
final result = await appClient.post("/sample", tData);
verify(() => mockDio.post(any(), queryParameters: any(named: "queryParameters"), data: any(named: "data"))).called(1);
expect(result, tResponse);
}
);
});
}
As you can see, I inject dio instance to my appclient class and add global configuration there including interceptors.
I think everything is ok until I get these error.
Testing started at 08.54 ...
package:dio/src/dio.dart 46:20 MockDio.interceptors
package:eazyconnect/data/network/app_client/app_client.dart 44:9 new AppClientImpl
test/data/network/app_client/app_client_test.dart 23:17 main.<fn>
type 'Null' is not a subtype of type 'Interceptors'
Why this is happen? Any help and suggestion would be great!
Thanks!
You need mock interceptors too. You need pass interceptors like parameters, for class http, you can see the list interceptors have setted on Dio instance dont no in DioMock, that's why the error are happening
How to get access token in SignalR package?
I get access token doing POST request and after that I get the access token. I have a model where I have parsed JSON and have token field.
Auth authFromJson(String str) => Auth.fromJson(json.decode(str));
String authToJson(Auth data) => json.encode(data.toJson());
class Auth {
Auth({
this.token,
this.user,
});
final String? token;
final User? user;
POST request to API to get accesss token which I got succesfully:
Future<Auth> getToken() async {
String _email = "admin";
String _password = "admin";
Map<String, String> headers = {
'Content-Type': 'application/json',
'accept': ' */*'
};
final body = {
'username': _email,
'password': _password,
};
var response = await http.post(
Uri.parse("http://******/login"),
headers: headers,
body: jsonEncode(body),
);
print(response.body);
print(response.statusCode);
var jsonResponse = jsonDecode(response.body);
return Auth.fromJson(jsonResponse);
}
What I have in print in my console:
"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA","user":{}}
After all this stuff I opened docs and found out how SignalR package handle token auth and did the same thing:
Future<List> fetchLists() async {
final httpConnectionOptions = HttpConnectionOptions(
accessTokenFactory: () => getToken().then((value) => value.token ?? ''),
);
final hubConnection = HubConnectionBuilder()
.withUrl('http://*****/hub',
options: httpConnectionOptions)
.build();
await hubConnection.start();
So after all of this I got this error [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: 302: Found
it means what I should add access token to each of requests and I do, but still get this error. How can i solve it or may be there is anoher way to add token in HubConnectionBuild?
There is parameter in accessTokenFactory which accept a function and have return type String so make a function which return token .
below attached code for your reference-
_hubConnection = HubConnectionBuilder()
.withUrl(chaturl,
options: HttpConnectionOptions(
headers: defaultHeaders,
accessTokenFactory: () async => await getToken() //define a function which return token
))
withAutomaticReconnect(retryDelays: [
20000,
]
).build();
//get token method
Future<dynamic> getToken() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
if (sharedPreferences.containsKey("token")) {
print(sharedPreferences.getString("token"));
return sharedPreferences.getString("token");
} else {
return null;
}
}
I am trying to upload an image in flutter using Dio package but its failing. I need to send an image in formdata.
API >> needs request body as imageUpload:image
Code for image upload
static Future uploadProfilePicToS3(File imageFile) async {
try {
FormData formData = new FormData.from(
{'imageUpload': new UploadFileInfo(imageFile, "profile_pic.jpg")});
var response =
await Dio().post(UPLOAD_PROFILE_PIC, data: {'imageUpload': formData});
print(response.statusCode);
} catch (error) {
throw (error);
}
}
Error >>>
E/flutter ( 4025): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)]
Unhandled Exception: DioError [DioErrorType.DEFAULT]: Converting
object to an encodable object failed: Instance of 'UploadFileInfo'#0
Let me know if there is any other way.
I used dio for post a file path with some other information in this way :
Dio dio = new Dio();
FormData formData = new FormData();
formData.add(
"apiKey",
"my_api_key",
);
formData.add(
"file",
"image_path",
);
Response response = await dio.post(
"https://localhost",
data: formData,
onSendProgress: (int sent, int total) {
// do something
},
).catchError((onError) {
throw Exception('something');
});
use this code
Future<ImageProperty> uploadImage(File imageFile, processfunction) async {
final StringBuffer url = new StringBuffer(BASE_URL + "/wp-json/wp/v2/media");
Dio dio = new Dio();
var token = await _getToken();
try {
FormData formData = FormData.fromMap(
{"file": await MultipartFile.fromFile(imageFile.path)},
);
print(url);
if (token != null) {
dio.options.headers["Authorization"] = "Bearer $token";
print(dio.options.headers);
}
var response = await dio.post(
url.toString(),
data: formData,
onSendProgress: processfunction,
);
print(response.data);
return Future.value(response.data);
} on DioError catch (e) {
print(e);
}
}
How to post below json array?
"LstUserOptions": [
{
"OptionID": "ca339e40-10cc-4459-b9ec-07f7df0f4c69"
}
]
i found the solution :
List<Map> carOptionJson = new List();
CarJson carJson = new CarJson("ca339e40-10cc-4459-b9ec-07f7df0f4c69");
carOptionJson.add(carJson.TojsonData());
var body = json.encode({
"LstUserOptions": carOptionJson
});
http.Response response = await http.post(
Uri.encodeFull(ConfigApi.SAVE),
body: body,
headers: {'Content-type': 'application/json'});
class CarJson {
String OptionID;
CarJson(this.OptionID);
Map<String, dynamic> TojsonData() {
var map = new Map<String, dynamic>();
map["OptionID"] = OptionID;
return map;
}
}
how to done this work with dio package i send whole my data with dio and now i want send a array of json with it , is correct this code if assume my json array is body
FormData formData = new FormData.from({
"cars": body
});
response = await dio.post("url", data:
formData);
I have this:
List<String> _filters = <String>[8, 11];
I pass this _filters into this endpoint:
this.api.setInterests(token, _filters)
.then((res) {
print(res);
});
which looks like this:
Future setInterests(String token, List<String> interests) {
return _netUtil.post(BASE_URL + "/setinterests", body: {
"token": token,
"interests": interests
}).then((dynamic res) {
return res;
});
}
Passing _filters always throws the error:
type 'List<String>' is not a subtype of type 'String' in type cast
I don't know what else dart wants from me.
I found the answer. I just added .toString() to the _filters List.
this.api.setInterests(token, _filters.toString())
.then((res) {
print(res);
});
You need to add json.encode(data) in body
Add these two header
'Content-type': 'application/json',
'Accept': 'application/json',
Create map of your data
final Map<String, dynamic> data = new Map<String, dynamic>();
data['token'] = token;
data['interests'] = interests;
Call api like this
http.post(url,<br>
body: json.encode(data),
headers: { 'Content-type': 'application/json',
'Accept': 'application/json'},
encoding: encoding)
.then((http.Response response) {
// print(response.toString());
}