I am trying to make this GET request in my app but I am not sure how to go about it as I'm fairly new to flutter/dart.
I have successfully made a POST request to log in and now I am trying to make this GET request to display the messages in this message board in my app. That can come later as I am trying to complete the GET request first.
Preferably the GET request should be in a method which I can use in a button; each will be in messageBoard_Page.dart
This is the request URL that I am trying to reach.
and this is the Request Header
for reference this is the response that I am getting from my Login POST method
{
"RESPONSE":{
"login_request_result":{
"user_must_change_password":"0"
},
"BASEL_RESPONSE":{
"UserDate":"0",
"UserTime":"0",
"UserName":"Administrator",
"module_config_1":"0",
"module_config_2":"0",
"ErrEntity":{
"MessageID":"0",
"last_req_id":"50029",
"table_id":"0",
"key_id_list":"536871",
"operation_id":"0"
},
"is_csv":"0",
"VersionName":"DYMA # 6.1.24.0, ORG # 2017.3.22.15.0.41, GRC # 2017.3.22.15.0.55, LDC # 2017.3.22.15.1.8, DYMA_XML # 2017.3.22.15.0.30, NAS # 2017.3.22.15.1.22 - Config: 0 - Node: OPRISK_DATACOLLECTOR",
"ExpiryDate":"31/01/2030",
"count_key":"0",
"id_Us":"1",
"is_popup":"0",
"tot_messages":"0",
"my_messages":"0",
"product":"0"
},
"RESPONSE_HEADER":{
"SessionID":"VtVQIdERO-206868772kpwAXF0001",
"NomeRichiesta":"LOGIN_REQUEST",
"ltimeStart":"22262791",
"ltimeStop":"22262813",
"ldate_null":"19900101",
"product":"1",
"server_name":"OPRISK_DATACOLLECTOR",
"cell_context_id":"537945",
"operation_key":"1000000",
"operation_sub_num":"-1"
}
}
}
and this is my Login POST Method in login_Page.dart
void sendLogin() async {
var map = <String, dynamic>{
"UserName": _usernameController.text,
"Password": _passwordController.text,
};
var res = await http.post(
Uri.parse("http://192.168.1.8:8080/HongLeong/LOGIN_REQUEST.do"),
body: map,
);
final data = jsonDecode(res.body);
final String userSessionID = (data as Map)['RESPONSE']['RESPONSE_HEADER']['SessionID'];
print(res.statusCode);
print(res.body);
await WriteCache.setString(key: "cache", value: userSessionID);
if ((data as Map)['RESPONSE']['login_request_result'] == null) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Center(child: Text('Invalid Username/Password')),
actions: <Widget>[
Center(
child: TextButton(
onPressed: () {
_usernameController.clear();
_passwordController.clear();
Navigator.of(ctx).pop();
},
child: const Text('Ok'),
),
),
],
),
);
} else {
Navigator.push(context,
MaterialPageRoute(builder: (context) => const DashboardPage()));
}
}
please ignore the messiness as Im trying to achieve the GET method as of now.
Any help is appreciated. Thank You.
ps. if the images are too small, I am not sure how else to show the request URL and header, sorry.
To make a get request its very much similar to the post you created. Just remove the body and change the request type
var res = await http.get(
Uri.parse("The url for getting the respose through get method here")
);
Rest everything stays the same.
Related
I have a problem with exception handling, I build the product manager app in which I use firebase rest API to post the data to the server, And use the exception if by chance any error occur then redirect to the home screen. But if any error occurs then it will only show the loading spinner so what is the problem here and Also tell that how the exception and future work here?
If there is a problem in url then it will show the alert dialog and show error message and after that it will show loading spinner but according to the code after catchError it will return future then it means next then block content should run but that doesn't work so what is the behavior behind this?
The function which has post method
Future<void> addProduct(Product product) {
const url =
'';
return http
.post(
Uri.parse(url),
body: json.encode(
{
'title': product.title,
'description': product.description,
'price': product.price,
'imageUrl': product.imageUrl,
'isFavorite': product.isFavorite,
},
),
)
.then(
(response) {
final id = json.decode(response.body)['name'];
final newProduct = Product(
id: id,
title: product.title,
description: product.description,
price: product.price,
imageUrl: product.imageUrl,
);
_items.add(newProduct);
notifyListeners();
},
).catchError(
(error) {
print(error.toString());
throw error;
},
);
}
Code which is used in fronted
Provider.of<Products>(context, listen: false)
.addProduct(_editedProduct)
.catchError((error) {
return showDialog(
context: context,
builder: (ctx) {
return AlertDialog(
title: const Text('An Error Occured!!'),
content: const Text('Something went wrong'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Okay'),
)
],
);
});
}).then((_) {
setState(() {
_isLoding = false;
});
Navigator.of(context).pop();
});
}
}
the issue you mentioned is that the loading spinner is not being shown after the alert dialog is displayed. This is because the then block after catchError is not being executed. This is because the error is being re-thrown in the catchError block and not being caught by the catchError block in the front-end code. To fix this, you need to catch the error in the catchError block in the front-end code, for example by adding a try-catch statement around the call to addProduct.
I want to upload an image that I have already retrieved from the database(product table) to the cart table.
The issue is, I can't use the .path with the MultipartFile("file", image.path);
I am getting an error if I try using .path with my image variable. I've also tried several methods but none is working... I'll attach my codes below
The image is already stored in a map(revievedMap) which I receivr from the previous screen so I'm not using an imagePicker, the product image I'm trying to access is already stored in the database.
request.fields['image'] = "http://10.0.2.2:/shopice/assets/${args.product.image}";
request.fields['image'] = "http://localhost:/shopice/assets/${args.product.image}";
I tried the code above, obviously didn't work.
var pic = await http.MultipartFile.fromPath("image", args.product.image!);
//request.files.add(pic);
I also tried this, but I need to set the path on the second argument, but args.product.image.path(), is returning this error
[the getter 'path' isn't defined for the type 'String'. (Documentation) Try importing the library that defines 'path', correcting the name to the name of an existing getter, or defining a getter or field named 'path'.]
here is the code:
//args.receivedMap: is my buyer detials
//args.product: is the product i'm trying to add to cart, which //contains the image
args.seller: is the seller details
child: FlatButton(
onPressed: ()async {
if(!args.receivedMap.isEmpty){
final uri = Uri.parse("http://10.0.2.2:/shopice/api/buyer/addToCart");
var request = http.MultipartRequest('POST', uri);
request.fields['buyer_id'] =args.receivedMap['id'];
request.fields['seller_id'] = args.seller.id.toString();
request.fields['seller_name'] = args.seller.name!;
request.fields['buyer_name'] = args.receivedMap['name'];
request.fields['price'] = args.product.pricePerKg!;
request.fields['product_name'] = args.product.name!;
//request.fields['image'] = "http://10.0.2.2:/shopice/assets/${args.product.image}";
//var pic = await http.MultipartFile.fromPath("image", "http://localhost:/shopice/assets/${args.product.image}");
//File file = "http://10.0.2.2:/shopice/assets/${args.product.image}" as File;
//var pic = await http.MultipartFile.fromString("image", args.product.image!);
//request.files.add(pic);
var bytes = (await rootBundle.load('http://localhost/shopice/assets/${args.product.image}')).buffer.asUint8List();
var mpFile = http.MultipartFile.fromBytes('img', bytes);
request.files.add(mpFile);
var response = await request.send();
print(args.product.image);
if (response.statusCode == 200) {
showModalBottomSheet(context: context, builder: (context){
return Wrap(children: [ListTile(leading: Icon(Icons.done_outline), title: Text('Product Added TO Cart'),)],);
});
}
else if (response.statusCode == 500) {
showModalBottomSheet(context: context, builder: (context){
return Wrap(children: [ListTile(leading: Icon(Icons.done_outline), title: Text('Server Error '),)],);
});
}
else {
showModalBottomSheet(context: context, builder: (context){
return Wrap(children: [ListTile(leading: Icon(Icons.done_outline), title: Text('ERROR WHILE PERFORMING OPPERATION\n CONTACT SUPPORT'),)],);
});
}
}
else if(args.receivedMap.isEmpty){
var snackbar = SnackBar(
content: Text('Login To Add Product To Cart!',
style: TextStyle(fontSize: 16.0)),
backgroundColor:
const Color(0xff4A777A),
padding: EdgeInsets.only(left: 50.0),
);
ScaffoldMessenger.of(context)
.showSnackBar(snackbar);
}
},
child: Text(
'Add to Cart',
style: GoogleFonts.poppins(
color: Color(0xff4A777A)),
)),
i simply add the image from the backend and forget about doing it with flutter, i moved the image with php and did some trial and error which later worked
So i in the fetching of data I have basic auth, so for the first time that the user logs in I need to take the basic authentication like value which is normally like : Basic (then some numbers), so I need to take that and store that inside the local storage. T
he reason why I need to do this is that the next screen after login is going to be a screen where data is being fetched, so I need to save the basic auth token inside the local storage so when the user closes the app and comes back I can pass the basic auth token and get the data from the API.
On the app the authorization is from the response. statusCode, so in order to get data from API I need. So what I require is for the first time the first screen will be the login screen, when the user successfully logs in, we need to get the basic auth token save it on local storage, then use that same token on basic auth, so the data is returned to the other screen successfully, and in 'authorization': basicAuth.toString(), we can do like boolVariable ? prefs.getString('keyName') : basicAuth.toString().
Any help would be really appreciated, and when you guys explain implementation of the code would be even better.
// dataset_Working_Location.dart
late Response response2;
TextEditingController emailController = TextEditingController();
TextEditingController passwordController = TextEditingController();
String? basicAuth;
Future<Response> fetchWorkingLocationData() async {
var url = 'https://dev.api.wurk.skyver.co/api/locations';
basicAuth = 'Basic ' +
base64Encode(
utf8.encode('${emailController.text}:${passwordController.text}'),
);
response2 = await http.get(
Uri.parse(url),
headers: <String, String>{'authorization': basicAuth.toString()},
);
return response2;
}
//dataset_employees.dart
late Response response1;
Future<Response> fetchAccountData() async {
var url = 'https://dev.api.wurk.skyver.co/api/v1/employees/account';
response1 = await http.get(
Uri.parse(url),
headers: <String, String>{'authorization': basicAuth.toString()},
);
return response1;
}
//login submit button
ElevatedButton(
onPressed: () async {
if (_formKey.currentState!.validate()) {
setState(() {
loading = true;
});
Future<Response> futureResponse = fetchWorkingLocationData();
futureResponse
.then((response) => {
if (response.statusCode == 200)
{
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Page1()),
)
}
else
{
setState(() {
try {
loading = false;
} on Exception catch (e, s) {
loading = true;
}
}),
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
backgroundColor: Colors.blue,
content: Text(
"Incorrect phone number or password",
style: TextStyle(fontSize: 18),
),
duration: Duration(seconds: 4),
),
),
},
})
.catchError((error, stackTrace) => print('shush'));
}
fetchAccountData();
},
Have you considered storing values in DevicePreferences? This is a simple process (irrespective of your decision to persist information on disk/files).
I create a login page. in that page if userId and password is incorrect, then it will show toast or snackbar.
though i tried myself, but i don't know, how to check my userid and password is correct or incorrect based on api?
**here is login button **
child: RaisedButton(
child: Text('Login'),
onPressed: () {
String _email = _emailController.text.trim();
String _password = _passwordController.text.trim();
setState(() {
_futureAlbum = createAlbum(
_emailController.text,
_passwordController.text);
});
if(){
// in this section i want to check email id and password comparing from api request
}
},
color: Colors.green,
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
),
Here is Api Request
Future<Album> createAlbum(String employee_custom_id, String password) async {
final response = await http.post(
Uri.parse('https://portal-api.jomakhata.com/api/auth/login'),
headers: <String, String>{
'Content-Type': 'application/json',
},
body: jsonEncode(<String, String>{
'employee_custom_id': employee_custom_id,
'password': password,
}),
);
final data = json.decode(response.body);
if (response.statusCode == 200) {
saveToken(data);
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (BuildContext context) => Main()),
(Route<dynamic> route) => false);
log('$data');
return Album.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to create album.');
}
}
this is api response
{token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjI5MDAsImlzcyI6Imh0dHBzOi8vcG9ydGFsLWFwaS5qb21ha2hhdGEuY29tL2FwaS9hdXRoL2xvZ2luIiwiaWF0IjoxNjMwNjk4MTY3LCJ..., message: success, userId: 2900, passwordChanged: yes}
I don't know if you're building the API yourself or have a say in how it is built. That said, please do not perform password checks on the frontend or return a user's password via an API. Doing so will expose your app to security attacks. Here's why:
A user can circumvent this process and call the API directly
You are potentially exposing the user's actual password by fetching it from the API
This logic is usually handled at the backend where the API sends you a response based on whether the details entered are correct or not. Please let me know if you have any other questions.
You can check if your userId and password are correct based on the API response.
If the userId and password are correct you should get a status code of 200 as usual.
However, if the userId or password is incorrect you should get a 403 status code.
From the above, anytime the status code is not 200 it means the userId or password is incorrect, you can then display the toast.
I created an app, which contains login and dashboard screen, i used Nodejs backend and mongodb also. i trying to add functionality when user logged in and close the app without logging out and then when user come to the app it should display where it left last time. so i used shared preference for it. I am testing it now, when i logged in and close the app using the right-most button (which shows all the currently running apps) it send me this "Lost connection to device.
".
login Code:
bool newuser;
String type ;
SharedPreferences myPrefs;
void initState() {
checkIfLoggedinalready();
}
Future login() async {
try {
Dio dio = new Dio();
var data = {
'username':"Munib khatri",
'password': "Munib123",
'date': "5/5/2021"
};
await dio
.post(localhostUrlLogin, data: json.encode(data))
.then((onResponse) async {
type = onResponse.data['User']['Type'];
if (type == 'Employee') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Employee()));
} else if (type == 'Manager') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Manager()));
}
myPrefs.setBool('login', false);
});
} catch (e) {
}
}
void checkIfLoggedinalready() async{
myPrefs = await SharedPreferences.getInstance();
newuser = (myPrefs.getBool('login') ?? true);
print(newuser);
if (newuser == false && type == 'Employee') {
Navigator.pushReplacement(
context, new MaterialPageRoute(builder: (context) => Employee()));
}
}
dashboard code:
i am doing this on drawer code where i use logout
new ListTile(
title: new Text('Log out'),
leading: Icon(Icons.logout,color:Colors.grey),
onTap: (){
myPrefs.setBool('login', true); //here i set it to true, if user is new
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=>
Login()
)
);
},
),
please help it would be appreciated.
Lost connection to device is not a coding issue, your linked device got disconnected at that time due to data cable, If you will test this on emulator then you will not get this issue.
If you are saving user data on Shared preference then do encode your sensitive data before saving it.
var response =
await http.post(Uri.parse(parseUse), body: json.encode(data), headers: { "Content-Type": "application/json; charset=UTF-8", }).timeout(Duration(minutes: 2));
Updated Answer :
try{
Dio dio = new Dio();
var data = {
'username':"Munib khatri",
'password': "Munib123",
'date': "5/5/2021"
};
await dio
.post(localhostUrlLogin, data: json.encode(data))
.then((onResponse) async {
type = onResponse.data['User']['Type'];
if (type == 'Employee') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Employee()));
} else if (type == 'Manager') {
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Manager()));
}
myPrefs.setBool('login', false);
});
}on DioError catch (e){
if(e.type == DioErrorType.connectTimeout){
"You can put a alert dialog or something you prefer".
}
}
or you can also use base Option since your using DIO
var dio = Dio(); // with default Options
// Set default configs
dio.options.baseUrl = 'https://www.xx.com/api';
dio.options.connectTimeout = 5000; //5s
dio.options.receiveTimeout = 3000;
// or new Dio with a BaseOptions instance.
var options = BaseOptions(
baseUrl: 'https://www.xx.com/api',
connectTimeout: 5000,
receiveTimeout: 3000,
);
Dio dio = Dio(options);
response = await dio.request(
'/test',
data: {'id':12,'name':'xx'},
options: Options(method:'GET'),
);