in short words I want to print in my console any Http request that my app is requesting without putting print command after each call I'm making for example :
let's say I have service with http.Client.get and I have another 100 service like that.
what I'm doing now is I'm waiting for the response in each service and then I'm printing it like this print('response is ' + response.body);.
what I want to achieve is that will be automatically be printed out for me without me writing print 100 times in after each request I'm making, any good architect would you recommend to follow ?
hope I cleared the idea well.
You can try the http_interceptor package which allows you to catch all the requests & responses from your http requests (change headers, params etc..)
If you add LogInterceptor, Request and Response URLs and request body are printed. Try ...
final logInterceptor = LogInterceptor(
requestBody: true,
responseBody: true,
error: false,
requestHeader: true,
responseHeader: true);
..interceptors.add(logInterceptor)
well here is my last approach for this.
for every one is seeking for making it with abstraction or let's say wrapping;
first what I did is kind if wrapping for the HTTP class and used my class everywhere instead of the original Http Class.
so the code would go like this
class MHttpClient {
final http.Client client;
final SharedPreferences sharedPreferences;
MHttpClient(this.client, this.sharedPreferences);
Future<http.Response> get(
{String path = "", Map<String, String> extraHeders}) async {
printWrapped('get Path: $path');
final response = await client.get(
Uri.parse(getBaseURL() + Version + path),
headers: getHeaders(extraHeaders: extraHeders),
);
printWrapped("get response : \n" + utf8.decode(response.bodyBytes));
return response;
}
Future<http.Response> post(
{String body = "",
String path = "",
Map<String, String> extraHeders}) async {
printWrapped('sended body: \n');
printWrapped(' ${json.decode(body)}');
final response = await client.post(
Uri.parse(getBaseURL() + Version + path),
body: body,
headers: getHeaders(extraHeaders: extraHeders),
);
printWrapped("post response : \n" + utf8.decode(response.bodyBytes));
return response;
}
Future<http.Response> put({String body = "", String path = ""}) async {
printWrapped('put body: \n ${json.decode(body)}');
final response = await client.put(
Uri.parse(getBaseURL() + Version + path),
body: body,
headers: getHeaders(),
);
printWrapped(utf8.decode(response.bodyBytes));
return response;
}
Future<http.Response> putImage({File image, String path = ""}) async {
printWrapped('Image Path: $path');
final response = await http.put(
Uri.parse(path),
headers: getImageHeaders(),
body: image.readAsBytesSync(),
);
return response;
}
String getBaseURL() {
if (Foundation.kDebugMode)
return BaseURLSTAGING;
else
return BaseURL;
}
String getApiKey() {
if (Foundation.kDebugMode)
return ApiKeyStaging;
else
return ApiKey;
}
String getToken() {
String cashedToken = sharedPreferences.getString(CACHED_TOKEN);
if (cashedToken == null) cashedToken = "";
return cashedToken;
}
Map<String, String> getHeaders({Map extraHeaders}) {
Map<String, String> headers = {
'Content-Type': 'application/json; charset=UTF-8',
'x-api-key': getApiKey(),
HttpHeaders.authorizationHeader: 'Bearer ' + getToken(),
};
if (extraHeaders == null || extraHeaders.isEmpty)
return headers;
else {
headers.addAll(extraHeaders);
return headers;
}
}
Map<String, String> getImageHeaders() {
return <String, String>{'Content-Type': 'image/png'};
}
void printWrapped(String text) {
final pattern = RegExp('.{400}'); // 800 is the size of each chunk
pattern.allMatches(text).forEach((match) => developer.log(match.group(0)));
}
}
and then I used MHttpClient else where
final MHttpClient client;
final response = await client.get(path: path);
and in this case I don't have to warry about anything else ,
and when you need to change one thing you will change it in one place only, and every thing will stay the same and work as you want without braking changes you have to do for all you requested.
Related
I have an api_service.dart file and when the user logs in I save the json.decode(response.body)['key'] in a variable as Tkey. I want to be able to access it in the same file but in a different function when I am trying to access user details:
I am not sure how to apply this answer How to pass access token value in flutter to my code
class APIService {
static var client = http.Client();
static Future<bool> login(
LoginRequestModel model,
) async {
Map<String, String> requestHeaders = {
'Content-Type': 'application/json', };
var url = Uri.parse(
Config.apiURL + Config.loginAPI, );
var response = await client.post(
url,
headers: requestHeaders,
body: jsonEncode(model.toJson()), );
if (response.statusCode == 200) {
await SharedService.setLoginDetails(
loginResponseJson(
response.body, ), );
print("No.2 Test ${response.body}"); <-------{"key":"xxxxxxxxxx"}
var Tkey = json.decode(response.body)['key'];
print("No.2 Test $Tkey"); <-------------- xxxxxxxxxxxxx
return true;
} else {
return false; } }
static Future<User> fetchUser() async {
var url = Uri.parse(Config.apiURL + Config.userProfileAPI);
final response = await http.get(
url,
headers: {
HttpHeaders.authorizationHeader:
'Token $Tkey', <--------------- I want to print here the value of the key
}, );
final responseJson = jsonDecode(response.body);
print(responseJson);
if (response.statusCode == 200) {
return User.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load User');
} }}
My question how can I get access to the key to be used in the fetchUser() ?
Declare a global variable in the global scope or in a separate file, then when this method is executing, assign that key to it, then use it everywhere else in your app.
in a separate file:
String GlobalTkey = "";
now in your method replace the following:
print("No.2 Test ${response.body}"); <-------{"key":"xxxxxxxxxx"}
var Tkey = json.decode(response.body)['key'];
print("No.2 Test $Tkey"); <-------------- xxxxxxxxxxxxx
with this:
print("No.2 Test ${response.body}"); <-------{"key":"xxxxxxxxxx"}
var Tkey = json.decode(response.body)['key'];
GlobalTkey = Tkey; // you need to import the file where the variable exists
print("No.2 Test $Tkey"); <-------------- xxxxxxxxxxxxx
now everywhere in your app including different files, methods, widgets, classes... you can use GlobalTkey
Referring to this article
https://medium.com/solidmvp-africa/making-your-api-calls-in-flutter-the-right-way-f0a03e35b4b1
I was trying to call API from a flutter app. But to make it the right way, I was looking for a complete example and came here. My question is why do I need to create an ApiBaseHelper class then RepositoryClass then all other formalities to call an API. Why can't I use FutureBuilder and a simple async function associated with the API like this:
class Networking {
static const BASE_URL = 'https://example.com';
static Future<dynamic> getProductById({
required String? token,
required String? productId,
}) async {
final url = Uri.parse('$BASE_URL/products/$productId');
final accessToken = 'Bearer $token';
Map<String, String> requestHeaders = {
'Authorization': accessToken,
'Content-Type': 'application/json'
};
try {
final response = await http.get(
url,
headers: requestHeaders,
);
if (response.statusCode != 200) {
throw Exception('Error fetching data.');
}
final responseJSON = json.decode(response.body);
if (responseJSON['error'] != null) {
return throw Exception(responseJSON['error']);
}
final product = Product.fromJson(responseJSON);
return product;
} catch (e) {
throw Exception(e.toString());
}
}
}
And then calling it from a FutureBuilder like this:
FutureBuilder(
future: Networking.getProductById(token, id),
builder: (context, snapshot) {
// rest of the code
}
)
Can anyone tell me what is the most convenient and widely used way to call an API?
I have an app which is using http request for php server.
But I have a problem here.
Future<List<Photo>> fetchPhotos(http.Client client) async {
final response =
await client.get(Uri.parse('https://meshcurrent.online/get_1userdrive.php'));
// Use the compute function to run parsePhotos in a separate isolate.
return compute(parsePhotos, response.body);
}
// A function that converts a response body into a List<Photo>.
List<Photo> parsePhotos(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
}
I have a code like this. I am getting datas from the server. But I want to send a value to php server. and get datas depend on the value.
For instance, I will send username to the php server and I will get the datas about the username parameter. My php codes works but the problem is in flutter code.
Thanks for your helps
If youre tryting to send parameters over a get, you could use something like:
Future<List<Photo>> fetchPhotos(http.Client client) async {
final response = await client
.get(Uri.parse('https://meshcurrent.online/get_1userdrive.php?userId=5'));
if (urlCallResponse.statusCode == 200) {
// Use the compute function to run parsePhotos in a separate isolate.
return compute(parsePhotos, response.body);
} else {
...
}
}
// A function that converts a response body into a List<Photo>.
List<Photo> parsePhotos(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
}
Here is an example on how to do a post:
final response = await post(
Uri.parse(
'http://.../PostCall'),
headers: {
'authorization': getBasicAuth(username, password),
'Content-type': 'application/json',
'Accept': 'application/json',
},
body: json.encode(jobFormValue),
);
if (response.statusCode == 200) {
}
getBasicAuth function:
String getBasicAuth(String username, String password) {
return 'Basic ${base64Encode(utf8.encode('$username:$password'))}';
}
I am creating a flutter app using GetX, for making server connections I am using GetConnect, I successfully integrated the Get Request but I am unable to integrate Post Request
Here is the piece of code:
const _baseUrl = 'https://support.instagram.com/'; // Dummy api url and key
const Map<String, String> _mapHeaders = {
"ISG-API": "ZMWFDK83NMDF7NM5DF23FI0DBUJ"
};
class ApiService extends GetConnect {
Future<TicketReply> submitTicketReply(String ticketId, String tktreply) async {
String apiUrl = '${_baseUrl}/supportreply';
var body = {
'tktid': ticketId,
'tktreply': tktreply,
};
final response = await post(
apiUrl,
body,
headers: _mapHeaders,
);
print('response: ${response.body}');
if (response.statusCode == 200) {
return TicketReply.fromJson(response.body);
} else {
return Future.error(response.statusText!);
}
}
}
Kindly guide me how to make a successful post request using getconnect
You should add the decoder to the request like so
await post(
apiUrl,
body,
headers: _mapHeaders,
decoder: (resbody) => TicketReply.fromJson(resbody),
);
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;
}
}