-
Notifications
You must be signed in to change notification settings - Fork 130
Expand file tree
/
Copy pathmain_json_serializable.dart
More file actions
123 lines (97 loc) · 3.58 KB
/
main_json_serializable.dart
File metadata and controls
123 lines (97 loc) · 3.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import 'dart:async';
import 'package:chopper/chopper.dart';
import 'package:chopper_example/json_serializable.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
/// Simple client to have working example without remote server
final client = MockClient((req) async {
if (req.method == 'POST') {
return http.Response('{"type":"Fatal","message":"fatal erorr"}', 500);
}
if (req.method == 'GET' && req.headers['test'] == 'list') {
return http.Response('[{"id":"1","name":"Foo"}]', 200);
}
return http.Response('{"id":"1","name":"Foo"}', 200);
});
Future<void> main() async {
final converter = const JsonSerializableConverter({
Resource: Resource.fromJsonFactory,
});
final chopper = ChopperClient(
client: client,
baseUrl: Uri.parse('http://localhost:8000'),
// bind your object factories here
converter: converter,
errorConverter: converter,
services: [
// the generated service
MyService.create(),
],
/* Interceptors */
interceptors: [AuthInterceptor()],
);
final myService = chopper.getService<MyService>();
final response1 = await myService.getResource('1');
print('response 1: ${response1.body}'); // undecoded String
final response2 = await myService.getResources();
print('response 2: ${response2.body}'); // decoded list of Resources
final response3 = await myService.getTypedResource();
print('response 3: ${response3.body}'); // decoded Resource
final response4 = await myService.getMapResource('1');
print('response 4: ${response4.body}'); // undecoded Resource
try {
await myService.newResource(Resource('3', 'Super Name'));
} on Response catch (error) {
print(error.body);
}
}
class AuthInterceptor implements Interceptor {
@override
FutureOr<Response<BodyType>> intercept<BodyType>(
Chain<BodyType> chain,
) async {
return chain.proceed(applyHeader(chain.request, 'Authorization', '42'));
}
}
typedef JsonFactory<T> = T Function(Map<String, dynamic> json);
class JsonSerializableConverter extends JsonConverter {
final Map<Type, JsonFactory> factories;
const JsonSerializableConverter(this.factories);
T? _decodeMap<T>(Map<String, dynamic> values) {
/// Get jsonFactory using Type parameters
/// if not found or invalid, throw error or return null
final jsonFactory = factories[T];
if (jsonFactory == null || jsonFactory is! JsonFactory<T>) {
/// throw serializer not found error;
return null;
}
return jsonFactory(values);
}
List<T> _decodeList<T>(Iterable values) =>
values.where((v) => v != null).map<T>((v) => _decode<T>(v)).toList();
dynamic _decode<T>(dynamic entity) {
if (entity is Iterable) return _decodeList<T>(entity as List);
if (entity is Map) return _decodeMap<T>(entity as Map<String, dynamic>);
return entity;
}
@override
FutureOr<Response<ResultType>> convertResponse<ResultType, Item>(
Response response,
) async {
// use [JsonConverter] to decode json
final jsonRes = await super.convertResponse(response);
return jsonRes.copyWith<ResultType>(body: _decode<Item>(jsonRes.body));
}
@override
// all objects should implements toJson method
// ignore: unnecessary_overrides
Request convertRequest(Request request) => super.convertRequest(request);
@override
FutureOr<Response> convertError<ResultType, Item>(Response response) async {
// use [JsonConverter] to decode json
final jsonRes = await super.convertError(response);
return jsonRes.copyWith<ResourceError>(
body: ResourceError.fromJsonFactory(jsonRes.body),
);
}
}