How to log http requests in flutter - dart

I am developing an app with flutter and I am using default http package in dart for making API calls. How do we log all the http requests which are going through. Is there any in built feature in http or middleware available for the same?

There doesn't seem to be a built-in way to log request. However, you can implement your own Client to log request:
class MyClient extends BaseClient {
MyClient(this.delegate);
final Client delegate;
Future<StreamedResponse> send(BaseRequest request) {
_logRequest(request);
return delegate.send(request);
}
void close() => delegate.close();
void _logRequest(BaseRequest request) => ....;
}

Just debugging solution as is
class LoggableHttpClient extends BaseClient {
final Client _delegate;
final Logger _logger;
LoggableHttpClient(this._delegate, this._logger);
#override
void close() {
_delegate.close();
}
#override
Future<StreamedResponse> send(BaseRequest request) async {
String s = "${request.method} ${request.url} -->";
s += "\nheader: ${request.headers}";
if(request is Request && request.body.length>0) {
s += "\nbody: ${request.body}";
}
_logger.info(s);
final response = await _delegate.send(request);
s = "${request.method} ${request.url} <--";
s += "\nheader: ${response.headers}";
// Simple request
if(request is Request) {
final List<int> bytes = await response.stream.toBytes();
s += "\nbody: ${await utf8.decode(bytes)}";
_logger.info(s);
return StreamedResponse(
ByteStream.fromBytes(bytes),
response.statusCode,
contentLength: response.contentLength,
request: request,
headers: response.headers,
isRedirect: response.isRedirect,
persistentConnection: response.persistentConnection,
reasonPhrase: response.reasonPhrase
);
}
_logger.info(s);
return response;
}
}

You can user http_logger
Add them to you pubspec.yaml like this
http: ^0.11.3+16
http_middleware: ^1.0.0
http_logger: ^1.0.0
Note that: http_logger 1.0.0 only works with http 0.11.3+16. (update 02/04/2020).
And import them to file like this:
import 'package:http_middleware/http_middleware.dart';
import 'package:http_logger/http_logger.dart';
import 'package:http/http.dart' as http;
And use them :
HttpWithMiddleware httpClient = HttpWithMiddleware.build(middlewares: [
HttpLogger(logLevel: LogLevel.BODY),
]);
final http.Response response = await httpClient.post(
"https:nhatvm.com/v1/user/login",
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{'email': email, 'password': password}),
);

You can use requests_inspector package.
void main() {
runApp(const RequestsInspector(
enabled: true,
child: MyApp(),
));
}
Screenshots
Note: Don't forget to add the request using RequestsInspectorInterceptor or using InspectorController.addRequest().

You can user pretty_http_logger Add it to your pubspec.YAML like this
pretty_http_logger: ^0.2.1
And use it like this:
HttpWithMiddleware http = HttpWithMiddleware.build(middlewares: [
HttpLogger(logLevel: LogLevel.BODY),
]);
That is it! Now go ahead and use this http object as you would normally do.
Simple POST request
var response = await http.post('https://jsonplaceholder.typicode.com/posts/',
body: {"testing", "1234"});
Simple GET request
var response = await http.get('https://jsonplaceholder.typicode.com/posts/');
It will print out all the headers, request body, response, and error in a proper format that is easy to read and looks pretty.

Related

how can i convert this Rapid API's HTTP Url to Dart Http request

i have this URL
https://zozor54-whois-lookup-v1.p.rapidapi.com/?rapidapi-key=MYAPIKEYb&domain=DOMAINTOCHECK&format=FORMATTYPE
rapid API gives two header's and other things
I Tried This Code By Exploring HTTP package But Not Working:
import 'package:http/http.dart' as http;
void main() async {
var url = 'https://zozor54-whois-lookup-v1.p.rapidapi.com/?domain=sendrank.com&format=json';
var headers = {
'X-Rapidapi-Key': APIKEyY
'X-Rapidapi-Host': 'zozor54-whois-lookup-v1.p.rapidapi.com',
'Host': 'zozor54-whois-lookup-v1.p.rapidapi.com'
};
var response = await http.get(url, headers: headers);
print(response.body);
}
You need to encode the url with the parameters
final queryParameters = {
'domain': 'sendrank.com',
'format': 'json',
};
final uri = Uri.https('zozor54-whois-lookup-v1.p.rapidapi.com', '/', queryParameters);
final response = await http.get(uri, headers: {
'X-Rapidapi-Key': APIKEyY
'X-Rapidapi-Host': 'zozor54-whois-lookup-v1.p.rapidapi.com',
'Host': 'zozor54-whois-lookup-v1.p.rapidapi.com'
});
See How do you add query parameters to a Dart http request?

Dart server side: How to receive data from the Postman (form-data)?

I am using dart:io to create the server. I send the request from the Postman with form-data. I need to use form-data because my old API from another language uses it and the app uses it too.
At the moment. I am trying to get the data and files with this code:
Future main(List<String> arguments) async {
HttpServer server = await HttpServer.bind('localhost', 8085);
server.listen((HttpRequest request) async {
String jsonString = await request.cast<List<int>>().transform(utf8.decoder).join();
print("jsonString:\n$jsonString");
await request.response.close();
});
}
When I send the data and a file from the Postman with this below.
I will get the error below.
Unhandled exception:
FormatException: Unexpected extension byte (at offset 435)
If I don't send the file as image 1, I got this.
jsonString:
----------------------------166099235909119466948633
Content-Disposition: form-data; name="key 1"
Content-Type: application/json
value 1
----------------------------166099235909119466948633
Content-Disposition: form-data; name="key 2"
value 2
----------------------------166099235909119466948633--
I can't convert the above results to variables.
I don't know how to do that. Has anyone an example for doing this or suggest any package to me? This is my first time creating a dart server.
I follow this.
You can get the data and files from the request by using shelf_multipart (Other packages may be used in conjunction with this one and find more methods on GitHub).
If you want to see results quickly that it can be done. Follow this below.
I am using 3 packages including the shelf, shelf_router, and shelf_multipart packages.
You need to add these packages to your pubspec.yaml.
(You can copy and paste these into your pubspec.yaml.)
dependencies:
shelf: ^1.4.0
shelf_router: ^1.1.3
shelf_multipart: ^1.0.0
Then copy my code and past it to your main.dart:
import 'dart:convert';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;
import 'package:shelf_router/shelf_router.dart';
import 'package:shelf_multipart/form_data.dart';
import 'package:shelf_multipart/multipart.dart';
Future main(List<String> arguments) async {
final service = Service();
final server = await shelf_io.serve(service.handler, 'localhost', 8085);
print('Server running on localhost:${server.port}');
}
class Service {
Handler get handler {
final router = Router();
router.post("/example", (Request request) async {
if (request.isMultipart && request.isMultipartForm) {
Map<String, dynamic>? data = await RequestConverter.formData(request);
return data != null
? Response.ok("form-data: true, receive-data: true, data: $data")
: Response.ok("form-data: true, receive-data: false");
}
return Response.ok("form-data: false");
});
router.all('/<ignored|.*>', (Request request) {
return Response.notFound('Page not found');
});
return router;
}
}
class RequestConverter {
static Future<Map<String, dynamic>?> formData(Request request) async {
try {
Map<String, dynamic> data = {};
Map<String, dynamic> files = {};
final List<FormData> formDataList = await request.multipartFormData.toList();
for (FormData formData in formDataList) {
if (formData.filename == null) {
String dataString = await formData.part.readString();
data[formData.name] = Json.tryDecode(dataString) ?? dataString; //Postman doesn't send data as json
} else if (formData.filename is String) {
files[formData.name] = await formData.part.readBytes();
}
}
return {"data": data, "files": files};
} catch (e) {
return null;
}
}
}
class Json {
static String? tryEncode(data) {
try {
return jsonEncode(data);
} catch (e) {
return null;
}
}
static dynamic tryDecode(data) {
try {
return jsonDecode(data);
} catch (e) {
return null;
}
}
}
After this, you can start your server in your terminal. For me I am using:
dart run .\bin\main.dart
Finally, open the Postman and paste http://localhost:8085/example to the URL field, select the POST method, and form-data. You can add the data into the KEY and VALUE fields. Then press send.
This is my example in the Postman:
This solution work with http.MultipartRequest() from the Flutter app.

Send post request in aqueduct dart

I have created a post request in aqueduct dart and it takes json as body parameter, and I need to send that request body to thirdparty api , upon getting response from third party api I need to return that response to user. I have updated the code and printed the response header and it says http 400 (bad request)
here is the code :
#override
Controller get entryPoint {
String dataRecieved;
var completer = new Completer();
var contents = new StringBuffer();
final router = Router();
// Prefer to use `link` instead of `linkFunction`.
// See: https://aqueduct.io/docs/http/request_controller/
router.route("/uploadurl").linkFunction((request) async {
final req = await request.body.decode();
// print( await request.body.decode());
HttpClient client = new HttpClient();
client.badCertificateCallback =
((X509Certificate cert, String host, int port) => true);
var auth = 'Bearer ' +
'eyJ...';
await client
.postUrl(Uri.parse(
'https://<removed>/api/datalake/v3/generateDownloadObjectUrls'))
.then((HttpClientRequest requestSend) {
requestSend.headers
.add("Content-Type", "application/json; charset=UTF-8");
requestSend.headers.add("Authorization", auth);
// requestSend.headers.contentLength = request.body.length;
print(req);
requestSend.write(req);
return requestSend.close();
}).then((HttpClientResponse response) async {
print(await response.contentLength);
var resStream = response.transform(Utf8Decoder());
await for (var data in resStream) {
print('Received data: $data');
}
print(await response.statusCode);
}).catchError((e) {
print("Request error: $e"); // The only case
});
print(contents);
return Response.ok({"key": dataRecieved});
});
return router;
}
when I make a request from the postman , I get
{
"key": null
}
I think I am not able to send the correct request to third party API , because when I tested third party API from the postman, it was sending correct response
My pubspec.yaml file is :
name: proxydl
description: An empty Aqueduct application.
version: 0.0.1
author: stable|kernel <jobs#stablekernel.com>
environment:
sdk: ">=2.0.0 <3.0.0"
dependencies:
aqueduct: ^3.0.0
http: ^0.12.0+2
dev_dependencies:
test: ^1.0.0
aqueduct_test: ^1.0.0
This is what I am sending from postman as post request:
{
"paths": [
{
"path": "/f1/f2.log"
}
]
}
This is my first POC with Dart on the server side.
Upon further investigation I found the answer:
final req = await request.body.decode();
var envalue = json.encode(req);
For now, this worked, but I feel there might be a better answer for this

How to Http Post with Json Body on Flutter

I am trying to get data from API. I need to pass value from the body, in postman without a header: application/JSON data is not displayed.
final response = await http.post(
"http://192.168.10.25:8080/Login/validateusername",
body: {"username": "user#PYA"},
headers: {'Content-Type': 'application/json'},
);
Error Message:
E/flutter (28851): [ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception:
E/flutter (28851): Bad state: Cannot set the body fields of a Request with content-type "application/json".
Add the content type application/json
Future<String> apiRequest(String url, Map jsonMap) async {
HttpClient httpClient = new HttpClient();
HttpClientRequest request = await httpClient.postUrl(Uri.parse(url));
request.headers.set('content-type', 'application/json');
request.add(utf8.encode(json.encode(jsonMap)));
HttpClientResponse response = await request.close();
// todo - you should check the response.statusCode
String reply = await response.transform(utf8.decoder).join();
httpClient.close();
return reply;
}
Simply encode body to json object when using content-type "application/json"
http.Response response = await http.post( uri , headers: headers, body: JsonEncoder().convert(body));
Another simple way is as bellow
import 'package:http/http.dart' as http;
String body = json.encode({
'foo': 'bar',
'complex_foo' : {
'name' : 'test'
}
});
http.Response response = await http.post(
url: 'https://example.com',
headers: {"Content-Type": "application/json"},
body: body,
);
use the http dart package
var data = {username:"username",password:"password"};
http.Response response = await http.post(
"yourApiroute",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: {"username": data.phone, "password": data.password});
var json = jsonCodec.encode(data);
print("json=$json");
var url = "http:yourAPIrouter.com/etc";
var response = await http.post(
url,
headers:{ "Accept": "application/json" } ,
body: { "json": '$json'},
encoding: Encoding.getByName("utf-8")
);
and dont forget add the key "json" in postman
I am doing almost the same. However, I tried to avoid doing back-end, like in your case. I just did a minimal php request so that I would not waste or patience learning what is needed to develop a user management controller.
However, I faced several limitations and problems that Flutter alone can't solve. After some denial, I gave a try. Lumen, a light version of the Laravel Framework, some tutorials and some past experience, I eventually realized that the API should carry most of the authentication, and not the application itself. I digressed.
In my case, the code of the fuction to a http post is:
Future<Post> createPost() async {
final url = "http://localhost:8000/api/login";
Map<String, String> body = {
'user': user.text,
'pass': pass.text,
};
await http.post(url, body: body);
print(body);
return http.;
}
I first convert it into a map. I prefer this method over parsing json, because down the line, if I need to add more variables, I just make the map bigger.
I just have a question: What does your http://192.168.10.25:8080/Login/validateusername look like? I think that there is no need to specify the type of information that your body parses.

How to get device user agent information in Flutter

I'm building a flutter app which needs to send user agent information along with the http request. I'm using http dart package to send requests. How to get user agent string in flutter and use it with http package?
I done it by calling native methods in flutter. First you have to add method channel in android Main Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
new MethodChannel(getFlutterView(), CHANNEL).setMethodCallHandler(
new MethodChannel.MethodCallHandler() {
#Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
if (call.method.equals("getUserAgent")) {
result.success(System.getProperty("http.agent"));
} else {
result.notImplemented();
}
}
});
}
Then getUserAgent() method can be called in flutter like below
Future<String> _getUserAgent() async {
try {
return await platform.invokeMethod('getUserAgent');
} catch (e) {
return 'Unknown';
}
}
You can get it in a cross-platform way by using the flutter_user_agent library: https://pub.dev/packages/flutter_user_agent.
import 'package:flutter_user_agent/flutter_user_agent.dart';
...
String ua = await FlutterUserAgent.getPropertyAsync('userAgent');
this worked for me by using flutter_user_agent library: https://pub.dev/packages/flutter_user_agent
as mentioned above
String _userAgent = await FlutterUserAgent.getPropertyAsync('userAgent');
final _response = await http.get(_url, headers: {
'Content-Type': 'application/json',
'Accept-Charset': 'utf-8',
'User-Agent': '${_userAgent.toLowerCase()}',
});
Found a library that does it. It would be interesting to look at what the library does, i don't think it's needed to implement a library for that.
https://pub.dartlang.org/packages/user_agent
An example on how you would use it:
main() async {
app.get('/', (req, res) async {
var ua = new UserAgent(req.headers.value('user-agent'));
if (ua.isChrome) {
res.redirect('/upgrade-your-browser');
return;
} else {
// ...
}
});
}
Alternatively, if you want to add a user-agent to the http client, you can do it this way:
Future<http.Response> fetchPost() {
return http.get(your_url,
// Send user-agent header to your backend
headers: {HttpHeaders.userAgentHeader: "your_user_agent"},
);
}
You can look at HttpHeadersto see the full list of predefined headers, although headers take a map, you could create your own header if you want.

Resources