I have a project with Flutter. And I want to get data from API. In my other project, I don't have any problem. But in this project, I have a problem. When I debug the process, in HTTP response didn't have body from API.
In class AuthService to get the API.
Future<ResponseCheckNIP> checkNIP({String? nip}) async {
var url = '$baseUrl/check-nip-new/$nip';
var header = {
'Content-Type': 'application/json',
};
// var body = jsonEncode({'nip': nip});
var response = await http.get(Uri.parse(url), headers: header);
if (response.statusCode == 200) {
var data = jsonDecode(response.body);
ResponseCheckNIP responseCheckNIP = ResponseCheckNIP.fromJson(data);
return responseCheckNIP;
} else {
throw Exception('Get NIP Failed');
}
}
And when I debug it, I get this
as we see, there is no body in there. Am I did something wrong?
If you look closely, the data is actually in the response.bodyBytes.
And Since you cannot directly convert bytes to json with dart, convert bytes to String first then decode the String using jsonDecode.
Below is the modified code.
Future<ResponseCheckNIP> checkNIP({String? nip}) async {
var url = '$baseUrl/check-nip-new/$nip';
var header = {
'Content-Type': 'application/json',
};
var response = await http.get(Uri.parse(url), headers: header);
if (response.statusCode == 200) {
// Get body bytes from response
final bytes = response.bodyBytes;
// Convert bytes to String then decode
final data = jsonDecode(utf8.decode(bytes));
ResponseCheckNIP responseCheckNIP = ResponseCheckNIP.fromJson(data);
return responseCheckNIP;
} else {
throw Exception('Get NIP Failed');
}
}
Hope this helps.
Thank you.
Related
This is my code. The goal is to get the link with file id.
// body parameter
Map<String, dynamic> body = {'file_id': 123};
String jsonBody = json.encode(body);
// response request
var download_response = await http.post(
Uri.parse('https://api.opensubtitles.com/api/v1/download'),
headers: {
'Content-Type': 'application/json',
'Api-Key': 'yCTZwGASncUthpMkMkbQDjcUdrrM2r8v'
},
body: jsonBody,
);
// print
debugPrint(download_response.body.toString());
I think I should be getting a JSON data response which I'm getting properly with postman but in flutter I'm getting empty response.
Things I tried:
encoding the body with jsonencode
correct syntax formatting
writing the body in plain json string
var headers = {
'Api-Key': 'yCTZwGASncUthpMkMkbQDjcUdrrM2r8v',
'Content-Type': 'application/json'
};
var request = http.MultipartRequest('POST', Uri.parse('https://api.opensubtitles.com/api/v1/download'));
request.fields.addAll({
'file_id': '123'
});
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
else {
print(response.reasonPhrase);
}
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']}');
}
}
I know this question could be redundant, but I am trying to send a png file through a POST request to Microsoft Custom Vision in Flutter.
This is my code:
void _makeRequest (File file) async {
String url = "<url>";
Map<String, String> headers = {
"Content-Type": "application/octet-stream",
"Prediction-Key": "<key>",
};
var bytes = file.readAsBytesSync();
var response = await http.post(
url,
headers: headers,
body: bytes,
);
print(response.body);
print(response.statusCode);
}
And when I run this code I get this response:
{"code":"ErrorUnknown","message":"The request entity's media type 'appliction/octet-stream' is not supported for this resource."}
Based on your comment , I think you used the wrong endpoint/URL. Since you're sending image, you have to use the other prediction endpoint that looks like this:
"https://southcentralus.api.cognitive.microsoft.com/customvision/v3.0/Prediction/<Project ID>/classify/iterations/<Iteration number>/image
^ Note ../image
If still can't, please try below code snipper(works for me):
final bytes = file.readAsBytesSync();
var uri = Uri.parse(
"<Prediction endpoint>");
var request = new http.Request("POST", uri)
..headers['Prediction-Key'] = "<Prediction Key>"
..headers['Content-Type'] = "application/octet-stream"
..bodyBytes = bytes;
http.Response response = await http.Response.fromStream(await request.send());
print(request);
print("Result: ${response.statusCode}");
print(response.statusCode);
print(response.body);
Here is my post method , i can send anything with text format but i need to send a file.
if you can, modify just my code. that is easy for catch problem, thanks
getComp() async {
final Map<String, dynamic> jsondata = {
'employee_id':
'${ScopedModel.of<AppModel>(context, rebuildOnChange: true).employee_id}',
'receiver_id': '${recid.text}',
'subject': '${subject.text}',
'message_body': '${msgbody.text}',
'message_attachment':'${filePath}'
};
var jsonresponse = null;
var response = await http.post(
'example.com/compose',
headers: {
"Accept": "application/json"
},
body: jsondata,
);
if (response.statusCode == 200) {
jsonresponse = json.decode(response.body);
print(jsonresponse);
}else{
print('problem');
}
}
Here is my file path picker
getfile(){
filePath = FilePicker.getFilePath(type: FileType.ANY);
}
if you can, modify this code .
convert it to base64 first and insert it to the database. That's how I did it when we developed an app that pass a file to the database.
i solve my problem with dio, :(
if anyone face then use dio
uploadFile() async {
FormData formData = new FormData.fromMap({
'employee_id':
'546546',
'receiver_id': '${recid.text}',
'subject': '${subject.text}',
'message_body': '${msgbody.text}',
'message_attachment': filePath ==null? 'nothing': await
MultipartFile.fromFile("${filePath}",filename: "$filePath}"),
});
Response response = await Dio().post("example.com", data: formData);
print(response);
}
Very weird...
In order to post some JSON data to my server, I define the contentLength to the length of the JSON encoded data but I then receive an exception that says "Content size exceeds specified contentLength". Difference is 1 byte.
Here is the source code:
Future<Map> ajaxPost(String serviceName, Map data) async {
var responseBody = json.decode('{"data": "", "status": "NOK"}');
try {
var httpClient = new HttpClient();
var uri = mid.serverHttps ? new Uri.https(mid.serverUrl, _serverApi + serviceName)
: new Uri.http(mid.serverUrl, _serverApi + serviceName);
var request = await httpClient.postUrl(uri);
var body = json.encode(data);
request.headers
..add('X-mobile-uuid', await _getDeviceIdentity())
..add('X-mobile-token', await mid.getMobileToken());
request.headers.contentLength = body.length;
request.headers.set('Content-Type', 'application/json; charset=utf-8');
request.write(body);
var response = await request.close();
if (response.statusCode == 200){
responseBody = json.decode(await response.transform(utf8.decoder).join());
//
// If we receive a new token, let's save it
//
if (responseBody["status"] == "TOKEN"){
await mid.setMobileToken(responseBody["data"]);
// Let's change the status to "OK", to make it easier to handle
responseBody["status"] = "OK";
}
}
} catch(e){
// An error was received
throw new Exception("AJAX ERROR");
}
return responseBody;
}
Some other times, it works fine...
Am I doing anything wrong with this code?
Many thanks for your help.
EDITED WITH SOLUTION:
Many thanks for your help. The simply fact of using utf8.encode(json.encode(data)) did not fully work. So, I turned to the http library and it now works like a charm. The code is even lighter!
Here is the new version of the code:
Future<Map> ajaxPut(String serviceName, Map data) async {
var responseBody = json.decode('{"data": "", "status": "NOK"}');
try {
var response = await http.put(mid.urlBase + '/$_serverApi$serviceName',
body: json.encode(data),
headers: {
'X-mobile-uuid': await _getDeviceIdentity(),
'X-mobile-token': await mid.getMobileToken(),
'Content-Type': 'application/json; charset=utf-8'
});
if (response.statusCode == 200) {
responseBody = json.decode(response.body);
//
// If we receive a new token, let's save it
//
if (responseBody["status"] == "TOKEN") {
await mid.setMobileToken(responseBody["data"]);
// Let's change the status to "OK", to make it easier to handle
responseBody["status"] = "OK";
}
}
} catch (e) {
// An error was received
throw new Exception("AJAX ERROR");
}
return responseBody;
}
I got it working with
req.headers.contentLength = utf8.encode(body).length;
From an indirect tip of the Utf8Codec documentation which states
decode(List codeUnits, { bool allowMalformed }) → String
Decodes the UTF-8 codeUnits (a list of unsigned 8-bit integers) to the corresponding string.
That means thatutf8.encode() returns codeUnits which actually means List<uint8>.
Encoding a String payload would in theory return a list which length is the length of the payload in bytes.
So using httpClient means to always measure the length of the payload in bytes, not the length of a String which may differ.
Günter is right. Content-Length has to be the length of the byte array after encoding from a String to bytes in whatever encoding you server requires.
There's a package called http which provides a slightly higher level api (it uses dart.io httpClient under the hood) which takes care of encoding the post body and length for you. For example, when you need to send application/x-www-form-urlencoded form it will even take a Map and do all the encoding for you (you still need to encode to json yourself). It's equally happy to send just a String or List<int>. Here's an example:
Map<String, String> body = {
'name': 'doodle',
'color': 'blue',
'teamJson': json.encode({
'homeTeam': {'team': 'Team A'},
'awayTeam': {'team': 'Team B'},
}),
};
Response r = await post(
url,
body: body,
);
Seems your string contains multibyte characters.
UTF8-encode the string to get the correct length:
var body = utf8.encode(json.encode(data));