0.4.1

Extending Flutter Data

Flutter Data is extended via adapters.

Some examples:

Override base URL for a User model

mixin UserURLAdapter on RemoteAdapter<User> {
  @override
  String get baseUrl => 'http://jsonplaceholder.typicode.com/';
}

Need to apply the adapter to ALL your models?

Make it generic using <T extends DataSupport<T>>! See the following examples.

Override headers and base URL

mixin BaseAdapter<T extends DataSupport<T>> on RemoteAdapter<T> {
  final _localStorageService = manager.locator<LocalStorageService>();

  @override
  get baseUrl => "http://my.remote.url:8080/";

  @override
  get headers {
    final token = _localStorageService.getToken();
    return super.headers..addAll({'Authorization': token});
  }
}

Same for query parameters.

All Repository public methods like findAll, save, serialize, deserialize, … are available.

Override type, URL paths, HTTP methods

See Repository where this mechanism is described in great detail.

Authentication service

mixin AuthAdapter on RemoteAdapter<User> {
  Future<String> login(String email, String password) async {
    final response = await withHttpClient(
      (client) => client.post(
        '$baseUrl/token',
        body: _serializeCredentials(user, password),
        headers: headers,
      ),
    );

    final map = json.decode(response.body);
    return map['token'] as String;
  }
}

Now this adapter may be configured and exposed on the User model only:

@JsonSerializable()
@DataRepository([StandardJSONAdapter, BaseAdapter, AuthAdapter])
class User extends DataSupport<User> {
  // ...
}

And use it in a widget or BLoC:

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  final Repository<User> _repository;
  AuthBloc(this._repository);

  @override
  Stream<AuthState> mapEventToState(
    AuthEvent event,
  ) async* {
    yield* event.map(
      login: (e) async* {
        final user = await (_repository as AuthAdapter).login(e.email, e.password);
        yield AuthState(user);
      },

Override HTTP client: set a proxy

mixin HttpProxyAdapter<T extends DataSupport<T>> on RemoteAdapter<T> {
  final _httpClient = HttpClient();
  IOClient _ioClient;

  @override
  Future<T> withHttpClient<T>(fn) {
    _httpClient.findProxy = (uri) => "PROXY http://proxy.url/$uri";
    _ioClient = IOClient(_httpClient);
    return fn(_ioClient);
  }

  @override
  Future<void> dispose() {
    _ioClient.close();
    return super.dispose();
  }
}

Override HTTP client: increase timeout

mixin HttpProxyAdapter<T extends DataSupport<T>> on RemoteAdapter<T> {
  final _httpClient = HttpClient();
  IOClient _ioClient;

  @override
  Future<T> withHttpClient<T>(fn) {
    _httpClient.connectionTimeout = const Duration(seconds: 60);
    _ioClient = IOClient(_httpClient);
    return fn(_ioClient);
  }

  @override
  Future<void> dispose() {
    _ioClient.close();
    return super.dispose();
  }
}

Override HTTP client: HTTPS/SSL

mixin HttpProxyAdapter<T extends DataSupport<T>> on RemoteAdapter<T> {
  final _httpClient = HttpClient();
  IOClient _ioClient;

  @override
  Future<T> withHttpClient<T>(fn) {
    _httpClient.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
    _ioClient = IOClient(_httpClient);
    return fn(_ioClient);
  }

  @override
  Future<void> dispose() {
    _ioClient.close();
    return super.dispose();
  }
}

Upload file

mixin UploadUserAdapter<T extends User<T>> on RemoteAdapter<T> {
  Future<void> uploadFile(String filePath) async {
    final repository = this;

    final response = await repository.withHttpClient(
      (http.Client client) async {
        final url = '$baseUrl/$type/profile-photo';
        final tags = {'name': 'profile photo'};

        return uploadImage(
          filePath: filePath,
          client: client,
          url: url,
          headers: headers,
          tags: tags,
        );
      },
    );
    return withResponse<void>(response, (_) {
      return;
    });
  }
}

The useless adapter

Appends zzz to any ID:

mixin StupidAdapter<T extends DataSupport<T>> on RemoteAdapter<T> {
  @override
  Future<T> findOne(dynamic id,
      {bool remote = true,
      Map<String, String> params,
      Map<String, String> headers}) {
        return super.findOne('${id}zzz', remote: remote, params: params, headers: headers);
      }
}

Useless on useless

mixin FurtherStupidAdapter<T extends DataSupport<T>> on StupidAdapter<T> {
  // ...
}