How make a http post using form data in flutter? - http

I'm trying to do a http post request and I need to specify the body as form-data, because the server don't take the request as raw.
This is what I'm doing:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
postTest() async {
final uri = 'https://na57.salesforce.com/services/oauth2/token';
var requestBody = {
'grant_type':'password',
'client_id':'3MVG9dZJodJWITSviqdj3EnW.LrZ81MbuGBqgIxxxdD6u7Mru2NOEs8bHFoFyNw_nVKPhlF2EzDbNYI0rphQL',
'client_secret':'42E131F37E4E05313646E1ED1D3788D76192EBECA7486D15BDDB8408B9726B42',
'username':'example#mail.com.us',
'password':'ABC1234563Af88jesKxPLVirJRW8wXvj3D'
};
http.Response response = await http.post(
uri,
body: json.encode(requestBody),
);
print(response.body);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Container(
child: Center(
child: RaisedButton(
child: Text('Press Here'),
onPressed: (){
postTest();
},
),
),
),
);
}
}
This is the actual response:
{
"error": "unsupported_grant_type",
"error_description": "grant type not supported"
}
This is the expected response:
{
"access_token": "00D0b000000Bb08!AR8AQO.s8mAGXCbwV77FXNLQqc2vtl8g6_16miVbgWlQMsuNHsaf2IGLUwnMVXBOfAj19iznhqhwlPOi4tagvf7FFgiJJgoi",
"instance_url": "https://na57.salesforce.com",
"id": "https://login.salesforce.com/id/00D0b000000Bb08EAC/0050b000005nstiAAA",
"token_type": "Bearer",
"issued_at": "1567993324968",
"signature": "1+Zd/dSh9i7Moh2U0nFJLdXkVHqPlPVU6emwdYzXDPk="
}
You can test this on postman switching the body between raw (you get the actual response) and form-data (you get the expected response)
PS: The headers are temporary headers created by the client tool.

Use Map instead, because body in http package only has 3 types: String, List or Map. Try this:
final uri = 'https://na57.salesforce.com/services/oauth2/token';
var map = new Map<String, dynamic>();
map['grant_type'] = 'password';
map['client_id'] = '3MVG9dZJodJWITSviqdj3EnW.LrZ81MbuGBqgIxxxdD6u7Mru2NOEs8bHFoFyNw_nVKPhlF2EzDbNYI0rphQL';
map['client_secret'] = '42E131F37E4E05313646E1ED1D3788D76192EBECA7486D15BDDB8408B9726B42';
map['username'] = 'example#mail.com.us';
map['password'] = 'ABC1234563Af88jesKxPLVirJRW8wXvj3D';
http.Response response = await http.post(
uri,
body: map,
);

There is a dart package dio
it works like a charm, am using it as a standard to do http requests.
Please read the docs too on sending form data with dio package
import 'package:dio/dio.dart';
postData(Map<String, dynamic> body)async{
var dio = Dio();
try {
FormData formData = new FormData.fromMap(body);
var response = await dio.post(url, data: formData);
return response.data;
} catch (e) {
print(e);
}
}

Use MultipartRequest class
A multipart/form-data request automatically sets the Content-Type header to multipart/form-data.
This value will override any value set by the user.
refer pub.dev doc here
For example:
Map<String, String> requestBody = <String,String>{
'field1':value1
};
Map<String, String> headers= <String,String>{
'Authorization':'Basic ${base64Encode(utf8.encode('user:password'))}'
};
var uri = Uri.parse('http://localhost.com');
var request = http.MultipartRequest('POST', uri)
..headers.addAll(headers) //if u have headers, basic auth, token bearer... Else remove line
..fields.addAll(requestBody);
var response = await request.send();
final respStr = await response.stream.bytesToString();
return jsonDecode(respStr);
Hope this helps

So, you wanna send the body as form-data right? maybe you can try this? for me it's work
postTest() async {
final uri = 'https://na57.salesforce.com/services/oauth2/token';
var requestBody = {
'grant_type':'password',
'client_id':'3MVG9dZJodJWITSviqdj3EnW.LrZ81MbuGBqgIxxxdD6u7Mru2NOEs8bHFoFyNw_nVKPhlF2EzDbNYI0rphQL',
'client_secret':'42E131F37E4E05313646E1ED1D3788D76192EBECA7486D15BDDB8408B9726B42',
'username':'example#mail.com.us',
'password':'ABC1234563Af88jesKxPLVirJRW8wXvj3D'
};
http.Response response = await http.post(
uri,
body: requestBody,
);
print(response.body);
}
Or
postTest() async {
final uri = 'https://na57.salesforce.com/services/oauth2/token';
http.Response response = await http.post(
uri, body: {
'grant_type':'password',
'client_id':'3MVG9dZJodJWITSviqdj3EnW.LrZ81MbuGBqgIxxxdD6u7Mru2NOEs8bHFoFyNw_nVKPhlF2EzDbNYI0rphQL',
'client_secret':'42E131F37E4E05313646E1ED1D3788D76192EBECA7486D15BDDB8408B9726B42',
'username':'example#mail.com.us',
'password':'ABC1234563Af88jesKxPLVirJRW8wXvj3D'
});
print(response.body);
}

Edit 1 (this worked for code login flow):
String url = "https://login.salesforce.com/services/oauth2/token";
http.post(url, body: {
"grant_type": "authorization_code",
"client_id": "some_client_id",
"redirect_uri": "some_redirect_uri",
"code": "some_code_generated_by_salesforce_login",
"client_secret": "some_client_secret",
}).then((response) {
//--handle response
});
give 'FormData' a try from:
import 'package:dio/dio.dart';
FormData formData = new FormData.fromMap(dataMap);
retrofitClient.getToken(formData).then((response){//--handle respnse--});
'retrofitClient' is from package
retrofit: ^1.0.1+1

Can you try this;
String url = 'https://myendpoint.com';
Map<String, String> headers = {
"Content-Type": "application/x-www-form-urlencoded"
"Content-type": "application/json"};
String json = '{"grant_type":"password",
"username":"myuser#mail.com",
"password":"123456"}';
// make POST request
Response response = await post(url, headers: headers, body: json);
// check the status code for the result
int statusCode = response.statusCode;
// this API passes back the id of the new item added to the body
String body = response.body;

This is my example with form data function
Future<ResponseModel> postWithFormData(String url, List<File> files,
{Map<String, String> body = const {}, bool throwAlert = false}) async {
var request = http.MultipartRequest("POST", Uri.parse(localApiHost + url));
request.headers
.addAll({"Authorization": "Bearer ${Storage.getString(token)}"});
request.fields.addAll(body);
for (var file in files) {
request.files.add(await http.MultipartFile.fromPath("files", file.path));
}
var sendRequest = await request.send();
var response = await http.Response.fromStream(sendRequest);
final responseData = json.decode(response.body);
if (response.statusCode >= 400 && throwAlert) {
showErrorDialog(responseData["message"]);
}
return ResponseModel(body: responseData, statusCode: response.statusCode);
}

HTTP does not support form-data yet!
Use DIO instead. It will handle everything on its own!

This code snippets successfully executes a POST api call which expect an authorization token and form-data.
final headers = {'Authorization': 'Bearer $authToken'};
var requestBody = {
'shopId': '5',
'fromDate': '01/01/2021',
'toDate': '01/10/2022',
};
final response = await http.post(
Uri.parse(
'https://api.sample.com/mobile/dashboard/getdetails'),
headers: headers,
body: requestBody,
);
print("RESPONSE ${response.body}");

Using POSTMAN to test the query and get the format is quite useful. This is allow you to see if you really need to set Headers. See my example below. I hope it helps and it is not too much
import 'dart:convert';
import 'package:http/http.dart';
class RegisterUser{
String fullname;
String phonenumber;
String emailaddress;
String password;
Map data;
RegisterUser({this.fullname, this.phonenumber, this.emailaddress, this.password});
Future<void> registeruseraction() async {
String url = 'https://api.url.com/';
Response response = await post(url, body: {
'fullname' : fullname,
'phonenumber' : phonenumber,
'emailaddress' : emailaddress,
'password' : password
});
print(response.body);
data = jsonDecode(response.body);
}
}

You can also use MultiPartRequest, it will work for sure
var request = new
http.MultipartRequest("POST",Uri.parse("$baseUrl/example/"));
request.headers.addAll(baseHeader);
request.fields['id'] = params.id.toString();
request.fields['regionId'] = params.regionId.toString();
request.fields['districtId'] = params.districtId.toString();
http.Response response = await http.Response.fromStream(await
request.send());
print('Uploaded! ${response.body} ++ ${response.statusCode}');

import 'package:http/http.dart' as http;
// Function to make the POST request
Future<http.Response> post(String url, Map<String, String> body) async {
// Encode the body of the request as JSON
var encodedBody = json.encode(body);
// Make the POST request
var response = await http.post(url,
headers: {"Content-Type": "application/json"}, body: encodedBody);
// Return the response
return response;
}

Related

How to read Http response from flutter?

I'm trying to read reponse from HTTP in flutter but I didnt read.
I posted the request. Can anyone know, what is wrong ?
final http.Client client;
Future<http.Response> post(
Uri uri, {
Map<String, dynamic> postParams,
String accessToken,
}) async {
log.info(uri.toString());
log.info('postParams: ${postParams?.toString()}');
///Encode map to bytes
String jsonString = json.encode(postParams);
List<int> bodyBytes = utf8.encode(jsonString);
Map headers = {
HttpHeaders.contentTypeHeader: 'application/json; charset=utf-8',
};
final response = await client
.post(
uri,
body: bodyBytes,
headers: headers,
)
.timeout(Duration(seconds: 120));
}
You can achieve this functionality as follow
1.install http package and import it as follow
import 'package:http/http.dart' as http;
Create an instance of http or http.Client as you did
final http.Client _client = http.Client();
Send the request to server as follow
var url = 'https://example.com/store/.....';
final Map<String, dynamic> data= {"name":"John Doe", "email":"johndoe#email.com"};
final Map<String, String> _headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
var response = await _client.post(url, body:data, headers:_headers);
Then you can read the response as
if(response.statusCode == 200) {
var decoded = json.decode(response.body);
print(decoded);
// The Rest of code
}

How to set Timeout for MultiPart Request in Dart?

Here is my MultiPartRequest code
var request =
http.MultipartRequest("POST", Uri.parse(EMPLOYEE_PUNCH_IN_URL));
request.fields['uid'] = userId;
request.fields['location'] = location;
request.fields['punchin_time'] = punchInTime;
request.fields['punchin_location_name'] = address;
var multiPartFile = await http.MultipartFile.fromPath(
"photo", imageFile.path,
contentType: MediaType("image", "$extension"));
request.files.add(multiPartFile);
http.StreamedResponse response = await request.send();
var responseByteArray = await response.stream.toBytes();
employeePunchInModel = standardSerializers.deserializeWith(
EmployeePunchInModel.serializer,
json.decode(utf8.decode(responseByteArray)));
......
I know how to set timeout to a normal http request. I have followed this link
Set timeout for HTTPClient get() request
I have tried adding timeout function in following ways but it won't work and my request gets completed
1.
var multiPartFile = await http.MultipartFile.fromPath(
"photo", imageFile.path,
contentType: MediaType("image", "$extension")).timeout(const Duration(seconds: 1));
2.
http.StreamedResponse response = await request.send().timeout(const Duration(seconds: 1));
3.
var responseByteArray = await response.stream.toBytes().timeout(const Duration(seconds: 15));
But none of the above timeout works.
Using http package, this is my approach :
Create a Streamed Response that we're going to use for onTimeOut callback
StreamedResponse timeOutResponse({
#required String httpMethod,
#required dynamic error,
#required String url,
}) {
Map<String, dynamic> body = {
'any': 'value',
'you': 'want for $error',
};
int statusCode = 404;
Uri destination = Uri.parse(url);
String json = jsonEncode(body);
return StreamedResponse(
Stream.value(json.codeUnits),
statusCode,
request: Request(httpMethod, destination),
);
}
Use the modified http multipart function from Mahesh Jamdade answer
Future<http.Response> makeAnyHttpRequest(String url,
Map<String, dynamic> body,
{Function onTimeout,
Duration duration = const Duration(seconds: 10)}) async {
final request = http.MultipartRequest(
'POST',
Uri.parse('$url'),
);
final res = await request.send().timeout(
duration,
onTimeout: () {
return timeOutResponse(
httpMethod: 'MULTIPART POST',
error: 'Request Time Out',
url: url,
);
},
);
return await http.Response.fromStream(res);
}
this way, instead of timeout exception, you can return the onTimeOut Http Response.
Use Dio package with following code:
try {
final response = await Dio().post(requestFinal.item1, data:formData, options: option,
onSendProgress: (sent, total) {
print("uploadFile ${sent / total}");
});
print("Response Status code:: ${response.statusCode}");
if (response.statusCode >= 200 && response.statusCode < 299) {
dynamic jsonResponse = response.data;
print("response body :: $jsonResponse");
final message = jsonResponse["msg"] ?? '';
final status = jsonResponse["status"] ?? 400;
final data = jsonResponse["data"];
return HttpResponse(status: status, errMessage: message, json: data);
}
else {
dynamic jsonResponse = response.data;
print('*********************************************************');
print("response body :: $jsonResponse");
print('*********************************************************');
var errMessage = jsonResponse["msg"];
return HttpResponse(status: response.statusCode, errMessage: errMessage, json: jsonResponse);
}
}
on DioError catch(error) {
print('*********************************************************');
print('Error Details :: ${error.message}');
print('*********************************************************');
dynamic jsonResponse = error.response.data;
print('*********************************************************');
print("response body :: $jsonResponse");
print('*********************************************************');
var errMessage = jsonResponse["message"] ?? "Something went wrong";
return HttpResponse(status: jsonResponse["status"] , errMessage: errMessage, json: null);
}
Hope this helps!
I suggest that
var request = http.MultipartRequest("POST", Uri.parse(EMPLOYEE_PUNCH_IN_URL));
request.fields['uid'] = userId;
request.fields['location'] = location;
request.fields['punchin_time'] = punchInTime;
request.fields['punchin_location_name'] = address;
var multiPartFile = await http.MultipartFile.fromPath(
"photo", imageFile.path,
contentType: MediaType("image", "$extension"));
request.files.add(multiPartFile);
await request.send().timeout(Duration(seconds: 1), onTimeout: () {
throw "TimeOut";
}).then((onValue) {
var responseByteArray = await onValue.stream.toBytes();
employeePunchInModel = standardSerializers.deserializeWith(
EmployeePunchInModel.serializer,
json.decode(utf8.decode(responseByteArray)));
}).catchError((){ throw "TimeOut";});
hey you can also use dio 3.0.4
A powerful Http client for Dart, which supports Interceptors, Global configuration, FormData, Request Cancellation, File downloading, Timeout etc.
Here is the link :Http client for Dart
You can try this which uses http package
declare your multipart function like this with your desired arguments
Future<http.Response> makeAnyHttpRequest(String url,
Map<String, dynamic> body,
{Function onTimeout,
Duration duration = const Duration(seconds: 10)}) async {
final request = http.MultipartRequest(
'POST',
Uri.parse('$url'),
);
final res = await request.send().timeout(duration, onTimeout: onTimeout);
return await http.Response.fromStream(res);
}
and then call it within a try catch block and you can catch the timeout exception by throwing the desired value on Timeout.
try{
final res = makeAnyHttpRequest("<url>",{"body":"here"},onTimeout:(){
throw 'TIME_OUT'; // Throw anything
});
}catch(_){
if (_.toString() == 'TIME_OUT') { // catch the thrown value to detect TIMEOUT
/// DO SOMETHING ON TIMEOUT
debugPrint('The request Timeout');
}
}
}
The above approach would work for any http request as long as you have a onTimeout call back

Flutter : Edit profile returns 401 'Unauthenticated' but works in POSTMAN

i was trying to edit my user's profile with flutter and laravel based on this tutorial . My register and login works fine. However, when i try to edit it always return this error.
Here are some of my codes;
api.dart
class CallApi {
final String _url = 'http://10.0.2.2:8000/api/';
var token ;
postData(data, apiUrl) async {
var fullUrl = _url + apiUrl + await _getToken();
print(fullUrl);
return await http.post(
fullUrl,
body: jsonEncode(data),
headers: _setHeaders());
}
editData(data, apiUrl) async {
var fullUrl = _url + apiUrl + await _getToken();
return await http.post(
fullUrl,
body: jsonEncode(data),
headers: _setTokenHeaders())
.then((response) {
print('Response status : ${response.statusCode}');
print('Response body : ${response.body}');
});
}
getData(apiUrl) async {
var fullUrl = _url + apiUrl + await _getToken();
return await http.get(fullUrl, headers: _setHeaders());
}
_setHeaders() => {
'Content-type': 'application/json',
'Accept': 'application/json',
};
_getToken() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var token = localStorage.getString('token');
return '?token=$token';
}
_setTokenHeaders() =>
{
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $_getToken()',
};
}
Handle update function
void _handleUpdate() async {
setState(() {
_isLoading = true;
});
var data = {
'residency': locationController.text,
'spouse': spouseController.text,
'occupation': occupationController.text,
};
var res = await CallApi().postData(data, 'profile');
// i've tried both postData and editData which returns the same error
var body = json.decode(res.body);
print(body);
/*if (body['status'] == true) {
SharedPreferences localStorage = await SharedPreferences.getInstance();
localStorage.setString('user_details', json.encode(body['token']));
Navigator.of(context).pushNamed(Profile.tag);
}*/
}
Logcat
I/flutter ( 2390): {message: Unauthenticated.}
The api works properly through postman and i have checked the url and parameters which i am entering in the post request and they are the same as that of postman but still i keep getting the error.
Whats working on POSTMAN
Register
Login
Logout
Update
On flutter App
Register
Login
You should only return the token only. No need to return string query.
_getToken() async {
...
return token;
};
Also, remove the _getToken() from your fullUrl variable. You need to send the token by headers, not by query parameters.
EDITED
Your postData() function should be using _setTokenHeaders() in the headers instead.

Flutter http headers

The post request is throwing an error while setting the header map.
Here is my code
Future<GenericResponse> makePostCall(
GenericRequest genericRequest) {String URL = "$BASE_URL/api/";
Map data = {
"name": "name",
"email": "email",
"mobile": "mobile",
"transportationRequired": false,
"userId": 5,
};
Map userHeader = {"Content-type": "application/json", "Accept": "application/json"};
return _netUtil.post(URL, body: data, headers:userHeader).then((dynamic res) {
print(res);
if (res["code"] != 200) throw new Exception(res["message"][0]);
return GenericResponse.fromJson(res);
});
}
but I'm getting this exception with headers.
══╡ EXCEPTION CAUGHT BY GESTURE ╞═
flutter: The following assertion was thrown while handling a gesture:
flutter: type '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'Map<String, String>'
flutter:
flutter: Either the assertion indicates an error in the framework itself, or we should provide substantially
flutter: more information in this error message to help you determine and fix the underlying cause.
flutter: In either case, please report this assertion by filing a bug on GitHub:
flutter: https://github.com/flutter/flutter/issues/new?template=BUG.md
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0 NetworkUtil.post1 (package:saranam/network/network_util.dart:50:41)
flutter: #1 RestDatasource.bookPandit (package:saranam/network/rest_data_source.dart:204:21)
Anybody facing this issue? I didn't find any clue with the above log.
Try
Map<String, String> requestHeaders = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': '<Your token>'
};
You can try this:
Map<String, String> get headers => {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer $_token",
};
and then along with your http request for header just pass header as header
example:
Future<AvatarResponse> getAvatar() async {
var url = "$urlPrefix/api/v1/a/me/avatar";
print("fetching $url");
var response = await http.get(url, headers: headers);
if (response.statusCode != 200) {
throw Exception(
"Request to $url failed with status ${response.statusCode}: ${response.body}");
}
var avatar = AvatarResponse()
..mergeFromProto3Json(json.decode(response.body),
ignoreUnknownFields: true);
print(avatar);
return avatar;
}
I have done it this way passing a private key within the headers. This will also answer #Jaward:
class URLS {
static const String BASE_URL = 'https://location.to.your/api';
static const String USERNAME = 'myusername';
static const String PASSWORD = 'mypassword';
}
In the same .dart file:
class ApiService {
Future<UserInfo> getUserInfo() async {
var headers = {
'pk': 'here_a_private_key',
'authorization': 'Basic ' +
base64Encode(utf8.encode('${URLS.USERNAME}:${URLS.PASSWORD}')),
"Accept": "application/json"
};
final response = await http.get('${URLS.BASE_URL}/UserInfo/v1/GetUserInfo',
headers: headers);
if (response.statusCode == 200) {
final jsonResponse = json.decode(response.body);
return new UserInfo.fromJson(jsonResponse);
} else {
throw Exception('Failed to load data!');
}
}
}
Try this
Future<String> createPost(String url, Map newPost) async {
String collection;
try{
Map<String, String> headers = {"Content-type": "application/json"};
Response response =
await post(url, headers: headers, body: json.encode(newPost));
String responsebody = response.body;
final int statusCode = response.statusCode;
if (statusCode == 200 || statusCode == 201) {
final jsonResponse = json.decode(responsebody);
collection = jsonResponse["token"];
}
return collection;
}
catch(e){
print("catch");
}
}
Future<String> loginApi(String url) async {
Map<String, String> header = new Map();
header["content-type"] = "application/x-www-form-urlencoded";
header["token"] = "token from device";
try {
final response = await http.post("$url",body:{
"email":"test#test.com",
"password":"3efeyrett"
},headers: header);
Map<String,dynamic> output = jsonDecode(response.body);
if (output["status"] == 200) {
return "success";
}else{
return "error";
} catch (e) {
print("catch--------$e");
return "error";
}
return "";
}
void getApi() async {
SharedPreferences prefsss = await SharedPreferences.getInstance();
String tokennn = prefsss.get("k_token");
String url = 'http://yourhost.com/services/Default/Places/List';
Map<String, String> mainheader = {
"Content-type": "application/json",
"Cookie": tokennn
};
String requestBody =
'{"Take":100,"IncludeColumns":["Id","Name","Address","PhoneNumber","WebSite","Username","ImagePath","ServiceName","ZoneID","GalleryImages","Distance","ServiceTypeID"],"EqualityFilter":{"ServiceID":${_radioValue2 != null ? _radioValue2 : '""'},"ZoneID":"","Latitude":"${fav_lat != null ? fav_lat : 0.0}","Longitude":"${fav_long != null ? fav_long : 0.0}","SearchDistance":"${distanceZone}"},"ContainsText":"${_txtSearch}"}';
Response response = await post(url , headers: mainheader ,body:requestBody);
String parsedata = response.body;
var data = jsonDecode(parsedata);
var getval = data['Entities'] as List;
setState(() {
list = getval.map<Entities>((json) => Entities.fromJson(json)).toList();
});
}

Why dio posts empty form data?

I have a function to upload an image but the server does not receive anything and I get 500 status code. I'm sure that the server is fine. It works when I send a post request from the postman!
This is my function:
uploadPrescriptionToAll(File file, data) async {
String convertedFilePath = await convertImage(file);
String token = await getToken();
Response response;
Dio dio = Dio();
dio.options.baseUrl = "http://x.x.x.x:x";
FormData formData = FormData.from({
"image":
UploadFileInfo(new File(convertedFilePath), "image.jpg"),
"data": data,
});
try {
response = await dio.post("/api/images",
data: formData,
options: Options(headers: {
"Authorization": token,
"Content-Type": "multipart/form-data"
}));
} catch (e) {
print("Error Upload: " + e.toString());
}
print("Response Upload:" + response.toString());
}
how can I post the file (form-data) correctly? Is there another way to do it?
Using Dio It's very simple by using : FormData.fromMap()
searchCityByName(String city) async {
Dio dio = new Dio();
var a = {"city": city};
var res = await dio.post(apiSearchState, data:FormData.fromMap(a));
}
In short, you should pass a Map<String, dynamic> object to dio.post()'s data field. For example:
response = await dio.post("/api/images",
data: {"image": "image.jpg", "data": data});
See: https://github.com/flutterchina/dio/issues/88 for details

Resources