Flutter Injectable Inject a Third Party Dependency - flutter

I've been spinning my wheels for hours on the simple question of how to inject http.Client into a flutter class when using injectable. They reference doing this in a module (as suggested in this post), but I can't figure that out either.
This is my file (abstract and concrete classes):
import 'dart:convert';
import 'package:get_it/get_it.dart';
import 'package:http/http.dart' as http;
import 'package:injectable/injectable.dart';
import 'package:myapp_flutter/core/errors/exceptions.dart';
import 'package:myapp_flutter/data/models/sample_model.dart';
abstract class ISampleRemoteDataSource {
/// Throws a [ServerException] for all error codes.
Future<SampleModel> getSampleModel(String activityType);
}
#Injectable(as: ISampleRemoteDataSource)
class SampleRemoteDataSourceImpl extends ISampleRemoteDataSource {
final http.Client client;
final baseUrl = "https://www.boredapi.com/api/activity?type=";
final headers = {'Content-Type': 'application/json'};
SampleRemoteDataSourceImpl({#factoryParam required this.client});
#override
Future<SampleModel> getSampleModel(String activityType) async {
Uri uri = Uri.parse(baseUrl + activityType);
GetIt.I.get<http.Client>();
final response = await client.get(uri, headers: headers);
if (response.statusCode == 200) {
return SampleModel.fromJson(json.decode(response.body));
} else {
throw ServerException();
}
}
}
I thought declaring it as a factory param in the constructor would do it, but I was wrong. Declaring the abstract class as a module doesn't do it (and seems very wrong, also). I just don't know.

This should work:
First implement a register module file
#module
abstract class RegisterModule {
//add http client
#lazySingleton
http.Client get httpClient => http.Client();
}
class $RegisterModule extends RegisterModule {}
Then, after generating injection.config.dart file your http Client should be mentioned in initGetIt class

You will have to register them as module as described below
https://pub.dev/packages/injectable#Registering-third-party-types

Related

Using http.dart to Call CoinMarketCap API. Not sure what to do

So I'm new to flutter and dart and am trying to call from the CoinMarketCap API. I'm using the HTTP package to call the data and the API. I'm not super familiar with them but here's what I came up with...
import 'package:http/http.dart' as http;
import 'dart:convert';
Future<Payload> getCryptoPrices() async {
var response = await http.get(Uri.parse(
"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?start=1&limit=5000&convert=USD"),
headers: {
'X-CMC_PRO_API_KEY': 'my-key',
"Accept": "application/json",
});
if (response.statusCode == 200) {
Payload payload = payloadFromJson(data.body);
return payload;
}
}
I get a couple of errors:
The name 'Payload' isn't a type so it can't be used as a type argument
The function 'payloadFromJson' isn't defined
Undefined name 'data'
Am I not successfully importing JSON? I'm not sure how to fix the error. What do I need to do to successfully make a API Call? Any feedback would be great.
CODE UPDATED #1
import 'package:wnetworking/wnetworking.dart';
class CoinMarketCap {
static const _apiKey = '111111111111111111111111111111';
static const _url = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency';
static Future<void> getListingLatest(int limit) async {
var url = '$_url/listings/latest?start=1&limit=$limit&convert=USD';
var result = await HttpReqService.get<JMap>(
url,
auth: AuthType.apiKey,
authData: MapEntry('X-CMC_PRO_API_KEY', _apiKey)
);
var coins = (result?['data'] as List).cast<JMap>().map<String>((e) => e['name']);
print(coins);
}
}
void main(List<String> args) async {
await CoinMarketCap.getListingLatest(7);
print('\nJob done!');
}
Output:
(Bitcoin, Ethereum, Tether, USD Coin, BNB, XRP, Cardano)
Job done!
'Payload' is not a flutter class so it does not exist. were you trying to use a Custom made Class?
the 'payloadFromJson' error means it does not exist so you probably did not import it properly if it is in another class
Undefined name 'data' means that data has not been defined if you want the body of the response use 'response.body'

Flutter testing with mockito and injectable

I'm learing test writing with mockito but i have some problems with testing remote_data_source_class.
Here's my abstract class
abstract class ApiRemoteDataSource {
Future<PokemonsListResponseModel> getPokemons();
}
Here's the implementation
import 'dart:convert';
import 'package:injectable/injectable.dart';
import 'package:http/http.dart' as http;
import '../../models/pokemons_list_response_model.dart';
import 'api_remote_data_source.dart';
#Injectable(as: ApiRemoteDataSource)
class ApiRemoteDataSourceImpl implements ApiRemoteDataSource {
ApiRemoteDataSourceImpl(this.client);
final http.Client client;
final pokemonListUrl = Uri.parse('https://pokeapi.co/api/v2/pokemon');
#override
Future<PokemonsListResponseModel> getPokemons() async {
final response = await client.get(pokemonListUrl);
final data = response.body;
final modelData = PokemonsListResponseModel.fromJson(json.decode(data));
return modelData;
}
}
Now Iwant to verify that when i invoke method .getPokemons() on mock data source my http.Client will execute a call to given endpoint:
#GenerateMocks([http.Client, ApiRemoteDataSource])
void main() {
late ApiRemoteDataSource dataSource;
late MockClient mockHttpClient;
setUp(() async {
await configureDependencies();
mockHttpClient = MockClient();
dataSource = MockApiRemoteDataSource();
print('test: $mockHttpClient, data source $dataSource');
});
group('getPokemonsList', () {
test('Should perform a GET request on a URL', () async {
final url = Uri.parse('https://pokeapi.co/api/v2/pokemon');
// arrange
when(mockHttpClient.get(url, headers: anyNamed('headers')))
.thenAnswer((_) async => http.Response(fixture('pokemon_list.json'), 200));
// act
dataSource.getPokemons();
// assert
verify(mockHttpClient.get(Uri.parse('https://pokeapi.co/api/v2/pokemon')));
});
});
}
Running test above gives me this error: "MissingStubError: 'getPokemons'
No stub was found which matches the arguments of this method call:
getPokemons()"
When i replace dataSource.getPokemons() in //act part with "mockHttpClient.get(url)" everything works but I'm not sure if that kind of test is valid

Using injectable for third party abstract class in flutter

I have used package http in my project and thus, I have Client's instance (which comes from package http) as a dependency, which is an abstract class. So, how should I annotate with proper annotations?
In injectable's documentation, there is information on how to register third-party dependencies and how to register abstract classes. But how can I register third-party abstract class?
This is my code
class TokenValueRemoteDataSourceImpl implements TokenValueRemoteDataSource {
TokenValueRemoteDataSourceImpl(this.client);
final http.Client client;
#override
Future<TokenValueModel> getAuthToken({
required EmailAddress emailAddress,
required Password password,
}) async {
final emailAddressString = emailAddress.getOrCrash();
final passwordString = password.getOrCrash();
const stringUrl = 'http://127.0.0.1:8000/api/user/token/';
final response = await client.post(
Uri.parse(stringUrl),
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(
{
'email': emailAddressString,
'password': passwordString,
},
),
);
if (response.statusCode == 200) {
return TokenValueModel.fromJson(
json.decode(response.body) as Map<String, dynamic>,
);
} else {
throw ServerException();
}
}
}
How should I write my register module for a third-party abstract class?
I did see this on injectable's documentation
#module
abstract class RegisterModule {
#singleton
ThirdPartyType get thirdPartyType;
#prod
#Injectable(as: ThirdPartyAbstract)
ThirdPartyImpl get thirdPartyType;
}
But I didn't understand what I should replace ThirdPartyImpl with in my code.
You don't necessarily need to define an abstract class to inject your dependencies. So for in your case, to register a third-party class, you can use the same type without having an abstract and concrete class separately. See the below example of how to register the http Client class that is imported from the http package:
#module
abstract class YourModuleName {
#lazySingleton // or #singleton
http.Client get httpClient => http.Client();
}
Then you can use the http Client anywhere using the global GetIt variable you have, like this:
yourGetItVariableName.get<http.Client>(); or GetIt.I.get<http.Client>();

Dart Is there a way to get HTTPS content?

I really need help. I try to get the rss feed from this url:
- https://www.france24.com/fr/rss?time=1573661731673
But I don't know how to do it when using a https url, I tried to use the HTTP dart library. Here is my code:
import 'package:html/parser.dart';
import 'package:html/dom.dart';
import 'dart:async';
import 'package:http/http.dart';
class Parser {
final String urlSite = "http://www.france24.com/fr/actualites/rss";
Future chargerRSS() async{
final reponse = await get(urlSite);
if(reponse.statusCode == 200){
final feed = RssFeed.parse(reponse.body);
print("$feed at parser");
}
else{
print("Erreur: ${reponse.statusCode}");
}
}
}```

Rx Flutter Request List From JsonPalceHolder

I try to get List from jsonPlaceHolder using flutter rxdart stream and try to apply bloc pattern on it.
this class that response for get post response from api
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../models/post_item.dart';
class ItemApi {
Future<List<JsonItem>> getPost() async {
String _url = 'https://jsonplaceholder.typicode.com/posts';
final _response = await http.get(_url);
if (_response.statusCode == 200) {
return (json.decode(_response.body) as List)
.map((jsonItem) => JsonItem.fromJson(jsonItem))
.toList();
}
}
}
I using repository class to wrap using ItemApi class
import 'json_item_request.dart';
import '../models/post_item.dart';
class Repository{
final jsonItemResponse = ItemApi();
Future<List<JsonItem>> getItem() => jsonItemResponse.getPost();
}
at the last i using bloc class that response for get data and set it inside PublishSubject
import '../models/post_item.dart';
import '../resouces/repository.dart';
import 'package:rxdart/rxdart.dart';
class JsonBloc {
final _repository = Repository();
final _streamOfJsonList = PublishSubject<List<JsonItem>>();
Observable<List<JsonItem>> get jsonList=> _streamOfJsonList.stream;
fetchAllPost() async{
Future<List<JsonItem>> list = _repository.getItem();
}
dispose(){
_streamOfJsonList.close();
}
}
My question is how i can set response inside _streamOfJsonList variable to using it when list changed.
Sounds like you already have all the moving parts connected? If so you just need to add the item list to the PublishSubject:
void fetchAllPost() async {
List<JsonItem> list = await _repository.getItem();
_streamOfJsonList.add(list);
}
This will trigger the onListen callback with the new list on anything that is listening to the stream.
You can add error and data to ReplaySubject like below :
void fetchAllPost() async {
List<JsonItem> list = await _repository.getItem();
if (list != null) {
_streamOfJsonList.sink.add(list);
} else {
_streamOfJsonList.addError("ERROR");
}
}