How to use variables on different class with dart/flutter - dart

I have one class which is my getToken class. In this class ı get the token which is String token. Here is my getToken.dart
class GetToken {
String token;
Future<Null> getData() async {
var url = "http://192.168.1.39:7070/api/v2/token";
http.post(url, body: {
"grant_type": "string",
"branchcode": "string",
"password": "string",
"username": "string",
"dbname": "string",
"dbuser": "string",
"dbpassword": "string",
"dbtype": "string"
}).then((response) {
print("Response Status: ${response.statusCode}");
//print("Response Body: ${response.body}");
print('access token is -> ${json.decode(response.body)['access_token']}');
token = json.decode(response.body)['access_token'];
});
}
}
I want to use this token in my getCari class and get the Json values in my rest api. Here is my getCari.dart class
class GetCari{
getCari() async {
final response = await http.get("http://192.168.1.39:7070/api/v2/ARPs",
headers: {HttpHeaders.AUTHORIZATION: token});
if(response.statusCode ==200){
return Cari.fromJson(json.decode(response.body));
}else{
throw Exception("Failed to Load");
}
}
}
I would like to ask how can ı use my token(which is get from getToken.dart) in my getCari.dart class. How can ı pass the token variable other classes?

Please use Dart's top level functions instead of classes which does not need instantiation.
This is mentioned in Effective Dart documentation
token_manager.dart
String _token;
String get token => _token // To ensure readonly
Future<Null> setToken() async {
// set your _token here
}
get_cari.dart
import 'token_manager.dart' as token_manager // use your import path here
getCari() async {
// You can now access token from token_manager from any class like this.
final String token = token_manager.token;
}
Excerpt
In Java and C#, every definition must be inside a class, so it’s
common to see “classes” that exist only as a place to stuff static
members. Other classes are used as namespaces—a way to give a shared
prefix to a bunch of members to relate them to each other or avoid a
name collision.
Dart has top-level functions, variables, and constants, so you don’t
need a class just to define something. If what you want is a
namespace, a library is a better fit. Libraries support import
prefixes and show/hide combinators. Those are powerful tools that let
the consumer of your code handle name collisions in the way that works
best for them.
If a function or variable isn’t logically tied to a class, put it at
the top level. If you’re worried about name collisions, give it a more
precise name or move it to a separate library that can be imported
with a prefix.

you can pass data to getCari method by create object fromGetCari() class
see this
class GetToken {
String token;
Future<Null> getData() async {
var url = "http://192.168.1.39:7070/api/v2/token";
http.post(url, body: {
"grant_type": "string",
"branchcode": "string",
"password": "string",
"username": "string",
"dbname": "string",
"dbuser": "string",
"dbpassword": "string",
"dbtype": "string"
}).then((response) {
print("Response Status: ${response.statusCode}");
//print("Response Body: ${response.body}");
print('access token is -> ${json.decode(response.body)['access_token']}');
token = json.decode(response.body)['access_token'];
GetCari().getCari("fdfd");
});
}
}
class GetCari{
getCari(String token) async {
final response = await http.get("http://192.168.1.39:7070/api/v2/ARPs",
headers: {HttpHeaders.AUTHORIZATION: token});
if(response.statusCode ==200){
return Cari.fromJson(json.decode(response.body));
}else{
throw Exception("Failed to Load");
}
}

You can use a service manager like get_it to reuse values anywhere in your app.
Create the class that will hold your shared information
class GetToken{
String token;
...
}
In your main.dart file, setup your GetIt instance
final getIt = GetIt.instance;
void setup() {
getIt.registerSingleton<GetToken>(GetToken());
}
Now, from anywhere in your app, you can call this class and get your token.
var mytoken= getIt.get<AppModel>().token;

Related

Why is there no spy functionality in Mockito Dart?

The following code is a simplified example from my code. I have class A which is dependent on class B. I want to test class A, so I mock class B. Then I'm writing a test for a method of class A and inside of that test I write a stub for whenever a method from my mocked class B is called:
fetchData() async {
try {
await b.getData();
} on DioError catch (e) {
switch (e.response!.statusCode) {
case 401:
logout();
throw UnauthorizedException();
default:
throw UnspecifiedDioException(error: e);
}
}
Test written for fetchData() method:
test('check if fetchData calls logout when 401 is returned', () {
when(mockB.getData())
.thenAnswer((_) async =>
throw DioError(
requestOptions: RequestOptions(path: ""),
response: Response(requestOptions: RequestOptions(path: ""), statusCode: 401)));
verify(a.logout()); // doesn't work because A isn't mocked
});
I've read that you can do this very easily with spies but to my surprise spies are available for every language which uses mockito except for dart. It's apparently deprecated but then again how can something be deprecated if there isn't even a newer version to replace it with.
I'd really appreciate it if someone could tell me if there is a convenient workaround for what I'm trying to achieve. Thanks in advance.
Edit: I've changed the question because the former one wasn't making much sense. I just wanna know if there is something like spies in dart or not.
Using mocktail..
You should stub your logout invocation's dependency as well.
class A {
A({required this.api, required this.auth});
// to be mocked
final Api api;
final Auth auth;
Future<void> fetchData() async {
try {
await api.getData();
} catch (e) {
auth.logout();
}
}
}
class Auth {
Future<void> logout() => Future(() {});
}
class Api {
Future<void> getData() => Future(() {});
}
And your test
class MockApi extends Mock implements Api {}
class MockAuth extends Mock implements Auth {}
void main() {
// create mock objects
final mockApi = MockApi();
final mockAuth = MockAuth();
test('when [Api.getData] throws, [Auth.logout] is called', () async {
// create an instance of "A" and use your mock objects
final a = A(api: mockApi, auth: mockAuth);
// use "thenThrow" to throw
when(() => mockApi.getData()).thenThrow('anything');
// use "thenAnswer" for future-returning methods
when(() => mockAuth.logout()).thenAnswer((_) => Future.value(null));
// call the method to "start" the test
await a.fetchData();
// verify logout was called
verify(mockAuth.logout).called(1); // passes
});
}

Serilog JSON config LoggingLevelSwitch access

Configuring Serilog using a JSON config, it is possible to configure log level switches as such:
"LevelSwitches": {
"$appLogLevel": "Debug",
"$netLogLevel": "Information",
"$sysLogLevel": "Error"
},
"MinimumLevel": {
"ControlledBy": "$appLogLevel",
"Override": {
"Microsoft": "$netLogLevel",
"System": "$sysLogLevel"
}
}
the purpose of the switches (when instantiated in code) is to be accessed at a later time in order to change the minimum log levels during run-time. However when configured via the JSON config, I can't find a way to access those switch instances. Does anyone know how to access them?
My current project required highly configurable logging as well as the ability to adjust any of those configured log levels at runtime.
So I had actually already written a work-around (but in a more generalized way), by simply processing the "MinimalLevel" section of the config manually in my Program.cs, like this:
Requires a static dictionary for later reference:
public static Dictionary<String, LoggingLevelSwitch> LogLevel = null;
And a code block to bind the LoggingLevelSwitches:
//Configure logger (optional)
if (appConfig.GetSection("Serilog").Exists()) {
//Configure Serilog
LoggerConfiguration logConfig = new LoggerConfiguration().ReadFrom.Configuration(appConfig);
//If Serilog config parsed okay acquire LoggingLevelSwitches
LogLevel = LoadLoggingLevelSwitches(appConfig);
//Bind LoggingLevelSwitches
foreach (String name in LogLevel.Keys) {
if (String.Equals(name, "Default", StringComparison.InvariantCultureIgnoreCase)) {
logConfig.MinimumLevel.ControlledBy(LogLevel[name]);
} else {
logConfig.MinimumLevel.Override(name, LogLevel[name]);
}
}
//Build logger from config
Log.Logger = logConfig.CreateLogger();
}
which utilizes a routine that instantiates all those switches (based on the config file):
public static Dictionary<String, LoggingLevelSwitch> LoadLoggingLevelSwitches(IConfiguration cfg) {
Dictionary<String, LoggingLevelSwitch> levels = new Dictionary<String, LoggingLevelSwitch>(StringComparer.InvariantCultureIgnoreCase);
//Set default log level
if (cfg.GetSection("Serilog:MinimumLevel:Default").Exists()) {
levels.Add("Default", new LoggingLevelSwitch((LogEventLevel)Enum.Parse(typeof(LogEventLevel), cfg.GetValue<String>("Serilog:MinimumLevel:Default"))));
}
//Set log level(s) overrides
if (cfg.GetSection("Serilog:MinimumLevel:Override").Exists()) {
foreach (IConfigurationSection levelOverride in cfg.GetSection("Serilog:MinimumLevel:Override").GetChildren()) {
levels.Add(levelOverride.Key, new LoggingLevelSwitch((LogEventLevel)Enum.Parse(typeof(LogEventLevel), levelOverride.Value)));
}
}
return levels;
}
I have separate class that handles applying runtime logging level changes via these switches, but this was the easiest way to get anything and everything I needed, however...
after writing all that code and then finding out there was a way to just add the switches directly from the config with the"LevelSwitches" section, I realized I was probably doubling up on the work. Because obviously Serilog needs to be instantiating and binding it's own switches defined in the config... it just doesn't appear to give a nice and easy way to access them so I can use them later. Which is counter intuitive because the whole point of a LoggingLevelSwitch is to reference it later at runtime.
Seems if the switches are allowed to be created through the config, we should be given an easy way to access them. Perhaps I should add this as a feature request over on the Serilog GitHub.
If you want to access your level switches from code, it probably means that you have a way to control them somehow, so you probably don't need them in the config file in the first place...
I do believe it makes more sense to keep that part entirely in the code and have the configuration partly in code and partly in the config file, so that would look like this :
// in C# code
var appLevelSwitch = new LoggingLevelSwitch(LogEventLevel.Debug);
var netLevelSwitch= new LoggingLevelSwitch(LogEventLevel.Information);
var systemLevelSwitch= new LoggingLevelSwitch(LogEventLevel.Error);
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
Log.Logger = new LoggerConfiguration()
// load config from config file ...
.ReadFrom.Configuration(configuration)
// ... and complete it in C# code
.MinimumLevel.ControlledBy(appLevelSwitch )
.MinimumLevel.Override("Microsoft", netLevelSwitch)
.MinimumLevel.Override("System", systemLevelSwitch)
.CreateLogger();
and in your config file
{
"Serilog": {
"Using": ["Serilog.Sinks.Console"],
"WriteTo": [
{ "Name": "Console" },
{ "Name": "File", "Args": { "path": "%TEMP%\\Logs\\serilog-configuration-sample.txt" } }
],
"Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"],
"Destructure": [
{ "Name": "With", "Args": { "policy": "Sample.CustomPolicy, Sample" } },
{ "Name": "ToMaximumDepth", "Args": { "maximumDestructuringDepth": 4 } },
{ "Name": "ToMaximumStringLength", "Args": { "maximumStringLength": 100 } },
{ "Name": "ToMaximumCollectionCount", "Args": { "maximumCollectionCount": 10 } }
],
"Properties": {
"Application": "Sample"
}
}
}
For the sake of completeness, though, in order to access the defined control switches, you could do the following (be warned that this is kind of a hack !).
Write a configuration method (i.e. an extension method that can appear after .WriteTo.xxx) that accepts LoggingLevelSwitches as arguments and stores them as static members. That configuration method will introduce a dummy ILogEventSink that does nothing (and for performance sake, we can even specify restrictedToMinimumLevel: LogEventLevel.Fatal so that it is almost never called). Then invoke that extension method from the config file (Serilog.Settings.Configuration knows how to find extension methods and pass them the parameters) and voilà, you can now access the static switches from your code !
Here is what it would look like :
public static class LevelSwitches
{
private static LoggingLevelSwitch _switch1;
private static LoggingLevelSwitch _switch2;
private static LoggingLevelSwitch _switch3;
public static LoggingLevelSwitch Switch1 => _switch1 ?? throw new InvalidOperationException("Switch1 not initialized !");
public static LoggingLevelSwitch Switch2 => _switch2 ?? throw new InvalidOperationException("Switch2 not initialized !");
public static LoggingLevelSwitch Switch3 => _switch3 ?? throw new InvalidOperationException("Switch3 not initialized !");
public static LoggerConfiguration CaptureSwitches(
this LoggerSinkConfiguration sinkConfig,
LoggingLevelSwitch switch1,
LoggingLevelSwitch switch2,
LoggingLevelSwitch switch3)
{
_switch1 = switch1;
_switch2 = switch2;
_switch3 = switch3;
return sinkConfig.Sink(
restrictedToMinimumLevel: LogEventLevel.Fatal,
logEventSink: new NullSink());
}
}
public sealed class NullSink : ILogEventSink
{
public void Emit(LogEvent logEvent)
{
// nothing here, that's a useles sink !
}
}
Then in you json config file :
"LevelSwitches": {
"$appLogLevel": "Debug",
"$netLogLevel": "Information",
"$sysLogLevel": "Error"
},
"MinimumLevel": {
"ControlledBy": "$appLogLevel",
"Override": {
"Microsoft": "$netLogLevel",
"System": "$sysLogLevel"
}
},
"WriteTo":[
{
"Name": CaptureSwitches"",
"Args": {
"switch1": "$appLogLevel",
"switch2": "$netLogLevel",
"switch3": "$sysLogLevel",
}
}
]
(you may need a "Using" directive with the name of the assembly containing the LevelSwitches class)
Configure your logger from the config file
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var logger = new LoggerConfiguration()
.ReadFrom.Configuration(configuration)
.CreateLogger();
From that point, you should be able to access the switches through LevelSwitches.Switch1, LevelSwitches.Switch2 and LevelSwitches.Switch3.

Dart Built Value Deserialize List of Objects

I have an API that's returning a list of objects...
[{}, {}, {}, ...]
I already have a defined and working built_value model for each object. However, now I need to deserialize the list.
I currently am trying something like this:
List<Map<String, dynamic>> json = JSON.decode(DEMO_TASK);
json.expand<Task>((Map<String, dynamic> map) => _serializers.deserializeWith<Task>(Task.serializer, map));
However, that causes issues since it says _serializers.deserializeWith return type Task isn't an Iterable<Task> as defined by the closure.
How do I go about deserializing the list. I'm sure I'm missing something super basic.
In case you want to have more general approach you can use this code snippet:
In case anybody needs this functionality I leave here code snippet of how to handle this situation (code should be placed in serializers.dart file):
Serializers standardSerializers = (serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();
T deserialize<T>(dynamic value) =>
standardSerializers.deserializeWith<T>(standardSerializers.serializerForType(T), value);
BuiltList<T> deserializeListOf<T>(dynamic value) =>
BuiltList.from(value.map((value) => deserialize<T>(value)).toList(growable: false));
So if you have json file
[
{
"name": "test1",
"result": "success"
},
{
"name": "test2",
"result": "fail"
}
]
And built value class:
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
part 'test_class.g.dart';
abstract class TestClass implements Built<TestClass, TestClassBuilder> {
String get name;
String get result;
TestClass._();
factory TestClass([updates(TestClassBuilder b)]) = _$TestClass;
static Serializer<TestClass> get serializer => _$testClassSerializer;
}
You can use method deserializeListOf from above as:
import 'package:path_to_your_serializers_file/serializers.dart';
final BuiltList<TestClass> listOfTestClasses = deserializeListOf<TestClass>(json);
Yup. I missed something basic. I was thinking I was using a stream, but since it's a list you just have to use the .map function on a list.
List<Map<String, dynamic>> json = JSON.decode(DEMO_TASK);
List<Task> tasks = json.map<Task>((Map<String, dynamic> map) => _serializers.deserializeWith<Task>(Task.serializer, map)).toList();

How to correctly wrap a Flux inside a Mono object

I have a web-service which returns student and enrolled class details.
{
"name": "student-name",
"classes": [
{
"className": "reactor-101",
"day": "Tuesday"
},
{
"className": "reactor-102",
"day": "Friday"
}
]
}
The DTO for this class is as below:
public class Student {
private String name;
private Flux<StudentClass> classes;
#Data
#AllArgsConstructor
#JsonInclude(JsonInclude.Include.NON_DEFAULT)
public static class StudentClass {
private String className;
private String day;
}
}
The main REST controller logic to fetch the student is as follows:
Flux<StudentClass> studentClassFlux = studentClassRepository.getStudentClass(studentName);
return Mono.just(new Student(studentName, studentClassFlux));
The problem with this is, I get the following output after making the REST call:
{
"name": "student-name",
"classes": {
"prefetch": 32,
"scanAvailable": true
}
}
I can achieve the desired output by blocking on the flux request to get completed and then convert the output to list.
List<StudentClass> studentClassList = studentClassRepository.getStudentClass(studentName)..toStream().collect(Collectors.toList());
return Mono.just(new Student(studentName, studentClassList)); // Change the Student#classes from flux to list
I am new to reactive-programming.
What is the correct way of using the Flux & Mono here to get the desired output?
Reactive types aren't meant to be serialized when wrapped in each other.
In that particular case, you probably want your Student object to contain a List<StudentClass>. You can achieve that like this:
public Mono<Student> findStudent(String studentName) {
return studentClassRepository
.getStudentClass(studentName)
.collectList()
.map(studentClasses -> new Student(studentName, studentClasses));
}
I think, in the case that you really need a Flux in your result, you would want to break down the API so that you have separate methods to retrieve the entities.
One for student properties, and another for their classes. The student GET method could be a Mono, while the classes would return a Flux.

Sending JSON in ActionScript 2

anyone know how to send JSON in ActionScript 2?
I tried using XML() but it changes all " into " before sending it. Ex:
var callout = new XML({ "name": "John"})
callout.sendAndLoad('http://api.app.com', new XML());
but what gets sent is { "name": "John"}
also cannot upgrade to AS3 (wish i could)
Here's how you do it
Create a new class that extends LoadVars and override the "toString" method to return the JSON. You can then use load() and sendAndLoad() to send JSON to an URL
Example:
class SendJson extends LoadVars {
public var data:String; // Put your JSON here
public function toString() {
return data;
}
}

Resources