utf8.decoder not working after latest Flutter Upgrade - android

The class APIPostRequest was wroking all fine until a flutter upgrade hit and it shows an error of "The argument type 'Utf8Decoder' can't be assigned to the parameter type 'StreamTransformer'." while transforming HttpClientResponse's object into String using ...transform(utf8.decoder)...
class APIPostRequest {
Future<String> apiRequest(String url, Map jsonMap) async {
HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
request.headers.set('Accept', 'application/json');
request.headers.set('Content-type', 'application/json');
request.headers
.set('Authorization', "Bearer " + UserConstants.userAccessToken);
request.add(utf8.encode(json.encode(jsonMap)));
HttpClientResponse response = await request.close();
String reply = await response.transform(utf8.decoder).join();
httpClient.close();
return reply;
}
}

See the corresponding breaking change announcement:
Error cases (and how to fix them):
If you see the following errors in your code, here's what you do to fix them:
Error: "The argument type 'Utf8Decoder' can't be assigned to the parameter type 'StreamTransformer'."
How to fix: Use StreamTransformer.bind(Stream) instead of Stream.transform(StreamTransformer).
Example:
Before: foo.transform(utf8.decoder)...
After: utf8.decoder.bind(foo)...

Comment String reply = await utf8.decoder.bind(response).join();
and use the following code :
//String reply = await response.transform(utf8.decoder).join();
String reply;
request.close().then((response){
response.cast<List<int>>().transform(utf8.decoder).listen((content) {
print (content);
reply = content;
});

See below solution
class APIPostRequest {
Future<String> apiRequest(String url, Map jsonMap) async {
HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
request.headers.set('Accept', 'application/json');
request.headers.set('Content-type', 'application/json');
request.headers
.set('Authorization', "Bearer " + UserConstants.userAccessToken);
request.add(utf8.encode(json.encode(jsonMap)));
HttpClientResponse response = await request.close();
String reply = await utf8.decoder.bind(response).join();
httpClient.close();
return reply;
}
}

Related

Api is working in postman but response always return 500 in flutter

My rest api is working successfully. When I send post request in flutter with Dio. Service always return 500 internal server error.
header
post request
Dio Options
To create a form data use this
var formData = FormData.fromMap({
'user': 'username',
'pass': 'password',
});
response = await dio.post('apiendpoint', data: formData);
I think you are missing the content-type in your header.. based on what your remote accepts either 'application/x-www-form-urlencoded' or 'application/json'
var data = {"phone": mobileNumber, "password": password};
var dio = Dio();
dio.options.headers['content-Type'] = 'application/x-www-form-urlencoded';
try {
var response = await dio.post(ApiUrl.baseUrl + url, data: data);
print(response);
} on DioError catch (e) {
print(e);
}
you can try this way :
var formData = {
'user': 'username',
'pass': 'password',
};
response = await dio.post('apiendpoint', data: jsonEncode(formData));

How to send Binary encrypted data in flutter POST with request encoding :null ? ; which is working in node js properly

According to node.js Documentation encoding : null when binary data to be sent via Api,
https://www.npmjs.com/package/request in this link below mentioned explanation is found.
encoding - encoding to be used on setEncoding of response data. If
null, the body is returned as a Buffer. Anything else (including the
default value of undefined) will be passed as the encoding parameter
to toString() (meaning this is effectively utf8 by default).
Note: if you expect binary data, you should set encoding: null.
Now I have achieve the same thing in flutter/dart and this encoding parameter is not accepting null as here in node.js they have mentioned.
I want to know how to make this same Post request from Flutter/dart or at least android/java.
var enc = AESCrypt.encrypt(key, iv, JSON.stringify(obj_j));
var output = new Buffer.from(enc, 'hex'); // Buffer
function test() {
console.time("XXX");
request.post({
headers: {
'content-type': 'application/json'
}, //required, or webserver will ignore it application/json multipart/form-data
url: 'http://192.168.29.210/deviceid/read', // webserver url
encoding:null,
body: output
},
function (error, response, body) {
if (!error && response.statusCode == 200) {
console.timeEnd("XXX");
body = AESCrypt.decrypt(key, iv, body);
//body is decrypted http response, can be parsed with json method
fs.writeFile('input.json', body, function (err) {
if (err) {
return console.error(err);
}
});
}
});
};
Adding code the What i have tried in flutter
var headers = {'Content-Type': 'application/json'};
var request =
http.Request('POST', Uri.parse('http://192.168.29.210/deviceid/read'));
request.body = encryptedText;
request.encoding = null ; // here this null parameter is not acceptable
request.encoding = Encoding.getByName("utf-8")); // only this option is available to add in flutter
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
Even in post man this encoding variable is not present to set it.
Use below flutter framework method
Future<Response> post(Uri url,
{Map<String, String>? headers, Object? body, Encoding? encoding}) =>
_withClient((client) =>
client.post(url, headers: headers, body: body, encoding: encoding));
How to use
final url = Uri.parse('$urlPrefix/posts');
final headers = {"Content-type": "application/json"};
final json = '{"title": "Hello", "body": "body text", "userId": 1}';
final response = await post(url, headers: headers, body: json,encoding:null); //here this null parameter is not acceptable
My Final working code is
var headers = {'Content-Type': 'application/json'};
final response = await http.post(
Uri.parse('http://192.168.29.210/deviceid/read'),
headers: headers,
body: encryptedText,
encoding: null);
if (response.statusCode == 200) {
String res = response.body.toString();
//String data = AesEncryption().decryption(res);
print('Body: ${response.body.toString()}');
} else {
print(response.reasonPhrase);
}
print('Status code: ${response.statusCode}');

Convert OkHttp's Form Data (Android) to Axios(React Native)'s Form Data

I'm recreating a project that was originally designed for Native Android to use React Native. There is an endpoint that is responsible to send a image using Form Data. I tried to convert the OkHttp3's Form Data to Axios's Form Data and I'm getting an error from backend saying that the request fields doesn't match.
My Code so far:
- Native Android(original app):
public RequestResponse<Boolean> functionApi(#NonNull String id, String imageExtension, #NonNull byte[] imageData, #NonNull String anotherData) throws ServerErrorException, IOException, AuthenticationException {
String path = "route/" + id;
Pair<String, String> contentTypeHeader = new Pair<>("Content-Type", "multipart/form-data");
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("anotherData", anotherData)
.addFormDataPart("imageData", id + "." + imageExtension, RequestBody.create(MediaType.parse("image/png"), imageData))
.build();
Response response = MyHttpClient.execute(path, "POST", requestBody, contentTypeHeader);
String body = response.body().string();
RequestResponse<Boolean> r = responseBodyToObject(body, RequestResponse.class);
r.setBody(r.getStatus() != RequestResponse.ERROR);
return r;
}
React Native(new app) version:
export const functionApi = async(id,imageExtension,imageData,anotherData)=>{
try{
let formData = new FormData()
formData.append('anotherData',anotherData)
formData.append('imageData',`data:image/${imageExtension};base64,${imageData}`,`${id}.${imageExtension}`)
//imageData here i tried to use a base64's string
let res = await axios({
url:`${URL_SERVER}/route/${id}`,
method:'POST',
headers:{
'Content-Type':"multipart/form-data"
},
data:formData
})
return res['data']
}catch(err){
return getErrorMessage(err)
}
}
I got a solution that finally worked for me:
export const functionApi = async(id,imageExtension,imageData,anotherData)=>{
try{
let formData = new FormData()
formData.append('anotherData',anotherData)
formData.append('imageData',{
uri: imageData['uri'],
type: 'image/jpg',
name: `${id}.${imageExtension}`,
})
let res = await axios({
url:`${URL_SERVER}/route/${id}`,
method:'POST',
headers:{
'Content-Type':'multipart/form-data'
},
data:formData
})
return res['data']
}catch(err){
return getErrorMessage(err)
}
}

How to post int/integer value as json from dart/flutter

I am using asp.net core web API as back-end. There is a method that accepts a single integer value.
Method([FromBody] int value)
I want to post the integer value from dart/flutter.
I tried the following with the dart http package.
Http.post(url, body:0,headers:{"content-type":"application/json"}
Http.post(url, body:{0},headers:{"content-type":"application/json"}
Http.post(url, body:convert.jsonEncode(0),headers:{"content-type":"application/json"}
Http.post(url, body:convert.jsonEncode({0}),headers:{"content-type":"application/json"}
All my above tries failed with error
"Invalid argument: invalid request body "0""
I had the same problem when trying to send an HTTP request to an API that has an integer as one of its arguments(age). Dart wanted me to convert the int into a string and the API was not accepting the int as a string. Hence I was getting the same error and ended up in this question.
My solution was to store the input in a map, add a header {"content-type":"application/json"} and pass the map in the body arguement.
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<String> register_user() async {
var req_body = new Map();
req_body['username'] = 'John Doe';
req_body['age'] = 20; /* The integer */
final response = await http.post(
'http://127.0.0.1:8081/user/register',
headers: {'Content-Type': 'application/json'},
body: jsonEncode(req_body));
if (response.statusCode == 200) {
var object = json.decode(response.body);
return object.toString();
} else if (response.statusCode == 422) {
return 'Error';
} else {
return 'Can not connect to server';
}
}
Please refer my code
import
import 'package:http/http.dart' as http;
http request
var client = new http.Client();
client.post(Uri.encodeFull("Your url"), body: {
"param1": "value1",
"param2": 11, // integer value type
}).then((response) {
client.close();
if (this.mounted && response.statusCode == 200) {
//enter your code for change state
}
}).catchError((onError) {
client.close();
print("Error: $onError");
});
I hope it will help you.
PS:
var client = new http.Client();
var response = await client.post(Uri.encodeFull("Your Url"), body : "0", header : {/*Your headers*/"});
You can try this code.
Http.post(url, body:{"id": "0"},headers:{"content-type":"application/json"}
Can you try bellow one
var queryParameters = {
'value': '0'
};
var uri =
Uri.https('www.myurl.com', '/api/sub_api_part/', queryParameters); //replace between part and your url
var response = await http.get(uri, headers: {
HttpHeaders.contentTypeHeader: 'application/json'
});

AWS Lambda : errorMessage Process exited before completing request

Hi I'm newbie in android!
I want to upload image file from android client to server(Server makes thumbnail, and return thumbnail's url).
However I stucked in this error message.
{"errorMessage":"RequestId: 8e2a21b8-e62e-11e8-8585-d9b6fdfec9b9 Process exited before completing request"}!
I tried to find this error code in stackoverflow, but i cannot found answer for android.
Please help or give me link where I can solve this problem...
Here is server code.
const AWS = require('aws-sdk');
const multipart = require("parse-multipart");
const s3 = new AWS.S3();
const bluebird = require('bluebird');
exports.handler = function(event, context) {
let result = [];
const bodyBuffer = new Buffer(event['body-json'].toString(), 'base64');
const boundary = multipart.getBoundary(event.params.header['Content-Type']);
const parts = multipart.Parse(bodyBuffer, boundary);
const files = getFiles(parts);
return bluebird.map(files, file => {
console.log('UploadCall');
return upload(file)
.then(
data => {
result.push({
'bucket': data.Bucket,
'key': data.key,
'fileUrl': file.uploadFile.fullPath })
console.log( `DATA => ${JSON.stringify(data, null, 2 )}`);
},
err => {
console.log(`S3 UPLOAD ERR => ${err}`);
}
)
})
.then(_=> {
return context.succeed(result);
});
}
let upload = function(file) {
console.log('PutObject Call')
return s3.upload(file.params).promise();
};
let getFiles = function(parts) {
let files = [];
parts.forEach(part => {
const buffer = part.data
const fileName = part.filename;
const fileFullName = fileName;
const originBucket = 'dna-edge/images';
const filefullPath = `https://s3.ap-northeast-2.amazonaws.com/${originBucket}/${fileFullName}`;
const params = {
Bucket: originBucket,
Key: fileFullName,
Body: buffer
};
const uploadFile = {
size: buffer.toString('ascii').length,
type: part.type,
name: fileName,
fullPath: filefullPath
};
files.push({ params, uploadFile })
});
return files;
};
And this is client code.(imgURL looks like /storage/emulated/0/DCIM/img/1493742568136.jpg)
public static String requestHttpPostLambda(String url, String imgURL){
/*
await axios.post(`${AWS_LAMBDA_API_URL}?type=${type}`, formData,
{ headers: { 'Content-Type': 'multipart/form-data' }})
.then((response) => {result = response});
*/
String result=null;
try {
HttpClient client = new DefaultHttpClient();
String postURL = url;
HttpPost post = new HttpPost(postURL);
post.setHeader("Content-Type", "multipart/form-data");
File file = new File(imgURL);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addPart("image", new FileBody(file));
post.setEntity(builder.build());
HttpResponse responsePOST = client.execute(post);
Log.e("HttpResponse", responsePOST.getStatusLine()+"");
HttpEntity resEntity = responsePOST.getEntity();
if (resEntity != null) {
result = EntityUtils.toString(resEntity);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
Welcome to stackoverflow.
So for some reason AWS aren't too good an updating the docs, don't use context.succeed, use the callback thats passed as a third param.
Also I'd move to Node 8.10 runtime because then rather than using promises/then pattern you can use async/await.
export default(event, context, callback) => {
try {
// do some stuff
callback(null, SOME_VALID_HTTP_RESPONSE)
} catch(e){
callback(e, null)
}
}
There's a few reason your Lambda could be failing, if the process exited before completing it's either crashing OR you're not returning a valid HTTP response(if your lambda is behind API gateway)
Two solutions - first place to look is in cloudwatch, find your lambda function name and check the latest log to look for error messages.
Second - check out my answer here so when your function succeeds you need to return a valid HTTP response to API Gateway so in essence if you use my code from there you can do:
callback(null, responder.success({someJson: someValue}))
Any questions let me know :-)
EDIT: I'm updating this question I'm just working on an example for a multiple file upload to S3!

Categories

Resources