How to make HTTP POST request with url encoded body in flutter?
DartFlutterDart Problem Overview
I'm trying to make an post request in flutter with content type as url encoded. When I write body : json.encode(data)
, it encodes to plain text.
If I write body: data
I get the error type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String' in type cast
This is the data object
var match = {
"homeTeam": {"team": "Team A"},
"awayTeam": {"team": "Team B"}
};
And my request
var response = await post(Uri.parse(url),
headers: {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body: match,
encoding: Encoding.getByName("utf-8"));
Dart Solutions
Solution 1 - Dart
You need to add three additional steps: First, you need to convert the JSON map to a String (using json.encode) Then you need to Uri encode it if you want to send it as application/x-www-form-urlencoded. Lastly, you need to give the parameter that you are posting a name.
For example (note, this is using the dart:io HttpClient, but it's basically the same):
Future<HttpClientResponse> foo() async {
Map<String, dynamic> jsonMap = {
'homeTeam': {'team': 'Team A'},
'awayTeam': {'team': 'Team B'},
};
String jsonString = json.encode(jsonMap); // encode map to json
String paramName = 'param'; // give the post param a name
String formBody = paramName + '=' + Uri.encodeQueryComponent(jsonString);
List<int> bodyBytes = utf8.encode(formBody); // utf8 encode
HttpClientRequest request =
await _httpClient.post(_host, _port, '/a/b/c');
// it's polite to send the body length to the server
request.headers.set('Content-Length', bodyBytes.length.toString());
// todo add other headers here
request.add(bodyBytes);
return await request.close();
}
The above is for the dart:io
version (which, of course, you can use in Flutter)
If you would like to stick with the package:http
version, then you need to tweak your Map a bit. body
must be a Map<String, String>
. You need to decide what you want as your POST parameters. Do you want two: homeTeam and awayTeam? or one, say, teamJson?
This code
Map<String, String> body = {
'name': 'doodle',
'color': 'blue',
'homeTeam': json.encode(
{'team': 'Team A'},
),
'awayTeam': json.encode(
{'team': 'Team B'},
),
};
Response r = await post(
url,
body: body,
);
produces this on the wire
> name=doodle&color=blue&homeTeam=%7B%22team%22%3A%22Team+A%22%7D&awayTeam=%7B%22team%22%3A%22Team+B%22%7D
alternatively, this
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,
);
produces this on the wire
> name=doodle&color=blue&teamJson=%7B%22homeTeam%22%3A%7B%22team%22%3A%22Team+A%22%7D%2C%22awayTeam%22%3A%7B%22team%22%3A%22Team+B%22%7D%7D
the package:http
client takes care of: encoding the Uri.encodeQueryComponent, utf8 encoding (note that that's the default, so no need to specify it) and sending the length in the Content-Length header. You must still do the json encoding.
Solution 2 - Dart
I'd like to recommend dio package to you , dio is a powerful Http client for Dart/Flutter, which supports Interceptors, FormData, Request Cancellation, File Downloading, Timeout etc.
dio is very easy to use, in your case you can:
Map<String, String> body = {
'name': 'doodle',
'color': 'blue',
'teamJson': {
'homeTeam': {'team': 'Team A'},
'awayTeam': {'team': 'Team B'},
},
};
dio.post("/info",data:body, options:
new Options(contentType:ContentType.parse("application/x-www-form-urlencoded")))
dio can encode the data automatically.
More details please refer to dio.
Solution 3 - Dart
I came here just trying to make an HTTP POST request. Here is an example of how to do that:
import 'dart:convert';
import 'package:http/http.dart';
makePostRequest() async {
final uri = Uri.parse('http://httpbin.org/post');
final headers = {'Content-Type': 'application/json'};
Map<String, dynamic> body = {'id': 21, 'name': 'bob'};
String jsonBody = json.encode(body);
final encoding = Encoding.getByName('utf-8');
Response response = await post(
uri,
headers: headers,
body: jsonBody,
encoding: encoding,
);
int statusCode = response.statusCode;
String responseBody = response.body;
}
See also
Solution 4 - Dart
you need to use json.encode
example;
var match = {
"homeTeam": {"team": "Team A"},
"awayTeam": {"team": "Team B"}
};
var response = await post(Uri.parse(url),
headers: {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body: json.encode(match),
encoding: Encoding.getByName("utf-8"));
Solution 5 - Dart
I suggest using the Dio library. It supports a lot with working with APIs.
With newest Dio version. Simply do the following:
BaseOptions options = new BaseOptions(
baseUrl: "https://www.xx.com/api",
connectTimeout: 5000,
receiveTimeout: 3000,);
Dio dio = new Dio(options);
//
Map<String, String> params = Map();
params['username'] = '6388';
params['password'] = '123456';
//
response = await dio.post("/login", data: FormData.fromMap(params));
Solution 6 - Dart
On the place of "UserModel" write the name of your model and do not pass String in the body it will create a problem using "Map" as given below.
static Future<UserModel> performUserLogin(String username, String password) async{
try{
Map<String, String> headers = {"Content-type": "application/json"};
Map<String, String> JsonBody = {
'username': username,
'password': password
};
print("The JSON Object is here $body");
// make POST request
final response = await http.post(loginAPIURL,body: JsonBody);
// check the status code for the result
int statusCode = response.statusCode;
print("Login calling $response");
if (statusCode == 200){
}else{
return null;
//return UserModel();
throw Exception("Error in login");
}
} catch (e) {
throw Exception(e);
}
}
Solution 7 - Dart
If you are using dio you can do it using :
dio.post(
'/info',
data: {'id': 5},
options: Options(contentType: Headers.formUrlEncodedContentType),
);
check https://github.com/flutterchina/dio for more details
Solution 8 - Dart
I did it like this with dart's http package. It's not too fancy. My endpoint wasn't accepting the parameters with other methods, but it accepted them like this, with the brackets included in the parameter.
import 'package:http/http.dart' as http;
String url = "<URL>";
Map<String, String> match = {
"homeTeam[team]": "Team A",
"awayTeam[team]": "Team B",
};
Map<String, String> headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
http.post(url, body: body, headers: headers).then((response){
print(response.toString());
});
Solution 9 - Dart
Map<String, String> body = {
'getDetails': 'true'
};
final response = await
http.post("https://example.com/", body: body);
if (response.statusCode == 200) {
//Your code
}
Solution 10 - Dart
> Post encoded URL request
static Future<http.Response> genearalRequest() async {
Map<String,String> headers = new Map();
headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8";
var data = {
"data1": "datat1 value",
"data2": "value2"
};
var parts = [];
data.forEach((key, value) {
parts.add('${Uri.encodeQueryComponent(key)}='
'${Uri.encodeQueryComponent(value)}');
});
var formData = parts.join('&');
print(formData);
return await http.post('$baseUrl/oauth/token', headers: headers, body: formData);
}
Solution 11 - Dart
Simple get request using DIO :
Future<dynamic> get(String uri, {
Map<String, dynamic> queryParameters,
Options options,
}) async {
try {
var response = await _dio.get(
uri,
queryParameters: queryParameters,
options: options,
);
return response.data;
} on SocketException catch (e) {
throw SocketException(e.toString());
} on FormatException catch (_) {
throw FormatException("Unable to process the data");
} catch (e) {
throw e;
}
}
Simple Post Request using DIO {you can send files and images as well} :
Future<dynamic> post(
String uri, {
data,
Map<String, dynamic> queryParameters,
Options options,
}) async {
try {
var response = await _dio.post(
uri,
data: data,
queryParameters: queryParameters,
options: options,
);
return response.data;
} on FormatException catch (_) {
throw FormatException("Unable to process the data");
} catch (e) {
throw e;
}
}
Solution 12 - Dart
You can use addAll()...
var multipart = await http.MultipartFile.fromPath("userfile", file.path);//userFile must match server
var requestMultipart = http.MultipartRequest("POST", Uri.parse("uri"));
requestMultipart.files.add(multipart);
Map<String, String> data = {
"name_of_image": "testName",
"id_image": "2",//if the
"upload_type": "Insert",
"id_location": "2"
};
requestMultipart.fields.addAll(data);