HttpException occure when i post a request to a server as below - flutter

This method is to post an order to a server and it's in a Provider class :
Future<void> addOrder(OrderRequest orderRequest) async {
final prefs = await SharedPreferences.getInstance();
String accessToken = prefs.getString(Constants.prefsUserAccessTokenKey);
String url = Urls.addOrderUrl;
try {
var bodyParams = json.encode({
"Branch": {"Id": orderRequest.branchId},
"DeliveryAddress":
orderRequest.addressId == 0 ? {} : {"Id": orderRequest.addressId},
"InBranch": orderRequest.inBranch,
"TableNumber": orderRequest.tableNumber.toString(),
"OrderItems": orderRequest.items,
"PromoCode": orderRequest.promoCodeId == 0
? {}
: {"Id": orderRequest.promoCodeId}
});
print("Url: " + url);
print("Token: " + accessToken);
print("Params: " + bodyParams);
final response = await retry(
() => http
.post(url,
headers: {
"content-type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer " + accessToken
},
body: json.encode(bodyParams))
.timeout(Duration(seconds: 5)),
retryIf: (e) => e is SocketException || e is TimeoutException);
final responseData = json.decode(response.body);
print(responseData);
if (response.statusCode == 200) {
} else if (response.statusCode == 401) {
throw AuthException("401", responseData['Message']);
} else {
throw HttpException(responseData['Message']);
}
} catch (error) {
print(error);
throw error;
}
}
and in my screen class i create a method to upload my data to the server which i use it when i press a button which handle the post request :
Future<void> _addOrder() async {
OrderRequest request = OrderRequest();
request.addressId = _selectedAddress.id;
request.branchId = int.parse(_selectedBranchId);
request.inBranch = _selectedAddress.id == 0;
request.items = _cartItemsList;
request.promoCodeId = _promoCodeId;
request.tableNumber = _tableNumber;
try {
setState(() {
_isLoading = true;
});
await Provider.of<OrderProvider>(context).addOrder(request);
Provider.of<CartProvider>(context).emptyCart();
_showDialog("Order Sent", "Your order is sent to restaurant.");
} on HttpException catch (error) {
_showDialog("Error adding order", error.message);
} on SocketException catch (_) {
_showDialog("Error adding order",
"Please check your internet connection and try again");
} on TimeoutException catch (_) {
_showDialog("Error adding order",
"Please check your internet connection and try again");
} on AuthException catch (_) {
_refreshToken();
} catch (error) {
print(error);
_showDialog("Error adding address", "Something went wrong");
}
}
but when i press a Order button t to send a post request to a server i got this error:
I/flutter (12421): {Message: Error:Object reference not set to an instance of an object.}
I/flutter (12421): HttpException: Error:Object reference not set to an instance of an object.

this is the model class that i use
class OrderRequest{
int branchId;
int addressId;
bool inBranch;
int promoCodeId;
int tableNumber;
List<CartItem> items;
OrderRequest(
{
this.branchId,
this.addressId,
this.inBranch,
this.promoCodeId,
this.tableNumber,
this.items});
}

Related

Flutter Web - set-cookie is not in the response headers

I have called an API for login and the cookies from server is there in network section in dev-tools in google chrome. I am attaching the screenshots and the code for reference.
We are using dio package for the network.
Code
static Future<void> request({
required HttpMethod? method,
bool hideLoadingIndicator = false,
required String? path,
required Map? params,
required BuildContext context,
required OnResponse onResponse,
}) async {
try {
if (!hideLoadingIndicator) {
showLoading(context);
}
Response response;
switch (method) {
case HttpMethod.post:
response = await DioFactory.dio!.post(
path!,
options: Options(headers: {
HttpHeaders.contentTypeHeader: "application/json",
}),
data: params,
);
break;
case HttpMethod.delete:
response = await DioFactory.dio!.delete(
path!,
data: params,
);
break;
case HttpMethod.get:
response = await DioFactory.dio!.get(
path!,
);
break;
case HttpMethod.patch:
response = await DioFactory.dio!.patch(
path!,
data: params,
);
break;
case HttpMethod.put:
response = await DioFactory.dio!.put(
path!,
options: Options(headers: {
HttpHeaders.contentTypeHeader: "application/json",
}),
data: params,
);
break;
default:
return;
}
print("----whole response----->>>>>>>>> $response");
print("------rawCookies--->>>>>>>>> ${response.headers.map}");
if (!hideLoadingIndicator) {
hideLoading(context);
}
if (response.statusCode == 401) {
showSessionDialog(context);
} else if (response.data["success"] == 0) {
List errors = response.data['error'];
if (errors.isNotEmpty) {
// handleApiError(errors.first ?? "");
handleApiError(errors.first ?? "", context);
} else {
handleApiError("Something went wrong! Please try again.", context);
}
// handleApiError(response.data["error"]["message"]);
// onError!(response.data["error"][0], {});
} else {
onResponse(response.data);
// onResponse!(BaseResponse.fromJson(response.data));
}
} catch (e) {
if (!hideLoadingIndicator) {
hideLoading(context);
}
String errorMessage = "";
if (e is DioError) {
if (e.type == DioErrorType.connectTimeout ||
e.type == DioErrorType.sendTimeout ||
e.type == DioErrorType.receiveTimeout ||
e.type == DioErrorType.other) {
errorMessage = 'Server unreachable';
} else if (e.type == DioErrorType.response) {
if (e.response!.statusCode == 401) {
PrefUtils.clearPrefs();
} else {
final response = e.response;
List errors = response?.data['error'];
if (errors.isNotEmpty) {
errorMessage = errors.first;
} else {
errorMessage = "Something went wrong! Please try again.";
}
}
} else {
errorMessage = "Request cancelled";
}
} else {
errorMessage = e.toString();
}
handleApiError(errorMessage, context);
}
}
I am getting this errors and in the Applications tab the cookie is not stored and also not there in the response headers log you can see in the image.

Flutter: How to send multiple images using for loop

I am using http package to perform multipart request.I am trying to upload multiple images using for loop but I am not getting any idea how to do it following is my postman response in the below image you can see 2 fields one is attribute and another one is image here I want to loop only adhar and pan inside attributes after sending "mobileno":"4567654","role":"p","userstatus":"D", to database
following is my multipart request code
Future<void> insertCategory(String category, BuildContext context) async {
var flutterFunctions =
Provider.of<FlutterFunctions>(context, listen: false);
var data = {"mobileno":"4567654","role":"p","userstatus":"D","adhar":"adhar","pan":"pan"};
var url = PurohitApi().baseUrl + PurohitApi().insertcategory;
Map<String, String> obj = {"attributes": json.encode(data).toString()};
try {
loading();
final client = RetryClient(
http.Client(),
retries: 4,
when: (reponse) {
return reponse.statusCode == 401 ? true : false;
},
onRetry: (request, response, retryCount) async {
if (retryCount == 0 && response?.statusCode == 401) {
var accesstoken = await Provider.of<Auth>(context, listen: false)
.restoreAccessToken();
request.headers['Authorization'] = accesstoken;
print(accesstoken);
}
},
);
var response = await http.MultipartRequest('Post', Uri.parse(url))
..files.add(await http.MultipartFile.fromPath(
"imagefile", flutterFunctions.imageFile!.path,
contentType: MediaType("image", "jpg")))
..headers['Authorization'] = token!
..fields.addAll(obj);
final send = await client.send(response);
final res = await http.Response.fromStream(send);
var messages = json.decode(res.body);
loading();
print(messages);
} catch (e) {
print(e);
}
}
Future<Object> addUserImages(List<XFile> files, String userID, String token) async {
try {
var url = Uri.parse(API_BASE_URL + addUserImagesUrl);
var request = http.MultipartRequest("POST", url);
request.headers['Authorization'] = "Bearer ${StaticServices.userBaseModel!.token!.token}";
for (var i = 0; i < files.length; i++) {
String fileName = DateTime.now().microsecondsSinceEpoch.toString().characters.takeLast(7).toString();
var pic = http.MultipartFile.fromBytes("files", await File(files[i].path).readAsBytes(), filename: '${userID}_${i}_$fileName', contentType: MediaType("image", files[i].mimeType ?? "png"));
//add multipart to request
request.files.add(pic);
}
var response = await request.send();
var responseData = await response.stream.toBytes();
var responseString = String.fromCharCodes(responseData);
if (response.statusCode == 200) {
return Success(response: Images.fromJson(jsonDecode(responseString)));
}
return Failure(
errorMessage: responseString,
);
} on HttpException {
return Failure(errorMessage: "No Internet Connection");
} on FormatException {
return Failure(errorMessage: "Invalid Format");
} on SocketException {
return Failure(errorMessage: "No Internet Connection");
} catch (e) {
return Failure(errorMessage: "Invalid Error");
}
}

flutter error 403 in post request using dio

i have a problem with hate. I'm trying to login using dio, the login method works perfectly, but when I put invalid credentials dio gives me this error:
DioError
Error in execution
I created a boolean function that would return true or false if the statuscode was 200 it would return true and if not it would return false, but when logging in with the right credentials everything is ok, everything happens as it should, but when logging in with invalid credentials this error above causes it. I'm using shared preferences to store the tolken in the app, and the logic would be simple, if it was 200 I would log into the app, otherwise it would show me a snackbar I made in another file, this is my code:
loginFinal() async {
if (formKey.currentState!.validate()) {
bool loginIsOk = await loginConect();
if (loginIsOk) {
Get.offAllNamed("/home");
await Future.delayed(const Duration(seconds: 1));
message(MessageModel.info(
title: "Sucesso",
message: "Seja bem vindo(a) influenciador(a)",
));
} else {
loaderRx(false); //LOADER
message(MessageModel.error(
title: "Erro",
message: "Erro ao realizar login",
));
}
}
}
//LOGICA DE ENTRAR NO APP
Future<bool> loginConect() async {
final dio = Dio();
String baseUrl = "https://soller-api-staging.herokuapp.com";
loaderRx(true); //LOADER
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
final response = await dio.post(
baseUrl + "/auth",
data: jsonEncode(
{
"login": emailController.text,
"senha": passWordController.text,
},
),
options: Options(
headers: {'Content-Type': 'application/json; charset=UTF-8'},
method: "post",
),
);
if (response.statusCode == 200) {
await sharedPreferences.setString(
"token",
"string: ${response.data["string"]}",
);
print("Resposta: ${response.data["string"]}");
loaderRx(false);
return true;
} else {
print("RESPOSTA: ${response.data}");
return false;
}
}
}
Dio always throw an exception if the status code in the header is not 200,
you will need to catch the exception using try catch.
In the catch method, you can check if the type of the error is DioError and then handle that exception,
Here is a code snippet of a login process that I use in my code to handle this behavior.
Future<SignInApiResponse> signInUser(String _email,String _password) async {
try {
final dio = Dio(ApiConstants.headers());
final Response response = await dio.post(
ApiConstants.baseUrl + ApiConstants.signInUrl,
data: {"email": _email,
"password": _password,
},
);
if (response.statusCode == 200) {
return SignInApiResponse.fromJson(response.data);
} else {
return SignInApiResponse(message: response.toString());
}
} catch (e) {
if (e is DioError) {
if (e.response?.data == null) {
return SignInApiResponse(message: Messages.loginFailed);
}
return SignInApiResponse.fromJson(e.response?.data);
} else {
return SignInApiResponse(message: e.toString());
}
}
}
hopefully, this will help
if not you can always use http package that does not throw an exception in similer case

Trying to make a request with http in Flutter

I am trying to make a class in Flutter that can send requests to an API and then store the response inside the class, however every time I send a request I get some sort of infinite request that end up in timing out. Here is my code:
When the user press the button in the screen:
onPressed: () async {
print('Email: ${emailFieldController.text} and password: ${passwordFieldController.text}');
await Api.sendRequest('POST', '/session', {
"email": emailFieldController.text,
"password": passwordFieldController.text
});
if (Api.content.containsKey("error")) {
print("Error connectiong with API");
print("The error was:" + Api.content["error"].toString());
} else {
if (Api.content["status"] == 200) {
print("User find");
} else {
print("User not find");
}
}
})
The class that I built:
import 'dart:convert';
import 'package:http/http.dart';
class Api {
static final String baseURL = 'http://192.168.15.4/api/v1';
static Map content;
static Future<void> sendRequest(String method, String endpoint, [Map body, Map headers]) async {
Response response;
switch (method) {
case 'GET':
try {
response = await get('$baseURL' + endpoint);
Api.content = jsonDecode(response.body);
} catch (e) {
Api.content["error"] = e.toString();
}
break;
case 'POST':
try {
response =
await post('$baseURL' + endpoint, body: body, headers: headers);
Api.content = jsonDecode(response.body);
print('Passando depois POST');
} catch (e) {
Api.content["error"] = e.toString();
}
break;
case 'PUT':
try {
response =
await put('$baseURL' + endpoint, body: body, headers: headers);
Api.content = jsonDecode(response.body);
} catch (e) {
Api.content["error"] = e.toString();
}
break;
case 'DELETE':
try {
response = await delete('$baseURL' + endpoint, headers: headers);
Api.content = jsonDecode(response.body);
} catch (e) {
Api.content["error"] = e.toString();
}
break;
}
}
}
I also tried to alter the return type of the method, but got the same result.
So I discovered what was wrong, baseURL attribute was missing the port, so the request never found it's target. So in the and the baseURL value was: http://192.168.15.4:3333/api/v1

How to handle timeout error with Dio in Flutter?

I'm using Dio to handle APIs functions.
Here's my code:
Future<List<ItemModel>> getItems() async {
try {
Response response = await dio.get("$_apiUrl$_itemEndPoint",
options: Options(headers: {
"Accept": 'application/json',
}));
List<ItemModel> _items = List<ItemModel>();
response.data['data']?.forEach((c) {
_items.add(ItemModel.fromMap(c));
});
return _items;
} catch (e) {
throw (e);
}
}
How can I catch an error based on timeout of send and receive?
Manage timeout exception using dio :
ApiRepositary.dart
class ApiRepositary {
Dio dio;
ApiRepositary() {
if (dio == null) {
BaseOptions options = new BaseOptions(
baseUrl: "your base url",
receiveDataWhenStatusError: true,
connectTimeout: 60*1000, // 60 seconds
receiveTimeout: 60*1000 // 60 seconds
);
dio = new Dio(options);
}
}
Future<LoginResponse> getLoginDetails(var loginRequestData) async {
try {
Response response = await dio.post("/authenticate", data: loginRequestData);
final LoginResponse loginResponse = LoginResponse.fromJson(response.data);
return loginResponse;
}on DioError catch (ex) {
if(ex.type == DioErrorType.CONNECT_TIMEOUT){
throw Exception("Connection Timeout Exception");
}
throw Exception(ex.message);
}
}
}
Example of handle exception :
void checkLogin(){
LoginRequest loginRequest = new LoginRequest(
email: "abcd#gmail.com",password: "passs#123");
var requestBody =jsonEncode(loginRequest);
debugPrint("Request Data : $requestBody");
_apiRepositary.getLoginDetails(requestBody).then((response){
debugPrint("Login Success $response");
//manage your response here
},
onError: (exception){
//Handle exception message
if(exception.message != null ){
debugPrint(exception.message); // Here you get : "Connection Timeout Exception"
}
},
);
}
You to define DIO option first:
BaseOptions options = new BaseOptions(
baseUrl: "http://example.org",
connectTimeout: 5000,
receiveTimeout: 3000,
);
then:
Dio dio = new Dio(options);
var jsonNews = await dio.get(
'http://example.org/v2/everything?q=bitcoin&from=2020-01-24&sortBy=publishedAt&apiKey=7f3c604b6e2245c88se50lzx02dc9cac1e2');
Source :
https://pub.dev/packages/dio
Here's what I'm guessing by looking at one of their test files and their error class:
try {
await Dio().get("https://does.not.exist");
} on DioError catch (e) {
if (e.type == DioErrorType.connectTimeout) {
// ...
}
if (e.type == DioErrorType.receiveTimeout) {
// ...
}
}
you can use the try-catch for Timeout exception and the handle it on you basis