Updated client

This commit is contained in:
thomashii 2021-07-15 16:11:54 +08:00
parent 6dbc1f5b9a
commit 38cc17e381
8 changed files with 85 additions and 5 deletions

View file

@ -1,6 +1,11 @@
# Change Log
## 4.0.2
* Added logging
* Added unit test for authentication
## 4.0.1
* Updated README

View file

@ -1,12 +1,12 @@
# Angel3 Client
[![version](https://img.shields.io/badge/pub-v4.0.1-brightgreen)](https://pub.dartlang.org/packages/angel3_client)
[![version](https://img.shields.io/badge/pub-v4.0.2-brightgreen)](https://pub.dartlang.org/packages/angel3_client)
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)
[![License](https://img.shields.io/github/license/dukefirehawk/angel)](https://github.com/dukefirehawk/angel/tree/angel3/packages/client/LICENSE)
A browser, mobile and command line based client that supports querying Angel3 servers
A browser, mobile and command line based client that supports querying Angel3 backend.
## Usage

View file

@ -5,6 +5,7 @@ import 'dart:async';
import 'package:collection/collection.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:logging/logging.dart';
export 'package:angel3_http_exception/angel3_http_exception.dart';
/// A function that configures an [Angel] client in some way.
@ -18,6 +19,8 @@ typedef AngelDeserializer<T> = T? Function(dynamic x);
/// Represents an Angel server that we are querying.
abstract class Angel extends http.BaseClient {
final _log = Logger('Angel');
/// A mutable member. When this is set, it holds a JSON Web Token
/// that is automatically attached to every request sent.
///

View file

@ -8,6 +8,7 @@ import 'package:http/src/request.dart' as http;
import 'package:http/src/response.dart' as http;
import 'package:http/src/streamed_response.dart' as http;
import 'package:path/path.dart';
import 'package:logging/logging.dart';
import 'angel3_client.dart';
const Map<String, String> _readHeaders = {'Accept': 'application/json'};
@ -47,6 +48,7 @@ AngelHttpException failure(http.Response response,
}
abstract class BaseAngelClient extends Angel {
final _log = Logger('BaseAngelClient');
final StreamController<AngelAuthResult> _onAuthenticated =
StreamController<AngelAuthResult>();
final List<Service> _services = [];
@ -89,6 +91,8 @@ abstract class BaseAngelClient extends Angel {
try {
//var v = json.decode(response.body);
_log.info(response.headers);
var v = jsonDecode(response.body);
if (v is! Map || !v.containsKey('data') || !v.containsKey('token')) {
@ -102,6 +106,7 @@ abstract class BaseAngelClient extends Angel {
} on AngelHttpException {
rethrow;
} catch (e, st) {
_log.severe('Authentication failed');
throw failure(response, error: e, stack: st);
}
}
@ -147,6 +152,7 @@ abstract class BaseAngelClient extends Angel {
request.bodyFields =
body.map((k, v) => MapEntry(k, v is String ? v : v.toString()));
} else {
_log.severe('Body is not a String, List<int>, or Map<String, String>');
throw ArgumentError.value(body, 'body',
'must be a String, List<int>, or Map<String, String>.');
}

View file

@ -5,12 +5,14 @@ import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:angel3_json_god/angel3_json_god.dart' as god;
import 'package:path/path.dart' as p;
import 'package:logging/logging.dart';
import 'angel3_client.dart';
import 'base_angel_client.dart';
export 'angel3_client.dart';
/// Queries an Angel server via REST.
class Rest extends BaseAngelClient {
//final _log = Logger('REST');
final List<Service> _services = [];
Rest(String path) : super(http.Client() as http.BaseClient, path);
@ -42,6 +44,8 @@ class Rest extends BaseAngelClient {
/// Queries an Angel service via REST.
class RestService<Id, Data> extends BaseAngelService<Id, Data> {
final _log = Logger('RestService');
final Type? type;
RestService(http.BaseClient client, BaseAngelClient app, url, this.type)
@ -49,7 +53,7 @@ class RestService<Id, Data> extends BaseAngelService<Id, Data> {
@override
Data? deserialize(x) {
print(x);
_log.info(x);
if (type != null) {
return x.runtimeType == type
? x as Data?
@ -61,7 +65,7 @@ class RestService<Id, Data> extends BaseAngelService<Id, Data> {
@override
String makeBody(x) {
print(x);
_log.info(x);
if (type != null) {
return super.makeBody(god.serializeObject(x));
}

View file

@ -1,5 +1,5 @@
name: angel3_client
version: 4.0.1
version: 4.0.2
description: A browser, mobile and command line based client that supports querying Angel3 servers
homepage: https://angel3-framework.web.app/
repository: https://github.com/dukefirehawk/angel/tree/angel3/packages/client
@ -12,11 +12,13 @@ dependencies:
http: ^0.13.1
meta: ^1.3.0
path: ^1.8.0
logging: ^1.0.0
dev_dependencies:
angel3_framework: ^4.0.0
angel3_model: ^3.0.0
angel3_mock_request: ^2.0.0
angel3_container: ^3.0.0
angel3_auth: ^4.0.0
async: ^2.6.1
build_runner: ^1.12.2
build_web_compilers: ^2.16.5

View file

@ -76,6 +76,7 @@ void main() {
test('credentials send right body', () async {
await app
.authenticate(type: 'local', credentials: {'username': 'password'});
print(app.client.spec?.headers);
expect(
await read(app.client.spec!.request.finalize()),
json.encode({'username': 'password'}),

View file

@ -0,0 +1,59 @@
import 'package:angel3_auth/angel3_auth.dart';
import 'package:angel3_client/io.dart' as c;
import 'package:angel3_framework/angel3_framework.dart';
import 'package:angel3_framework/http.dart';
import 'package:logging/logging.dart';
import 'package:test/test.dart';
const Map<String, String> USER = {'username': 'foo', 'password': 'bar'};
var localOpts = AngelAuthOptions<Map<String, String>>(canRespondWithJson: true);
void main() {
late Angel app;
late AngelHttp http;
late c.Angel client;
setUp(() async {
app = Angel();
http = AngelHttp(app, useZone: false);
var auth = AngelAuth(
serializer: (_) async => 'baz', deserializer: (_) async => USER);
auth.strategies['local'] = LocalAuthStrategy(
(username, password) async {
if (username == 'foo' && password == 'bar') {
return USER;
}
return {};
},
);
app.post('/auth/local', auth.authenticate('local', localOpts));
await app.configure(auth.configureServer);
app.logger = Logger('auth_test')
..onRecord.listen((rec) {
print(
'${rec.time}: ${rec.level.name}: ${rec.loggerName}: ${rec.message}');
});
var server = await http.startServer();
client = c.Rest('http://${server.address.address}:${server.port}');
});
tearDown(() {
http.close();
client.close();
});
test('auth event fires', () async {
var localAuth = await client.authenticate(type: 'local', credentials: USER);
print('JWT: ${localAuth.token}');
print('Data: ${localAuth.data}');
expect(localAuth.data, USER);
});
}