validate: update README for MapField

This commit is contained in:
Tobe O 2020-05-04 14:35:16 -04:00
parent 1ed5d20ad6
commit 5b3472c677
3 changed files with 48 additions and 15 deletions

View file

@ -28,15 +28,30 @@ its usage in `package:test`):
var positiveNumberField = IntField('pos_num').match([isPositive]);
```
A `MapField` can embed a `Form` (forms covered below), and when combined with
`Field.deserialize`, can be used to deserialize structured data as a body field:
```dart
app.post('/map_field', (req, res) async {
var form = Form(fields: [
MapField('todo', todoForm).deserialize(Todo.fromMap),
]);
var data = await form.validate(req);
print(data['todo'] is Todo);
});
```
There are several included field types:
* `TextField`
* `BoolField`
* `NumField`
* `DoubleField`
* `IntField`
* `DateTimeField`
* `FileField`
* `ImageField`
* `TextField` - Standard text input.
* `BoolField` - Checks if a field is present; used for checkboxes.
* `NumField` - Base class that parses input as a number.
* `DoubleField` - Specialization of `NumField` for doubles.
* `IntField` - Specialization of `NumField` for integers.
* `DateTimeField` - Parses an input as an ISO-8601 date.
* `FileField` - Validates a file in `req.uploadedFiles`.
* `ImageField` - Uses `package:image` to decode an `UploadedFile` into an image.
* `MapField` - Validates a Map using a Form.
# Forms
The `Form` class lets you combine `Field` instances, and decode
@ -55,9 +70,15 @@ var todo = await todoForm.deserialize(req, TodoSerializer.fromMap);
// Same as above, but with a Codec<Todo, Map> (i.e. via `angel_serialize`).
var todo = await todoForm.decode(req, todoSerializer);
// Same as above, but returns the plain Map without any deserialization.
var todoMap = await todoForm.validate(req);
// Lower-level functionality, typically not called directly.
// Use it if you want to handle validation errors directly, without
// throwing exceptions.
var result = await todoForm.read(req);
print(result.isSuccess);
print(result.errors.length);
@serializable
class _Todo {

View file

@ -72,13 +72,18 @@ Future<void> main() async {
</html>
''');
});
app.post('/b', (req, res) async {
// You can use a [MapField] to embed one [Form] with another.
// In this example, we embed the [todoForm], but also call `.deserialize`,
// so that the final value we see is a [Todo] instance, rather than a [Map].
app.post('/map_field', (req, res) async {
var form = Form(fields: [
MapField('todo', todoForm),
MapField('todo', todoForm).deserialize(Todo.fromMap),
]);
var data = await form.read(req);
return data;
var data = await form.validate(req);
var b = StringBuffer();
b.write(data);
return b.toString();
});
app.fallback((req, res) => throw AngelHttpException.notFound());
@ -103,4 +108,7 @@ class Todo {
static Todo fromMap(Map map) {
return Todo(map['text'] as String, map['is_complete'] as bool);
}
@override
String toString() => 'Todo($text, $isComplete)';
}

View file

@ -115,7 +115,9 @@ class _MatchedField<T> extends Field<T> {
Future<FieldReadResult<T>> read(
Map<String, dynamic> fields, Iterable<UploadedFile> files) async {
var result = await inner.read(fields, files);
if (!result.isSuccess) {
if (result == null) {
return null;
} else if (!result.isSuccess) {
return result;
} else {
var errors = <String>[];
@ -149,7 +151,9 @@ class _DeserializeField<T, U> extends Field<U> {
FutureOr<FieldReadResult<U>> read(
Map<String, dynamic> fields, Iterable<UploadedFile> files) async {
var result = await inner.read(fields, files);
if (!result.isSuccess) {
if (result == null) {
return null;
} else if (!result.isSuccess) {
return FieldReadResult.failure(result.errors);
} else {
return FieldReadResult.success(await converter(result.value));