Last active
February 27, 2021 21:02
-
-
Save roipeker/87177aadb7908ea533ecbe8fd73c768d to your computer and use it in GitHub Desktop.
Dart generic api response.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * 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(); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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}}'; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * 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; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// 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