How to implement try statement when sending http request? - flutter

I want to create a login method to post http request. I use the following code to post user data into the server and get a response:
import 'dart:convert';
import 'dart:html';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../Services/baseHttp.dart' as base;
class Services {
late var token = '';
Future<http.Response> login(String username, String password) async {
var url = base.BaseURL.loginUrl;
Map data = {"username": username, "password": password};
var body = json.encode(data);
var response = await http.post(Uri.parse(url),
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: body);
print(response.statusCode);
token = response.body;
print(token);
return response;
}
}
I tried to use try catch inside the method:
Future<http.Response> login(String username, String password) async {
try {
var url = base.BaseURL.loginUrl;
Map data = {"username": username, "password": password};
var body = json.encode(data);
var response = await http.post(Uri.parse(url),
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: body);
print(response.statusCode);
token = response.body;
print(token);
return response;
} catch (e) {
print(e);
}
}
I want to send statusCode instead of print(e) when any exception is thrown. How can I do that?

To check whether a response is valid, you can check the status code if it's equal to 200 like this:
if (response.statusCode == 200){
// Do something
} else {
// Throw exception
}
Taking a look the official documentation. You will see the following:
Future<Album> fetchAlbum() async {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}

Related

Flutter http post request gives status code 401

I am using API to verify phone number provided by user.... on postman api give perfect response and give OTP code in response but in flutter status code 401 is returned
here is my code
Future verifyPhone(String phoneNumber) async {
try {
String token = "528724967b62c6c9e546aeaee1b57e234991ad98";
var body = <String, String>{};
body['user_number'] = phoneNumber;
var url = Uri.parse(ApiKeys.phoneVerifyApiKey);
var response = await http.post(
url,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"authentication": "Bearer $token"
},
body: body,
);
if (response.statusCode == 200) {
print("Code sent");
} else {
print("Failed to send code");
print(response.statusCode);
}
} catch (err) {
print(err.toString());
}
notifyListeners();
}
instead of "code sent" i get "failed to send code" and status code 401
EDIT
You can send form request this way
Future verifyPhone(String phoneNumber) async {
try {
String token = "528724967b62c6c9e546aeaee1b57e234991ad98";
var body = <String, String>{};
body['user_number'] = phoneNumber;
var url = Uri.parse(ApiKeys.phoneVerifyApiKey);
var headers ={
"Content-Type": "application/x-www-form-urlencoded",
"authentication": "Bearer $token"
};
var request = http.MultipartRequest('POST', url)
..headers.addAll(headers)
..fields.addAll(body);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print("Code sent");
} else {
print("Failed to send code");
print(response.statusCode);
}
} catch (err) {
print(err.toString());
}
notifyListeners();
}
EDIT
To access :
var _data = jsonDecode(response);
var list = _data["data"];
print(list[0]['otp_code']);

Common method for flutter api calls

Is there any example that I can refer to about Common class/method for flutter API calls(GET,POST,...) in flutter? I have handled all the API requests in a common method in react native, I'm not sure how to implement it in flutter.
you have to call getRequest using url parameter
Future<Response> getRequest(String url) async {
Response response;
try {
response = await _dio.get(url,
options: Options(headers: {
HttpHeaders.authorizationHeader:
'Bearer $accessToken'
}));
print('response $response');
} on DioError catch (e) {
print(e.message);
throw Exception(e.message);
}
return response;
}
here is the post method
Future<Response> posRequestImage(String url, data) async {
try {
response = await _dio.post(
url,
data: formData,
options: Options(headers: {
HttpHeaders.authorizationHeader:
'Bearer $accessToken'
}),
);
if (response.statusCode == 200) {
return response;
}
print('post response $response');
} on DioError catch (e) {
print(e.message);
throw Exception(e.response?.statusMessage);
}
return response;
}
You can create a class to handle it. For example, this is my class to handle all service for user model
import 'package:http/http.dart' as http;
class UserService {
var baseUrl = URL.devAddress;
Future<User> getUser() async {
final response = await http.get(
Uri.parse(baseUrl + "user/1")
);
if (response.statusCode == 200) {
final data = json.decode(response.body);
return data
} else {
throw Exception("Failed");
}
}
}
Future<void> getUser(String username) async {
Uri uri = Uri.parse('https://example.com');
try {
Map<String, dynamic> params = new HashMap();
params['username'] = username;
final response = await client.post(uri,
body: jsonEncode(params),
);
print("response ${response.body}");
} on FetchDataException {
throw FetchDataException("No Internet connection");
}
}

How to refresh token and retry request on 401 error using Flutter

I try to refresh token and retry request on 401 error, but can not understand how to do it by right way
This is a recreation from what I remember so there can be typo and small errors maybe.
I hope you get an idea what I am trying to do here.
import 'package:http/http.dart' as http;
class APIUtility {
Uri uri;
String path, method;
var body;
var headers;
APIUtility({ #required this.path, #required this.method, this.body}) {
this.uri = Uri.parse("http://localhost:4000/api/${this.path}");
this.headers = {'Content-Type': 'application/json'};
}
Future request({ bool useToken = true }) async {
http.Response response;
if ( useToken ) { this.header['token'] = await getAccessToken(); }
try {
response = await // call api with http package with correct path, method and body
if ( useToken && response.statusCode == 401 ) return await _refreshTokenAndRequest();
else return jsonDecode(response.data);
}
catch (e) {
print(e);
return null;
}
}
_refreshTokenAndRequest() async {
String accessToken = await getAccessToken();
String refreshToken = await getRefreshToken();
var body = {'access_token': accessToken, 'refresh_token': refreshToken};
http.Response response = await http.post("${this.baseUrl}/api/auth/refresh", body: body);
if (response.statusCode == 200 || response.statusCode == 201) {
saveAccessToken(response.body['access_token']);
saveRefreshToken(response.body['refresh_token']);
return await request();
} else {
// Logout user from app
// Delete all database, token and all user info and show login screen;
return null;
}
}
}

how to post form data request using flutter in http package

I want to send form data in flutter using the HTTP package. Getting the error:FormatException: Unexpected character (at character 1)
I/flutter (30465):
I am sending the form data in the HTTP post request.
Future<void> authethicate(
String schoolName,
String password,
) async {
try {
final url = 'https://yobimx.com/citykey/api/users/login';
final response = await http.post(url, body: {
'email': 'usamashafiq199#outlook.com',
'password': '123',
}, headers: {
"Content-Type": "application/x-www-form-urlencoded",
});
print(
json.decode(response.body),
);
final responseData = json.decode(response.body);
} catch (error) {
print(error);
}
}
I have to use a multipart request for request. Thanks for your help.
Future<void> authethicate(
String schoolName,
String password,
) async {
try {
final url = Uri.parse('https://yobimx.com/citykey/api/users/login');
Map<String, String> requestBody = <String, String>{
'email': 'usamashafiq199#outlook.com',
'password': '123'
};
var request = http.MultipartRequest('POST', url)
..fields.addAll(requestBody);
var response = await request.send();
final respStr = await response.stream.bytesToString();
print(
jsonDecode(respStr),
);
print("This is the Status Code$respStr");
var encoded = json.decode(respStr);
print(encoded['status']);
print('This is the userId${encoded['data']['user_id']}');
} catch (error) {
print(error);
}
}

Register to aqueduct backend from Flutter frontend

I'm having a bit of difficulty with registering to aqueduct backend from my Flutter frontend
Here is my code in my frontend:
Future<void> signUp(String email, String password) async {
final body = "username:$email,password:$password"; //<- return request entity could not be decoded
//final body = {"username": email, "password": password}; //<- return bad state: Cannot set the body fields of Request with content-type "application/json"
try {
final http.Response response = await http.post(
"http://localhost:8888/register",
headers: {"Content-Type": "application/json"},
body: body);
final jsonResponse = json.decode(response.body);
if (jsonResponse["error"] != null) {
throw HttpException(jsonResponse["error"]);
}
} catch (error) {
throw error;
}
}
There must be some silly mistake. I believe it is with formatting body so I tried 2 options and both throw different http exception (as in comment).
Here is an example of connecting to an Aqueduct server from a Flutter client. (This isn't really a server question, though, since the client and server are independent of each other.)
Here is an example of registering:
void _register(String email, String password) async {
Map<String, String> headers = {"Content-type": "application/json"};
final jsonString = '{"username":"$email", "password":"$password"}';
Response response = await post(YOUR_URL_HERE, headers: headers, body: jsonString);
print('${response.statusCode} ${response.body}');
}
In your example you aren't encoding the JSON correctly.
And here is another example of signing in. The class is a view model architecture that I talk about here.
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
class LoginViewModel extends ChangeNotifier {
String _token = '';
bool _isLoggedIn = false;
bool get isLoggedIn => _isLoggedIn;
String get token => _token;
Future onLoginPressed(String username, String password) async {
if (username.isEmpty || password.isEmpty) {
return;
}
_isLoggedIn = await _login(username, password);
notifyListeners();
}
Future<bool> _login(String username, String password) async {
var clientID = 'com.example.app';
var clientSecret = '';
var body = 'username=$username&password=$password&grant_type=password';
var clientCredentials = Base64Encoder().convert('$clientID:$clientSecret'.codeUnits);
Map<String, String> headers = {
'Content-type': 'application/x-www-form-urlencoded',
'authorization': 'Basic $clientCredentials'
};
var response = await http.post(YOUR_URL_HERE, headers: headers, body: body);
final responseBody = response.body;
if (response.statusCode != 200) {
return false;
}
final map = json.decode(responseBody);
_token = map['access_token'];
return true;
}
}