Force http from dart.dev to use dio from flutterchina.club - flutter

I have built interceptors around dio for error handling,logging and cache. I found some other packages like cached_network_image, advance_pdf_viewer use dart.dev's http client.
I want to make same requests processed from cached_network_image, advance_pdf_viewer from dio's client so that custom error messages are displayed in UI which provides uniformity.
Future<Dio> _getDio() async {
final dio = Dio()..options.baseUrl = ApiEndPoints.base;
dio.interceptors.addAll([
DioCachingInterceptor(
connectivity,
),
DioAppInterceptor(),
DioLoggingInterceptor(),
]);
return dio;
}
Any Ideas??

Related

Post request flutter

i'm trying to do a post request but all the time i get this error
Uncaught Error: XMLHttpRequest error.
i' working on dartpad on line and i'm using the package http.dart .I don't get the problem despite i post a json format i dont understand why the error is with the xml ?!
this my code :
import 'package:http/http.dart' as http;
void main() async {
// This will be sent as form data in the post requst
var map = new Map<String, dynamic>();
map['username'] = '**********';
map['password'] = '**********';
final response = await http.post(
Uri.parse('************'),
body: map,
);
print(response.body);
}
I suggest the following:
Verify that your URI is correct, I tried your code on DartPad with a simple GET request onto a Free API I found on the web and I get no errors
Verify that your endpoint has no weird CORS errors with another client (e.g. postman or Dio, see below)
Verify that you don't have weird cache values onto your machine. Doing a flutter clean && flutter pub get might help
Consider using Dio (pub.dev) as your http client as the dart's inner http package isn't quite ready for production imho.

http requests are very slow in flutter

I am using the http package to call my API, but every request takes 8+ seconds to complete.
I have tried calling the same route via browser and postman and I get the response in less than a second. Also, I can assure that there is no issue with my internet connection.
class ApiRest {
Future<List<Product>> getProducts() async {
final apiResponse = await http.get(Uri.parse('some route'));
final resBody = jsonDecode(apiResponse.body);
return resBody['products']
.map<Product>((product) => Product.fromJson(product))
.toList();
}
}
Additionally, I tried applying the approach recommended by this answer, using the HTTP Client(), which didn't make a difference either.
Is there anything I am doing wrong or inefficient?
Lastly, the latest version of the http package for Flutter is currently 0.13.4. Do you think that the issue might be with this package? Or it might not be stable enough?

Flutter testing, passing an actual HTTP client, instead of a mocked one

I have developed a package in flutter, and wanted to test it, which makes a network call.
As we know that all network request while testing will return 404, and such HTTP reqeust needs to be mocked.
However its also possible to use the orginal HTTP clients instead of mocking or getting 404.
https://github.com/flutter/flutter/issues/19086#issuecomment-402639134
How do we do that ?
I have tried this :
main(){
TestWidgetsFlutterBinding.ensureInitialized();
HttpOverrides.runZoned(() {
test("Case1: Make HTTP request to an actual server", ()async{
let a = MyPackage.makesAHTTPRequest();
expect(a,"hello world");
});
}, createHttpClient: (SecurityContext c) => new HttpClient(context: c));
}
My URL is working all fine.
But it keeps giving me 404.
How do one use real HTTP client, if needed that way?
Ok so if any one is facing a similar issue like me use this hack.
You will need to modify your class, in a way that we can inject HTTP clients into it at run time. We will need to modify our test case as such.
import 'package:http/http.dart'; //client is from this pack
Client httpclinet = Client();
var a = MyPackage.makesAHTTPRequest(httpclient);
remove that Httpoverride.runzoned cod, you can pass Client object from http package directly.
Some test case will fail, due to fake asynchronous effect, but you can use timeouts to manage those.
You will also need to remove any such statements:
TestWidgetsFlutterBinding.ensureInitialized();
In my case I added this line as I was loading files from assets, using packages notation, I referenced them locally and removed above ensureInitalized line as well. [Actually I passed flag to use local notation during testing and package notation otherwise]

Flutter - Dependency Injection

I am after some best practise tips for developing my Flutter app.
Currently, I have an app with multiple pages and multiple plugins such as network connection, SQLite, Location etc.
Currently, on each page, I am creating a new instance of each plugin I need access to as shown below, and then using the plugin functionality.
final _secureStorage = FlutterSecureStorage();
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
What I want to achieve: I would like to possibly only create an instance of these classes once, and then be able to access the instance in all pages - something like Dependency Injection.
Currently, I am looking into InheritedWidget widget or the Provider package, however, I am not sure if they do what I am trying to achieve as I don't want to inherit or pass around widgets, I want to inject classes instances.
You could try out, the get_it package, since it is not tied to Flutter.
https://pub.dev/packages/get_it
The ioc_container may suit your case because it has specific documentation on how to use it with Firebase and firebase Messaging. It does exactly as you say: initialize Firebase asynchronously and store the instances as singletons with dependency injection.
Here is a snippet of the code from the documentation:
extension FlutterFireExtensions on IocContainerBuilder {
void addFirebase() {
//These factories are all async because we need to ensure that Firebase is initialized
addSingletonAsync(
(container) {
WidgetsFlutterBinding.ensureInitialized();
return Firebase.initializeApp(
options: container.get<FirebaseOptions>(),
);
},
);
addSingletonAsync(
(container) async => FirebaseAuth.instanceFor(
app: await container.getAsync<FirebaseApp>(),
),
);
addSingletonAsync(
(container) async => FirebaseFirestore.instanceFor(
app: await container.getAsync<FirebaseApp>(),
),
);
addSingletonAsync((container) async {
//Ensure we have already initialized Firebase
await container.getAsync<FirebaseApp>();
return FirebaseMessaging.instance;
});
}
}

Flutter integration test - how to load a JSON file?

I am writing a Flutter integration test with a mock client that returns a JSON response for each of the REST endpoints my app calls.
These JSON responses are stored in separate JSON files, but I am unable to access the files when the test is running.
I've tried loading the files by creating and reading a new file object. Flutter: how to load file for testing but it could never find the file.
I also tried putting my JSON files into assets. This worked, but also resulted in the test JSON files being bundled when I built the APK.
Simplified Mock Client:
MockClient integrationMockClient = MockClient((request) async {
switch (request.url.toString()) {
case 'https://staging.company.com/api/123':
return Response(readJsonfile('myJsonFile.json'), 200);
Simplified integration test main function - passes mock client in. test_driver/app.dart
void main() async {
enableFlutterDriverExtension();
final app = await initializeApp(
integrationMockClient
);
runApp(app);
}
When I try and read a file it can never find it. Possible because flutterDriver runs the 'real app' with no access to files stored in test directories.
How can I access a JSON file from an integration test without it being bundled in production code/APK?
I encountered similar issues accessing file resources using flutter driver for integration tests. What I did as a workaround was to parse the JSON response directly, instead of storing the JSON response as a file.
Here's a sample that you can try out. This uses https://jsonplaceholder.typicode.com as its endpoint sample.
test('Test http', () async {
final file = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1'));
final json = jsonDecode(file.body.toString());
print('json contents: $json');
print('userId: ${json['userId']}');
final userId = json['userId'];
expect(userId, 1);
});
Put JSON into String variable, like this. const String objectJson = """{JSON}""";
Wrap your JSON with a triple quotation mark """
and use it on integration tests, instead of reading it from a file