Skip to content

Instantly share code, notes, and snippets.

@roipeker
Last active February 27, 2021 21:02
Show Gist options
  • Select an option

  • Save roipeker/87177aadb7908ea533ecbe8fd73c768d to your computer and use it in GitHub Desktop.

Select an option

Save roipeker/87177aadb7908ea533ecbe8fd73c768d to your computer and use it in GitHub Desktop.
Dart generic api response.
/*
* Copyright (c) 2020. roipeker™ [Rodrigo López Peker]
* All rights reserved.
*/
import 'api_response.dart';
// ignore: avoid_classes_with_only_static_members
abstract class ApiErrors {
static const defaultError = 'No se puede procesar la data';
static const _errors = <String, String>{
'user_does_not_exist': 'Usuario inexistente',
'authentication_fail': 'Datos de usuario no encontrados',
'incomplete_data': 'Datos incompletos',
'duplicated_key': 'Ya existe un usuario con este email',
'membership_same_provider_already_exist':
'Ya existe una membresía con este proveedor',
'membership_not_found': 'No encontramos una membresía con ese código',
};
static String getErrorMessage(ApiResponse response) {
try {
final json = response.jsonBody;
if (json is Map) {
final description = json['description']?.toString();
if (description != null && description.isNotEmpty) {
return json['description'].toString();
}
final key = json['msg']?.toString();
if (key != null) {
return _errors[key] ?? key;
}
}
return defaultError;
// ignore: avoid_catches_without_on_clauses
} catch (e) {
return e.toString();
}
}
}
import 'dart:convert';
import 'package:dio/dio.dart';
class ApiResponse<T> {
static final _serializerMap = <Object, Function>{};
static void register<J>(J type, Function fromJson) {
_serializerMap[type] = fromJson;
}
static ApiResponse<T> from<T>(Response response, [Function converter]) {
if (response?.statusCode != 200 ?? false) {
return ApiResponse<T>(response, null);
} else {
if (response.data is String) {
response.data = jsonDecode(response.data as String);
}
if (response.data is List) {
throw 'Use ApiResponse.fromList() instead, response is not a Map().';
}
converter ??= _serializerMap[T];
final _data = converter(response.data);
return ApiResponse<T>(response, _data as T);
}
}
// ignore: lines_longer_than_80_chars
static ApiResponse<List<T>> fromList<T>(Response response,
[Function converter]) {
if (response.statusCode != 200) {
// todo: parse error...
return ApiResponse<List<T>>(response, null);
} else {
if (response.data is String) {
response.data = jsonDecode(response.data as String);
}
if (response.data is! List) {
throw 'Use ApiResponse.from(), response is not a List().';
}
converter ??= _serializerMap[T];
final _data = (response.data as List)
.map<T>((e) => converter(e) as T)
.where((e) => e != null)
.toList();
return ApiResponse<List<T>>(response, _data);
}
}
static T getVo<T>(dynamic data, [Function converter]) {
if (data is! Map) {
throw 'Use ApiResponse.getVoList(), response is not a Map().';
}
converter ??= _serializerMap[T];
return converter(data) as T;
}
static List<T> getVoList<T>(dynamic data, [Function converter]) {
if (data is! List) {
throw 'Use ApiResponse.getVo(), response is not a List().';
}
converter ??= _serializerMap[T];
return (data as List).map<T>((e) => converter(e) as T).toList();
}
final Response response;
final T data;
bool get cancelled => response?.statusCode == 0 ?? false;
dynamic get jsonBody {
if (response.data is String) {
return jsonDecode(response.data as String);
}
return response.data;
}
ApiResponse(this.response, this.data);
bool get isError => response != null && response.statusCode >= 400;
String get error => response?.statusMessage;
@override
String toString() {
return 'ApiResponse {isError=$isError, '
'error=$error, '
'code=${response.statusCode}, '
'data=${response.data}}';
}
}
/*
* Copyright (c) 2020. roipeker™ [Rodrigo López Peker]
* All rights reserved.
*/
import 'package:dio/dio.dart';
import '../../api_response.dart';
import '../endpoints.dart';
import 'models/response_dto.dart';
export 'models/response_dto.dart';
class CategoryEndpoint extends BaseApiEndpoint {
Dio get _dio => service.dio;
@override
void init() {
super.init();
/// generic way to register Model response.
ApiResponse.register(
MainCategoryResponseDto,
MainCategoryResponseDto.fromJson,
);
}
//
Future<ApiResponse<List<MainCategoryResponseDto>>> list() async {
final response = await _dio.get('/category/main');
final apiResponse = ApiResponse.fromList<MainCategoryResponseDto>(response);
if (apiResponse.isError) {/// notified globally.
} else {}
return apiResponse;
}
}
/// irrelevant model.
class CategoryResponseDto {
CategoryResponseDto({
this.tags,
this.children,
this.id,
this.name,
this.slug,
this.updatedAt,
this.icon,
this.photo,
});
List<String> tags;
List<_Child> children;
String id;
String name;
String slug;
String updatedAt;
String icon;
String photo;
static CategoryResponseDto fromJson(Map<String, dynamic> json) =>
CategoryResponseDto(
tags: (json["tags"] as List).map((x) => x as String).toList(),
children: (json["children"] as List)
.map((x) => _Child.fromJson(x as Map<String, dynamic>))
.toList(),
id: json["_id"] as String,
name: json["name"] as String,
slug: json["slug"] as String,
updatedAt: json["updatedAt"] as String,
icon: json["icon"] as String,
photo: json["photo"] as String,
);
Map<String, dynamic> toJson() => {
"tags": List<dynamic>.from(tags.map((x) => x)),
"children": List<dynamic>.from(children.map((x) => x.toJson())),
"_id": id,
"name": name,
"slug": slug,
"updatedAt": updatedAt,
"icon": icon,
"photo": photo == null ? null : photo,
};
}
class _Child {
_Child({
this.name,
this.slug,
this.photo,
this.tags,
});
String name;
String slug;
String photo;
List<String> tags;
factory _Child.fromJson(Map<String, dynamic> json) => _Child(
name: json["name"] as String,
slug: json["slug"] as String,
photo: json["photo"] as String,
tags: (json["tags"] as List).map((x) => x as String).toList(),
);
Map<String, dynamic> toJson() => {
"name": name,
"slug": slug,
"photo": photo == null ? null : photo,
"tags": List<dynamic>.from(tags.map((x) => x)),
};
}
class MainCategoryResponseDto {
MainCategoryResponseDto({
this.name,
this.slug,
this.icon,
});
String name;
String slug;
String icon;
static MainCategoryResponseDto fromJson(Map<String, dynamic> json) =>
MainCategoryResponseDto(
name: json["name"] as String,
slug: json["slug"] as String,
icon: json["icon"] as String,
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment