Skip to content

Commit 910d6d0

Browse files
committed
api [nfc]: Pull some common logic into an ApiConnection class
1 parent 9c1128e commit 910d6d0

File tree

3 files changed

+57
-31
lines changed

3 files changed

+57
-31
lines changed

lib/api/core.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import 'dart:convert';
2+
3+
import 'package:http/http.dart' as http;
4+
5+
abstract class Auth {
6+
String get realmUrl;
7+
8+
String get email;
9+
10+
String get apiKey;
11+
}
12+
13+
class ApiConnection {
14+
ApiConnection({required this.auth});
15+
16+
final Auth auth;
17+
18+
Map<String, String> _headers() {
19+
// TODO memoize
20+
final authBytes = utf8.encode("${auth.email}:${auth.apiKey}");
21+
return {
22+
'Authorization': 'Basic ${base64.encode(authBytes)}',
23+
};
24+
}
25+
26+
Future<String> post(String route, Map<String, dynamic>? params) async {
27+
final response = await http.post(
28+
Uri.parse("${auth.realmUrl}/api/v1/$route"),
29+
headers: _headers(),
30+
body: params?.map((k, v) => MapEntry(k, jsonEncode(v))));
31+
if (response.statusCode != 200) {
32+
throw Exception("error on $route: status ${response.statusCode}");
33+
}
34+
return response.body;
35+
}
36+
}

lib/api/route/register_queue.dart

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,21 @@
11
import 'dart:convert';
22

3-
import 'package:http/http.dart' as http;
4-
5-
import '../../store.dart';
3+
import '../core.dart';
64
import '../model/initial_snapshot.dart';
75

86
/// https://zulip.com/api/register-queue
9-
Future<InitialSnapshot> registerQueue(Account account) async {
10-
final response = await http.post(
11-
Uri.parse("${account.realmUrl}/api/v1/register"),
12-
headers: _headers(account),
13-
body: {
14-
'apply_markdown': 'true',
15-
'slim_presence': 'true',
16-
'client_capabilities': jsonEncode({
17-
'notification_settings_null': true,
18-
'bulk_message_deletion': true,
19-
'user_avatar_url_field_optional': true,
20-
'stream_typing_notifications': false, // TODO implement
21-
'user_settings_object': true,
22-
}),
23-
});
24-
if (response.statusCode != 200) {
25-
throw Exception("registerQueue: status ${response.statusCode}");
26-
}
27-
final json = jsonDecode(response.body);
7+
Future<InitialSnapshot> registerQueue(ApiConnection connection) async {
8+
final data = await connection.post('register', {
9+
'apply_markdown': true,
10+
'slim_presence': true,
11+
'client_capabilities': {
12+
'notification_settings_null': true,
13+
'bulk_message_deletion': true,
14+
'user_avatar_url_field_optional': true,
15+
'stream_typing_notifications': false, // TODO implement
16+
'user_settings_object': true,
17+
},
18+
});
19+
final json = jsonDecode(data);
2820
return InitialSnapshot.fromJson(json);
2921
}
30-
31-
Map<String, String> _headers(Account account) {
32-
final authBytes = utf8.encode("${account.email}:${account.apiKey}");
33-
return {
34-
'Authorization': 'Basic ${base64.encode(authBytes)}',
35-
};
36-
}

lib/store.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:flutter/foundation.dart';
22

3+
import 'api/core.dart';
34
import 'api/model/initial_snapshot.dart';
45
import 'api/route/register_queue.dart';
56
import 'credential_fixture.dart' as credentials; // prototyping hack; not in Git
@@ -8,9 +9,10 @@ class PerAccountStore extends ChangeNotifier {
89
// Load the user's data from storage. (Once we have such a thing.)
910
static Future<PerAccountStore> load() async {
1011
const account = _fixtureAccount;
12+
final connection = ApiConnection(auth: account);
1113

1214
final stopwatch = Stopwatch()..start();
13-
final initialSnapshot = await registerQueue(account); // TODO retry
15+
final initialSnapshot = await registerQueue(connection); // TODO retry
1416
final t = (stopwatch..stop()).elapsed;
1517
// TODO log the time better
1618
if (kDebugMode) print("initial fetch time: ${t.inMilliseconds}ms");
@@ -36,11 +38,14 @@ const Account _fixtureAccount = Account(
3638
apiKey: credentials.api_key,
3739
);
3840

39-
class Account {
41+
class Account implements Auth {
4042
const Account(
4143
{required this.realmUrl, required this.email, required this.apiKey});
4244

45+
@override
4346
final String realmUrl;
47+
@override
4448
final String email;
49+
@override
4550
final String apiKey;
4651
}

0 commit comments

Comments
 (0)