How to fix errors on http put request on flutter - flutter

I'm trying to authenticate using the below code and unable to succeed. It looks like the json structure is incorrect.
I've tried to check the same on native android using kotlin and it works correctly.
below are the logs
flutter: {data: {email: nelloresec#xxx.com, password: xxx}}
flutter: "{\"errors\":[]}"
flutter: http://xxx.xxx.xx
flutter: Instance of 'Response'
flutter: 400
flutter: {errors: []}

The default content-type for a body of types String, List<int> or Map<String, String> is 'text/plain' and I guess you want 'application/json'
In addition you can directly pass in the user object to the body paramater (as toJson will be invoked automatically by the json.encode()-function).
Lastly, you don't need to use both await and .then(...), await will suffice:
void userLogin(String url, User user) async {
http.Response response = await http.put(
'$url/api/login',
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
},
body: json.encode(user),
);
if (response.statusCode == 200) {
print(url);
print(response.statusCode);
print(json.decode(response.body));
} else {
print(json.encode(response.body));
print(url);
print(response);
print(response.statusCode);
print(json.decode(response.body));
throw Exception("Error while fetching data");
}
}

Related

Flutter http - Invalid argument(s): Invalid request body when jsonEncode is used

Future<void> _sendData() async {
final url = Uri.https('websitename.tld', 'restricted/login');
try {
final response = await http.post(
url,
headers: {"Content-Type": "application/json"},
body: {
json.encode({
'username': 'UserName',
'userpass': 'UserPaZZw0rd',
})
},
);
} catch (err) {print(err);}
}
causes : flutter: Invalid argument(s): Invalid request body "{{"username":"UserName","userpass":"UserPaZZw0rd"}}".
if i make a call without json, code works like a charm.
jsonEncode instead of json.encode -> same result.
Any ideas?
Thanks!
Try this.
body: json.encode({
'username': 'UserName',
'userpass': 'UserPaZZw0rd',
}),

POST call works on Postman but not on Flutter

Future<String> loginUser(User user) async {
var body = jsonEncode({
'strlogin': user.email,
});
Response response = await post(SeguriSignAPIURL.loginUser,
headers: headers,
body: body);
if (response.statusCode == 200) {
var decode = jsonDecode(response.body);
return decode['token'];
} else {
print(response.reasonPhrase);
return '';
}
Hey! When I make this Post call on Postman I get a result, however when I run this code on flutter I get a 400 error. My headers:
final headers = {
'Content-Type': 'application/json; charset=UTF-8',
"Accept": "application/json",
};
Postman:
In Postman you do the request using form-data, but in your Flutter code, you pass json-encoded body.
You either need to use form-data in Flutter or update your server code to accept json content type.

Google Drive API: Uploading and creating folders with http requests, for example in DIO with Flutter

I'm trying to create a simple Flutter app which interacts with the Google Drive API.
Authentication works great via the Google Sign In package, so I have access to the correct headers and auth tokens.
What I don't understand however, despite trying different approaches and reading the Drive Documentation up and down - how can I interact with the API via http requests, for example via Dio or via the "standard" way in dart/flutter?
To state one example: I want to upload an an image the user picked. I have everything figured out (the file path, the auth token, etc.), but how does a http request look like?
Here is the "bare" http request:
Map headers = await user.currentUser.authHeaders;
var formData = FormData.fromMap({
'name': filePath,
'file': MultipartFile.fromBytes(fileData, filename: filePath)
});
var response = await Dio().post(
'https://www.googleapis.com/upload/drive/v3/files?uploadType=media',
data: formData,
options: Options(headers: headers));
print(response);
It's probably a very mundane/trivial question, but I just can't figure it out ..
Thanks in advance for your help!
Christian
You need to create the File first then upload the file data into it.
I'll using the http plugin and not DIO. But the same process should work for dio.
Step one: Create the file metadata in a folder
Future<String> createFile({File image, String folderId}) async {
String accessToken = await Prefs.getToken();
Map body = {
'name': 'name.jpg',
'description': 'Newly created file',
'mimeType': 'application/octet-stream',
'parents': ['$folderId']
};
var res = await http.post(
'https://www.googleapis.com/drive/v3/files',
headers: {
'Authorization': 'Bearer $accessToken',
'Content-Type': 'application/json; charset=UTF-8'
},
body: jsonEncode(body),
);
if (res.statusCode == 200) {
// Extract the ID of the file we just created so we
// can upload file data into it
String fileId = jsonDecode(res.body)['id'];
// Upload the content into the empty file
await uploadImageToFile(image, fileId);
// Get file (downloadable) link and use it for anything
String link = await getFileLink(fileId);
return link;
} else {
Map json = jsonDecode(res.body);
throw ('${json['error']['message']}');
}
}
Step two: Upload image data into empty file
Future uploadImageToFile(File image, String id) async {
String accessToken = await Prefs.getToken();
String mimeType = mime(basename(image.path).toLowerCase());
print(mimeType);
var res = await http.patch(
'https://www.googleapis.com/upload/drive/v3/files/$id?uploadType=media',
body: image.readAsBytesSync(),
headers: {
'Authorization': 'Bearer $accessToken',
'Content-Type': '$mimeType'
},
);
if (res.statusCode == 200) {
return res.body;
} else {
Map json = jsonDecode(res.body);
throw ('${json['error']['message']}');
}
}
Step three: Get downloadable file link(to store in database or use for anything)
Future getFileLink(String id) async {
String accessToken = await Prefs.getToken();
var res = await http.get(
'https://www.googleapis.com/drive/v3/files/$id?fields=webContentLink',
headers: {
'Authorization': 'Bearer $accessToken',
'Content-Type': 'application/json; charset=UTF-8'
},
);
if (res.statusCode == 200) {
Map json = jsonDecode(res.body);
String link = json['webContentLink'];
return link.split('&')[0];
} else {
Map json = jsonDecode(res.body);
throw ('${json['error']['message']}');
}
}

How can pass the request parameter as a formdata in dart or flutter

I have tried many formats to pass the request parameter in the flutter project but I'm getting API status code 415 and Unhandled Exception: FormatException: Unexpected end of input (at character 1).
I have added the postman image for the understanding of the form data.
For Flutter HTTP library it goes like this,
var headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
var request = http.Request('POST', Uri.parse(''));
request.bodyFields = {
'firstName': 'Keval',
'lastName': 'ebiz',
'email': 'al#gmail.com',
'phone': '1234'
};
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
else {
print(response.reasonPhrase);
}

Flutter Dio interceptor: DioError [DioErrorType.DEFAULT]: Bad state: Can‘t finalize a finalized MultipartFile

Hi i'm trying refreshtoken logic in Dio interceptor. it's working fine for json body params, but its throwing DioError [DioErrorType.DEFAULT]: Bad state: Can‘t finalize a finalized MultipartFile when i tried uploading images.
onError: (DioError error) async {
// Do something with response error
if (error.response?.statusCode == 401) {
// _dio.interceptors.requestLock.lock();
Response response;
RequestOptions options = error.response.request;
response = await _dio
.post('/user/refresh', data: {"refreshToken": _refreshToken});
if (response.statusCode == 200) {
final userData = json.encode(
{
'token': response.data["accessToken"],
'tokenType': _tokenType,
'refreshToken': response.data["refreshToken"]
},
);
prefs.setString('userData', userData);
options.data = formData;
}
options.headers["Authorization"] =
"$_tokenType ${response.data['accessToken']}";
return await _dio.request(options.path, options: options);
} else {
throw error;
}
I put together a workaround for this issue which basically consists of rebuilding the FormData before retrying. It feels a bit hacky but it works. I start by passing any info I need for the reconstruction in via the "extra" map in the request options so the interceptor has access to it. Here is some pseudo code:
//original request
dioResponse = await dio.post(
'http://my/api/endpoint',
data: myOriginalFormData,
options: Options(
headers: myHeaders,
extra: {'pathToMyFile': pathToMyFile},
),
);
//and in my interceptor I use it to construct a fresh FormData that has not been finalized
final FormData newFormData = FormData.fromMap({
'file': await MultipartFile.fromFile(
requestOptions.extra['pathToMyFile'],
contentType: MediaType('application/json', 'json')),
});
//retry with the fresh FormData
return dio.request(
requestOptions.path,
data: newFormData,
options: requestOptions,
cancelToken: requestOptions.cancelToken,
onReceiveProgress: requestOptions.onReceiveProgress,
onSendProgress: requestOptions.onSendProgress,
queryParameters: requestOptions.queryParameters,
);
Anyone have thoughts on this approach? Any major downsides?