Unable to send header information with client.post - flutter

I'm trying to pass along a bearer token and refresh token to an endpoint in Flutter but I'm getting errors no matter what I try. The api endpoint does work with Postman and returns a new token so the issue is with Flutter.
Future<List<PetsList>> fetchPets(http.Client client) async {
var _headers = {
'Content-Type': 'application/json',
'token': singleton.token,
'refreshToken': singleton.refreshToken,
};
var encodedHeader = json.encode(json.encode(_headers));
final response = await client.post(
Uri.parse(baseUrl + '/account/refreshtoken'),
headers: encodedHeader);
print("${response.body}");
};
This threw an error and stated that "The argument type 'String' can't be assigned to the parameter type 'Map<String, String>?'"
So I appended encodedHeader as Map<String, String> in the response
encodedHeader as Map<String, String>
but that then threw another error, "_CastError (type 'String' is not a subtype of type 'Map<String, String>' in type cast)"
Lastly, the response.body throws an error when I try to simply
print("${response.body}");
and states "Object reference not set to an instance of an object."
No matter what I've tried Flutter complains about this, I seem to be going in circles on this one and could use some help.

The headers require a map<string, string> if you json encode it then it becomes a single string. Please remove the encode
Future<List<PetsList>> fetchPets(http.Client client) async {
Map<String, String> _headers = {
'Content-Type': 'application/json',
'token': singleton.token,
'refreshToken': singleton.refreshToken,
};
final response = await client.post(
Uri.parse(baseUrl + '/account/refreshtoken'),
headers: _headers);
};

Related

The body might complete normally, causing 'null' to be returned, but the return type, 'FutureOr<UserModel> and can't be assigned to type 'Uri'

I am getting two errors in the below code.
The body might complete normally, causing 'null' to be returned, but the return type, 'FutureOr', is a potentially non-nullable type.
Try adding either a return or a throw statement at the end.
The argument type 'String' can't be assigned to the parameter type 'Uri'.
import 'dart:convert';
import 'package:altamazee/models/user_model.dart';
import 'package:http/http.dart' as http;
class AuthService {
String baseUrl = 'https://shamo-backend.buildwithangga.id/api';
Future<UserModel> register({
required String name,
required String username,
required String email,
required String password,
}) async {
var url = '$baseUrl/register';
var headers = {'Content-Type': 'application/json'};
var body = jsonEncode({
'name': name,
'username': username,
'email': email,
'password': password,
});
var response = await http.post(
url,
headers: headers,
body: body,
);
if (response.statusCode == 200) {
var data = jsonDecode(response.body)['data'];
UserModel user = UserModel.fromJson(data['user']);
user.token = 'Bearer ' + data['access_token'];
return user;
}
}
}
The first error occurs on the line Future<UserModel> register({. The second error is on the line with http.post.
The first error is because you don't return anything if your http.post request isn't successful. You can fix this by returning something even if the post request fails, such as using Future<UserModel?> as the return type (null if no UserModel is returned), by returning an empty UserModel, or by throwing an error.
The second error is because the first parameter for http.post is a Uri, not a string. Build your Uri according to the example here: http package example.
final url = Uri.https('https://shamo-backend.buildwithangga.id', '/api/register');
First error says what if you haven’t get any response due to error!
You only checked for 200 status code. If error happens then this block
if(response.statusCode == 200) will not be executed.
So, there is nothing to return! You may write like this,
if(response.statusCode == 200)
{
// your code
}
return null; //this will execute if error occurs
But doing this will show an error because your return type is, Future<UserModel>.
So, change it to Future<UserModel?> will fix the first error!
Second Error
This worked previously, but now http needs Uri type instead of String.
Doing like this will fix your error,
var response = await http.post(
Uri.parse(url),
headers: headers,
body: body,
);

In flutter I am unable to connect to API, When I test it works well but from flutter it is not working?

Future predictCluster(List<List<int>> scores) async {
String url = 'http://127.0.0.1:5000/predict';
Uri uri = Uri.parse(url);
Response response = await post(uri, body: (scores));
Map<String, dynamic> prediction = json.decode(response.body);
cluster = int.parse(prediction["predicted_cluster"][0]);
notifyListeners();
}
Here I have to send a list of list with integers as per API but getting rejected by casting when I am using encode methods I am getting a Format exception.
This is the api.
Getting Error for line
Response response = await post(uri, body: (scores));
Error:
[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'List' is not a subtype of type 'int' in type cast
The problem is, probably, that your emulator doesn't reach your API on your local machine.
The url should instead be:
String url = 'http://10.0.2.2:5000/predict';
Future predictCluster(List<List<int>> scores) async {
String url = 'http://10.0.2.2:5000/predict';
Uri uri = Uri.parse(url);
final encodedData = jsonEncode(<String, dynamic>{
"score": scores,
});
Response response = await post(
uri,
headers: {"Content-Type": "application/json"},
body: encodedData,
);
Map<String, dynamic> prediction = json.decode(response.body);
cluster = int.parse(prediction["predicted_cluster"][0]);
notifyListeners();
}
We have to send through the map structure to encode data and also mention the header content type to application/json.

Reusing http headers

I'm trying to find a best way to reuse http headers in my http responses. Instead of writing it in string literal
final http.Response response = await http.post(APIPath.somePath(),
headers:{"Content-Type": "application/json","Authorization": "Bearer $_token"},
body: json.encode(body));
I have made a custom class and get each header into a static function
class APIHeader {
static Map<String, String> json() => {"Content-Type": "application/json"};
static Map<String, String> form() => {"Content-Type": "multipart/form-data"};
static Map<String, String> authorization(String token) =>
{"Authorization": "Bearer $token"};
}
and call them wherever I need them which work great if there is only one header needed
final http.Response response = await http.put(APIPath.somePath(),
headers: APIHeader.json(), body: json.encode(body));
However I'm having a trouble if I need more then one header. I tried this..
final header = {}
..addAll(APIHeader.authorization(_token))
..addAll(APIHeader.json());
final http.Response response = await http.post(APIPath.somePath(),
headers: header, body: json.encode(body));
which gives me an error
Unhandled Exception: type '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'Map<String, String>'
Anyone have better idea how to reuse the headers?
Thanks to #pskink I found using mergeMaps from 'package:collection/collection.dart' the best way to reuse headers and merge them into one map
final http.Response response = await http.post(APIPath.somePath(),
headers: [APIHeader.authorization(_token), APIHeader.json()]
.reduce(mergeMaps),
body: json.encode(body));

Invalid Header Name In Flutter HTTP Request

I have a login page where i am trying to send a login request to my backend. But I get an Unhandled Exception: Invalid header field name. Here is my submit function
submit() async {
var res = await LoginAPI().loginData(
{'email': _emailController.value, 'password': _passwordController.value});
var body = json.decode(res.body);
print(body);
}
Then in my LoginAPI class here is my loginData function that makes the call to the backend
import 'dart:convert';
import 'package:http/http.dart' as http;
class LoginAPI {
final String _url = "http://10.0.2.2:8000/api/";
Map<String, String> headers = {"Content-type": "application/json"};
loginData(data) async {
var fullUrl = _url + "v1/users/login";
return await http.post(
fullUrl,
body: jsonEncode(data),
headers: headers
);
}
}
Here is my request through postman
Here is my response through postman
When I make the same request with Postman i get the response I am supposed to get. What Am i doing wrong?
try this
Map<String, String> headers = {"Content-type": "application/json", "Accept": "application/json",};
It looks from your postman request that you are just sending form data (not a json encoded body). package:http will form encode the body for you (and add the content type header) if you do the following:
return await http.post(
fullUrl,
body: data,
);
So i was able to solve the issue. The issue was with my CORS middleware on my server. I just made some changes and it worked fine. So if anyone has this issue just know it has nothing to do with flutter but most probably CORS

Dart unable to parse JSON from string to int

I am trying to parse a JSON value from string to int but got stuck :(
The code below shows a HTTP get request and retrieving a JSON object in which I want to obtain the 'reps' value in Integer.
var response = await httpClient.get(url, headers: {
'Content-type': 'application/json',
'Accept': 'application/json',
'X-API-Key': apikey
});
print('Response status: ${response.statusCode}');
print('Response body: ${response.body}');
var res = json.decode(response.body);
String repStr = res['reps'];
print(repStr);
int repInt = int.parse(repStr);
The debug console shows the following error on the line
String repStr = res['reps'];
E/flutter ( 8562): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: type 'int' is not a subtype of type 'String'
As the exception explains, the value res['reps'] is already an integer you don't need to parse it.
int repStr = res['reps'];