1.0.4
This commit is contained in:
parent
53c9de3d5e
commit
1c478f0b4a
12 changed files with 70 additions and 26 deletions
|
@ -1,3 +0,0 @@
|
|||
analyzer:
|
||||
strong-mode: true
|
||||
exclude: ./scripts-bin/**/*.dart
|
4
CHANGELOG.md
Normal file
4
CHANGELOG.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# 1.0.4
|
||||
* `isNonEmptyString` trims strings.
|
||||
* `ValidationException` extends `AngelHttpException`.
|
||||
* Added `requireField` and `requireFields`.
|
|
@ -92,7 +92,10 @@ to throw an error if it is not present.
|
|||
```dart
|
||||
main() {
|
||||
var validator = new Validator({
|
||||
'googleId*': isString
|
||||
'googleId*': isString,
|
||||
|
||||
// You can also use `requireField`
|
||||
requireField('googleId'): isString,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
|
3
analysis_options.yaml
Normal file
3
analysis_options.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
analyzer:
|
||||
strong-mode:
|
||||
implicit-casts: false
|
|
@ -4,3 +4,10 @@ library angel_validate;
|
|||
export 'package:matcher/matcher.dart';
|
||||
export 'src/matchers.dart';
|
||||
export 'src/validator.dart';
|
||||
|
||||
/// Marks a field name as required.
|
||||
String requireField(String field) => '$field*';
|
||||
|
||||
/// Marks multiple fields as required.
|
||||
String requireFields(Iterable<String> fields) =>
|
||||
fields.map(requireField).join(', ');
|
||||
|
|
|
@ -88,7 +88,7 @@ RequestMiddleware validateQuery(Validator validator,
|
|||
HookedServiceEventListener validateEvent(Validator validator,
|
||||
{String errorMessage: 'Invalid data.'}) {
|
||||
return (HookedServiceEvent e) {
|
||||
var result = validator.check(e.data);
|
||||
var result = validator.check(e.data as Map);
|
||||
|
||||
if (result.errors.isNotEmpty) {
|
||||
throw new AngelHttpException.badRequest(
|
||||
|
|
|
@ -34,7 +34,8 @@ final Matcher isString = predicate((value) => value is String, 'a String');
|
|||
|
||||
/// Asserts that a value is a non-empty `String`.
|
||||
final Matcher isNonEmptyString = predicate(
|
||||
(value) => value is String && value.isNotEmpty, 'a non-empty String');
|
||||
(value) => value is String && value.trim().isNotEmpty,
|
||||
'a non-empty String');
|
||||
|
||||
/// Asserts that a `String` is an `http://` or `https://` URL.
|
||||
///
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:angel_http_exception/angel_http_exception.dart';
|
||||
import 'package:matcher/matcher.dart';
|
||||
|
||||
final RegExp _asterisk = new RegExp(r'\*$');
|
||||
|
@ -19,13 +20,13 @@ Map<String, dynamic> autoParse(Map inputData, Iterable<String> fields) {
|
|||
|
||||
for (var key in inputData.keys) {
|
||||
if (!fields.contains(key)) {
|
||||
data[key] = inputData[key];
|
||||
data[key.toString()] = inputData[key];
|
||||
} else {
|
||||
try {
|
||||
var n = inputData[key] is num
|
||||
? inputData[key]
|
||||
: num.parse(inputData[key].toString());
|
||||
data[key] = n == n.toInt() ? n.toInt() : n;
|
||||
data[key.toString()] = n == n.toInt() ? n.toInt() : n;
|
||||
} catch (e) {
|
||||
// Invalid number, don't pass it
|
||||
}
|
||||
|
@ -38,7 +39,7 @@ Map<String, dynamic> autoParse(Map inputData, Iterable<String> fields) {
|
|||
/// Removes undesired fields from a `Map`.
|
||||
Map<String, dynamic> filter(Map inputData, Iterable<String> only) {
|
||||
return inputData.keys.fold(<String, dynamic>{}, (map, key) {
|
||||
if (only.contains(key)) map[key] = inputData[key];
|
||||
if (only.contains(key.toString())) map[key.toString()] = inputData[key];
|
||||
return map;
|
||||
});
|
||||
}
|
||||
|
@ -153,7 +154,7 @@ class Validator extends Matcher {
|
|||
for (Matcher matcher in rules[key]) {
|
||||
try {
|
||||
if (matcher is Validator) {
|
||||
var result = matcher.check(value);
|
||||
var result = matcher.check(value as Map);
|
||||
|
||||
if (result.errors.isNotEmpty) {
|
||||
errors.addAll(result.errors);
|
||||
|
@ -310,7 +311,7 @@ class Validator extends Matcher {
|
|||
|
||||
@override
|
||||
bool matches(item, Map matchState) {
|
||||
enforce(item);
|
||||
enforce(item as Map);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -333,14 +334,18 @@ class ValidationResult {
|
|||
}
|
||||
|
||||
/// Occurs when user-provided data is invalid.
|
||||
class ValidationException {
|
||||
class ValidationException extends AngelHttpException {
|
||||
/// A list of errors that resulted in the given data being marked invalid.
|
||||
final List<String> errors = [];
|
||||
|
||||
/// A descriptive message describing the error.
|
||||
final String message;
|
||||
|
||||
ValidationException(this.message, {List<String> errors: const []}) {
|
||||
ValidationException(this.message, {List<String> errors: const []})
|
||||
: super(new FormatException(message),
|
||||
statusCode: 400,
|
||||
errors: errors ?? [],
|
||||
stackTrace: StackTrace.current) {
|
||||
if (errors != null) this.errors.addAll(errors);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
name: angel_validate
|
||||
description: Cross-platform validation library based on `matcher`.
|
||||
version: 1.0.3
|
||||
version: 1.0.4
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/validate
|
||||
environment:
|
||||
sdk: ">=1.19.0"
|
||||
sdk: ">=1.19.0 <3.0.0"
|
||||
dependencies:
|
||||
angel_framework: ^1.0.0-dev
|
||||
angel_http_exception: ^1.0.0
|
||||
matcher: ^0.12.0
|
||||
dev_dependencies:
|
||||
angel_diagnostics: ^1.0.0-dev
|
||||
angel_test: ^1.0.0-dev
|
||||
browser: ^0.10.0
|
||||
dart2_constant: ^1.0.0
|
||||
logging: ^0.11.0
|
||||
test: ^0.12.18
|
|
@ -22,6 +22,11 @@ main() {
|
|||
expect(result.errors.first, equals('Hello, world!'));
|
||||
});
|
||||
|
||||
test('requireField', () => expect(requireField('foo'), 'foo*'));
|
||||
|
||||
test('requireFields',
|
||||
() => expect(requireFields(['foo', 'bar']), 'foo*, bar*'));
|
||||
|
||||
test('todo', () {
|
||||
expect(() {
|
||||
todoSchema
|
||||
|
|
|
@ -1,30 +1,40 @@
|
|||
import 'dart:io';
|
||||
import 'package:angel_diagnostics/angel_diagnostics.dart';
|
||||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_test/angel_test.dart';
|
||||
import 'package:angel_validate/server.dart';
|
||||
import 'package:dart2_constant/convert.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:mock_request/mock_request.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
final Validator echoSchema = new Validator({'message*': isString});
|
||||
|
||||
void printRecord(LogRecord rec) {
|
||||
print(rec);
|
||||
if (rec.error != null) print(rec.error);
|
||||
if (rec.stackTrace != null) print(rec.stackTrace);
|
||||
}
|
||||
|
||||
main() {
|
||||
Angel app;
|
||||
AngelHttp http;
|
||||
TestClient client;
|
||||
|
||||
setUp(() async {
|
||||
app = new Angel();
|
||||
http = new AngelHttp(app, useZone: false);
|
||||
|
||||
app.chain(validate(echoSchema)).post('/echo',
|
||||
(RequestContext req, res) async {
|
||||
res.write('Hello, ${req.body['message']}!');
|
||||
});
|
||||
|
||||
await app.configure(logRequests(new File('log.txt')));
|
||||
app.logger = new Logger('angel')..onRecord.listen(printRecord);
|
||||
client = await connectTo(app);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
await client.close();
|
||||
await http.close();
|
||||
app = null;
|
||||
client = null;
|
||||
});
|
||||
|
@ -32,17 +42,23 @@ main() {
|
|||
group('echo', () {
|
||||
test('validate', () async {
|
||||
var response = await client.post('/echo',
|
||||
body: {'message': 'world'}, headers: {HttpHeaders.ACCEPT: '*/*'});
|
||||
body: {'message': 'world'}, headers: {'accept': '*/*'});
|
||||
print('Response: ${response.body}');
|
||||
expect(response, hasStatus(HttpStatus.OK));
|
||||
expect(response, hasStatus(200));
|
||||
expect(response.body, equals('Hello, world!'));
|
||||
});
|
||||
|
||||
test('enforce', () async {
|
||||
var response = await client.post('/echo',
|
||||
body: {'foo': 'bar'}, headers: {HttpHeaders.ACCEPT: '*/*'});
|
||||
print('Response: ${response.body}');
|
||||
expect(response, hasStatus(HttpStatus.BAD_REQUEST));
|
||||
var rq = new MockHttpRequest('POST', new Uri(path: '/echo'))
|
||||
..headers.add('accept', '*/*')
|
||||
..headers.add('content-type', 'application/json')
|
||||
..write(json.encode({'foo': 'bar'}))
|
||||
..close();
|
||||
http.handleRequest(rq);
|
||||
|
||||
var responseBody = await rq.response.transform(utf8.decoder).join();
|
||||
print('Response: ${responseBody}');
|
||||
expect(rq.response.statusCode, 400);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
|
|
Loading…
Reference in a new issue