POST image to web service with Flutter - rest

I am currently using Flutter and Dart to try to send an image to a web service, after which I wait for a JSON response. The below links show the Postman request that I am trying to mimic.
An image of Postman with the headers required
An image of Postman with the body
I think the issue I am having is either not setting the headers of my request correctly, or not encoding the image correctly.
Currently I am getting a HTTP 400 error.
I have tried following these suggested solutions on StackOverflow but have been getting the HTTP 400 error.
Any help would be much appreciated!

Try this. I'd suggest creating yourself a plain Dart project, if you haven't already. This way you can test things without the need of the phone emulator, etc.
main() async {
http.MultipartRequest request =
new http.MultipartRequest('POST', Uri.parse(url));
request.headers['Prediction-Key'] = '3f4a......'; // todo - insert real value
request.files.add(
new http.MultipartFile.fromBytes(
'image',
bytes,
filename: 'somefile', // optional
contentType: new MediaType('image', 'jpeg'),
),
);
http.StreamedResponse r = await request.send();
print(r.statusCode);
}
If the file is on disk, not in memory, then use the fromPath named constructor instead. Experiment with different media types. I've used image/jpeg, but you could try application/octet-stream.
As an aside, in your first screenshot you show a content type, but Postman ignores this as the overall content type is overridden by multipart-form. Uncheck that row in Postman to prove this.
There was another question recently on SO, where the server was incorrectly expecting headers to be case sensitive. In postman, try again with lowercase prediction-key to prove that the server doesn't mind lowercase headers (which is what Dart uses).

Related

How to extract header values from http response?

I am using http post to send some information and get back the response.
final response = await http.post(
Uri.parse(
"some url"
),
headers: <String, String>{
'email': email,
'callbacktoken': callbacktoken
},
);
When I run this, my execution gets stuck at this codeblock ( I tried putting a print statement in the next line) when the response coming from the backend has header values, however if I send the response with no header from the backend (I am using django at the backend) then the my program runs with no issue.
So my question is how to handle responses with headers and how to extract them?
After a little researching I finally found the issue. My custom header name had space in it "New user" because of which http was not able to parse it. After changing the name to "newuser" everything is working fine.

Flutter - Making a web request

I would like to know if there is a way to format special characters when parsing JSON requests from Flutter. I have tested a http request as such:
void curlRequest() async
{
String urlRequest = "http://my.web.url/webservice/rest/server.php?wstoken=my_token&moodlewsrestformat=json&wsfunction=core_user_create_users&users[0][username]=test_user_4&users[0][firstname]=John&users[0][lastname]=Doe&users[0][email]=john.doe#gmail.com&users[0][password]=Johns_Password";
http.post(urlRequest, headers: {'Content-type': 'application/json; charset=utf-8'}).then((response){
print("Response status: ${response.statusCode}");
print("Response body: ${response.body}");
});
}
I get the following response:
http://my.web.url/webservice/rest/server.php?wstoken=my_token&moodlewsrestformat=json&wsfunction=core_user_create_users&users%5B0%5D%5Busername%5D=test_user_4&users%5B0%5D%5Bfirstname%5D=John&users%5B0%5D%5Blastname%5D=Doe&users%5B0%5D%5Bemail%5D=john.doe#gmail.com&users%5B0%5D%5Bpassword%5D=Johns_Password&i=1
The request was invalid due to special characters being used. How do I make a request so that the special characters are also handled properly?
In a http restful request, the http GET request must be url encoded, which means that most special characters must be encoded in a way understandable by a webserver.
As such, characters such as the plus sign (+) or the question mark (?) must be replaced by their URL encoded equivalents (%2b for the plus sign and %3F for a question mark for instance) and vice versa for decoding.
Several URL encoders can be found online such as http://www.url-encode-decode.com/
In Dart you can use Uri.encodeFull() to encode string and Uri.encodeComponent() to encode a string component
Similarly to decode you can use Uri.decodeFull() and others
read more about this here Uri class
Switching to a better web hosting service resolved my issue. I was using AeonFree, which was a free web hosting service and had limited access for obvious reasons.
I also switched from the http package to using the dio package.

JSON localized strings retuned from API are invalid

I have been trying to get a JSON response form API call which return a localised strings. Works well in Postman with same setup as http calls. but when make an API call from application it returns weird string - please check below.
I tried passing header for supporting language but does not work
JSON response in Postman - "text": "Número OMI-IMO",
JSON response through application - "text":"Número OMI-IMO"
http.Response response = await http.get(
login,
headers: {'Consumer-Key': consumerKey, 'Accept-Language': '*'},
);
I have also tried setting my device default language to respective localized language in this case Spanish, local strings used int he application works fine.
Tried binding the string "text": "Número OMI-IMO", from JSON file works well.
The response re not working only with API response strings, its same with other language like Frensh, Portuguese.
Been trying different solution but nothing work this problem exist on both Android and iOS.
Import this dart lib on the head of the file
import 'dart:convert' as convert
then you do
String jsonString = convert.utf8.decode(response.bodyBytes);
Now you will have a proper formatted and decoded JSON

Error fetch image from storage with message 'Alamofire.AFError.ResponseValidationFailureReason.unacceptableContentType'

I attemp to fetch image from Firebase storage, but have error message:
Alamofire.AFError.responseValidationFailed(reason: Alamofire.AFError.ResponseValidationFailureReason.unacceptableContentType(acceptableContentTypes: ["image/x-xbitmap", "image/jpeg", "application/octet-stream", "image/gif", "image/ico", "image/tiff", "image/x-icon", "image/bmp", "image/x-bmp", "image/x-win-bitmap", "image/png", "image/x-ms-bmp"], responseContentType: "application/json")
My url looks like this: https://firebasestorage.googleapis.com/v0/b/####/o/executors/o4uAQa158nXTvJ5omuxqcRb0e793/products/7DDCEEAC-ED54-4910-B93D-5E40BF411B80
I can download this image via browser.
My image has MIME-type 'image/jpeg':
I found the same situation:
Response Content-Type was missing and acceptable content types
Make sure you set alamofire acceptable content types
Image Response Serializers
These hints didn't help me to fix my bug.
Version of pod:
Alamofire: 5.0.2
AlamofireImage 4.0.2
Initially I used AlamofireImage: productImageView.af.setImage(withURL: url), but it didn't work. Then I began using Alamofire. And into request I pass MIME-type image/jpeg like Content-Type:
And I decided to use this approach to fix bug, but has the same error and I don't understand why(from docs):
If you can see in error-message I have:
responseContentType: "application/json"
So does it have any side effect to fetch image? What I do wrong at all?
Link should be
https://firebasestorage.googleapis.com/v0/b/projectname/o/image.png?alt=media&token=auth_token
replace projectname , image name and token to yours
First, your request headers have nothing do with whether the response is valid, so adding image/jpeg there won't help. Second, your response is return an application/json content type, so adding image/jpeg to the acceptable content types won't help (and image/jpeg is already acceptable). (As an aside, you need to import AlamofireImage to get addAcceptableImageContentTypes to work.)
In the end, you should ensure you're getting the response you expect, as an application/json content type implies you're getting a JSON body, not an image fro your request. When I request the URL you posted, I get this JSON response:
{
"error": {
"code": 400,
"message": "Invalid HTTP method/URL pair."
}
}
So most likely you need to double check how you're supposed to be making the request.

Azure bing cognitive services speech to text in javascript via REST fails

In JavaScript we use recorder.js to capture microphone input, down sample it to 16kHz, encode it as a WAV file and get a blob.
Next, we obtain the raw blob bytes via a FileReader onload() callback and then use an XMLHttpRequest to send() the raw bytes to Bing.
The XMLHttpRequest includes the headers:
'Ocp-Apim-Subscription-Key' : 'xxxxxx'
'Content-Type' : 'audio/wav; codec=audio/pcm; samplerate=16000'
A sample blob size is 62456 bytes.
FireFox network tracing shows 2 interactions. The first is
Request URL: https://speech.platform.bing.com/speech/recognition/interactive/cognitiveservices/v1?language=en-US&format=simple
Request Method: OPTIONS
and the second
Request URL:https://speech.platform.bing.com/speech/recognition/interactive/cognitiveservices/v1?language=en-US&format=simple
Request Method: POST
content-length: 94476
However, I keep getting the following reply
{"RecognitionStatus":"InitialSilenceTimeout","Offset":29000000,"Duration":0}
FWIW, any idea why the source blob size of 62456 would result in content-length: 94476?
The same raw blob bytes are processed by Amazon Lex properly.
Is there any JavaScript RESTful example?
Many thanks.
/--------------------------------------------------------------
After putting together the test case below I also tried the following without success.
console.log("Send to BING blob");
var self = this;
console.log(blob);
var msUrl = 'https://speech.platform.bing.com/speech/recognition/interactive/cognitiveservices/v1';
msUrl += '?language=en-US';
msUrl += '&format=simple';
console.log(msUrl);
var xhr = new XMLHttpRequest();
xhr.onload = function(evt) { console.log('onload', xhr, evt);};
xhr.open('POST', msUrl, true);
xhr.setRequestHeader('Accept', 'application/json;text/xml');
xhr.setRequestHeader('Ocp-Apim-Subscription-Key', 'xxx');
var bingContentType = 'audio/wav; codec=audio/pcm; samplerate=16000';
xhr.setRequestHeader('Content-Type', bingContentType);
xhr.send(blob);
The shorter code version of sending to Bing was fine. The probelm was that the recorder worker's encodeWAV(samples) function did not
take into account the down sampling to 16000. The function was incorrectly writing the captured sampling rate as the header value. The lines to be tweaked are:
view.setUint32(24, downSampleRate, true);
view.setUint32(28, downSampleRate * 2, true); /*MONO*/
Apparently AWS Lex ignores the header values as it only expects 16kHz mono whereas the Bing service has to look at the header information to determine which of the audio formats supported is being sent.
Today I came across this problem, after spending half an hour, I was able to find the real cause of my issue. Let me go through the steps which are mentioned in this link.
Verified my Bing speech API is in running status.
Verified my key by running the below code in
$FetchTokenHeader = #{
'Content-type'='application/x-www-form-urlencoded';
'Content-Length'= '0';
'Ocp-Apim-Subscription-Key' = ''
}
$OAuthToken = Invoke-RestMethod -Method POST -Uri https://api.cognitive.microsoft.com/sts/v1.0/issueToken -Headers $FetchTokenHeader
show the token received
$OAuthToken
As mentioned in the last point in that link, InitialSilenceTimeout may be the result of the unformatted/invalid wav file. So I downloaded a new wav file from internet and tested with it.
Bingo, that worked. And finally, I was able to get my speech in text format