-
Notifications
You must be signed in to change notification settings - Fork 123
/
main_json_serializable.dart
128 lines (102 loc) · 3.59 KB
/
main_json_serializable.dart
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
124
125
126
127
128
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);
});
main() async {
final converter = 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>(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),
);
}
}