I am trying to make an HTTP request (I realise there is an http package that would probably make this easier but I want to learn how to do it with dart:io). My code below successfully prints out index.html from example.com, except the program runs forever, I assume because it is continues listening for data from the response. How do I stop the listener once all the data has been received from the stream? I assume I need to pass a handler to the onDone argument but I'm not sure what. I tried calling response.detachSocket() as per below, as that was the only logical seeming thing I could find, but it didn't work. If it's not obvious, I'm not totally sure what I'm doing here so any explanation would be greatly appreciated.
import 'dart:convert';
import 'dart:io';
main() async {
var client = new HttpClient();
var request = await client.getUrl(Uri.parse("http://www.example.com/"));
var response = await request.close();
response.transform(utf8.decoder).listen((data) {
print(data);
}, onDone: () => response.detachSocket());
}
You never close your HttpClient. Close it after you're done with it. The stream subscription will close itself when it's done, the onDone handler is a convenient way to run code when a stream completes, it's not necessary to use it to close the stream.
import 'dart:convert';
import 'dart:io';
main() async {
var client = new HttpClient();
var request = await client.getUrl(Uri.parse("http://www.example.com/"));
var response = await request.close();
response.transform(utf8.decoder).listen((data) {
print(data);
}, onDone: () => response.detachSocket());
client.close();
}
There is also no need to detach the socket.
You could even call client.close earlier with the force parameter set to false, which is the default:
main() async {
var client = new HttpClient();
var request = await client.getUrl(Uri.parse("http://www.example.com/"));
client.close();
var response = await request.close();
response.transform(utf8.decoder).listen((data) {
print(data);
});
}
I'm trying to stream the html response in Deno but can't quite figure it out.
Doing it from a Service Worker on the front end looks like this:
async function streamResponse(html: {start: (s: string) => Promise<void>}) {
const encoder = new TextEncoder()
const stream = new ReadableStream({
async start(controller : ReadableStreamDefaultController<any>) {
const send = (item: string) => controller.enqueue(encoder.encode(item))
await html.start(send)
controller.close()
}
})
return new Response(stream, { headers: { "content-type": "text/html; charset=utf-8" }})
}
When I do something similar to that in Deno (req.respond({body: stream, headers})) it says that the body can't be of the type ReadableStream. I know there is some way to do this. I just can't figure it out. What am I missing? I looked in multiple places trying to understand how it is done but I haven't found any good example yet.
Figured it out. I need to use Deno.Buffer as the writer and then bring in BufReader to wrap the writer.
import { BufReader } from "https://deno.land/std#0.79.0/io/bufio.ts"
import { ServerRequest } from "https://deno.land/std#0.79.0/http/server.ts"
import { HTML } from "./html.ts"
var headers = new Headers({
"Content-Type": "text/html"
})
const encoder = new TextEncoder()
export async function toHTML(req: ServerRequest, html: Promise<HTML>) {
var buffer = new Deno.Buffer()
var body = new BufReader(buffer)
var h = await html
req.respond({body, headers})
await h.start((item: string) => buffer.write(encoder.encode(item)))
}
this is what i tried:
Future<User> guestLogin(String deviceID) async {
var body = {
"deviceid": deviceID,
};
var bodyEncoded = json.encode(body);
Response response = await client.post(
"$_baseURL/api/user/guest",
body: bodyEncoded,
headers: {"Content-Type": "application/json"},
);
return User.fromJson(json.decode(response.body));
}
but when i check it from serverside which coded by golang then i see that the body is empty. when i try it on postman its working well. Where is the problem?
try jsonEncode(body) instead of json.encode(body)
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;
}
I'm trying to receive a get request using Flutter and HttpClient.
This is complete code in what I'm trying to accomplish.
getSuggest() async {
try {
var httpClient = new HttpClient();
var uri = new Uri.http(
'http://autocomplete.geocoder.api.here.com', '/6.2/suggest.json', {
'app_id': 'APP_ID',
'app_code': 'APP_CODE',
'query': '123 Main Street',
'country': 'USA',
'language': 'en',
});
var request = await httpClient.getUrl(uri);
var response = await request.close();
var responseBody = await response.transform(Utf8Decoder()).join();
Map data = jsonDecode(responseBody);
print(data);
} catch (error) {
print(error);
}
}
And I'm using
import 'dart:io';
import 'dart:convert';
But my code always gets sent to the print(error) and the error that gets printed is
FormatException: Invalid radix-10 number
Any ideas?
Thanks!!
The problem is the scheme. You don't have to set it in Uri.http or Uri.https methods, it is set automatically, so change with the following:
Uri.http(
'autocomplete.geocoder.api.here.com', '/6.2/suggest.json', {
'app_id': 'APP_ID',
'app_code': 'APP_CODE',
'query': '123 Main Street',
'country': 'USA',
'language': 'en',
});
And I suggest using http package and do something like that:
import 'package:http/http.dart' as http;
import 'dart:convert';
final json = const JsonCodec();
getSuggest() async {
try {
var uri = Uri.http(
'autocomplete.geocoder.api.here.com', '/6.2/suggest.json', {
'app_id': 'APP_ID',
'app_code': 'APP_CODE',
'query': '123 Main Street',
'country': 'USA',
'language': 'en',
});
var response = await http.get(uri);
var data = json.decode(response.body);
print(data);
} catch (error) {
print(error);
}
}
and use its http client if you need to set much more things (e.g. User Agents).
var url = Uri.https('http://192.168.43.5:3000/api', '/auth/getAllUsers', {'q': '{http}'});
The reason of this error is you do not have to provide https:// like above. Base url is enough. Additionally, you should use Uri.http instead of Uri.https, since your URL uses http:// (not https://). You should do it like the following.
var url = Uri.http('192.168.43.5:3000/api', '/auth/getAllUsers', {'q': '{http}'});