diff --git a/example/main.dart b/example/main.dart
index 8b137891..3d747d7a 100644
--- a/example/main.dart
+++ b/example/main.dart
@@ -1 +1,62 @@
+import 'package:angel_framework/angel_framework.dart';
+import 'package:angel_framework/http.dart';
+import 'package:angel_validate/angel_validate.dart';
+import 'package:http_parser/http_parser.dart';
+import 'package:logging/logging.dart';
+import 'package:pretty_logging/pretty_logging.dart';
+main() async {
+ Logger.root
+ ..level = Level.ALL
+ ..onRecord.listen(prettyLog);
+
+ var app = Angel(logger: Logger('angel_validate'));
+ var http = AngelHttp(app);
+
+ var todoForm = Form(fields: [
+
+ ]);
+
+ app.get('/', (req, res) {
+ res
+ ..contentType = MediaType('text', 'html')
+ ..write('''
+
+
+
+
+
+
+ ''');
+ });
+
+ app.fallback((req, res) => throw AngelHttpException.notFound());
+
+ app.errorHandler = (e, req, res) {
+ res.writeln('Error ${e.statusCode}: ${e.message}');
+ for (var error in e.errors) {
+ res.writeln('* $error');
+ }
+ };
+
+ await http.startServer('127.0.0.1', 3000);
+}
+
+class Todo {
+ final String text;
+ final bool isComplete;
+
+ Todo(this.text, this.isComplete);
+
+ static Todo fromMap(Map map) {
+ return Todo(map['text'] as String, map['is_complete'] as bool);
+ }
+}
diff --git a/lib/angel_forms.dart b/lib/angel_forms.dart
deleted file mode 100644
index da383990..00000000
--- a/lib/angel_forms.dart
+++ /dev/null
@@ -1,2 +0,0 @@
-export 'src/field.dart';
-export 'src/form.dart';
diff --git a/lib/angel_validate.dart b/lib/angel_validate.dart
new file mode 100644
index 00000000..70a535c6
--- /dev/null
+++ b/lib/angel_validate.dart
@@ -0,0 +1,4 @@
+export 'src/field.dart';
+export 'src/form.dart';
+export 'src/form_renderer.dart';
+export 'src/matchers.dart';
diff --git a/lib/src/form.dart b/lib/src/form.dart
index 15e1f37f..6910874e 100644
--- a/lib/src/form.dart
+++ b/lib/src/form.dart
@@ -9,25 +9,24 @@ import 'field.dart';
///
/// Example:
/// ```dart
-/// import 'package:angel_forms/angel_forms.dart';
/// import 'package:angel_validate/angel_validate.dart';
///
/// var myForm = Form(fields: [
-/// TextField('username').match([]),
+/// TextField('username').match([minLength(8)]),
/// TextField('password', confirmedAs: 'confirm_password'),
/// ])
///
/// app.post('/login', (req, res) async {
-/// var loginRequest =
-/// await myForm.decode(req, loginRequestSerializer);
-/// // Do something with the decode object...
+/// var loginBody =
+/// await myForm.decode(req, loginBodySerializer);
+/// // Do something with the decoded object...
/// });
/// ```
class Form {
+ /// A custom error message to provide the user if validation fails.
final String errorMessage;
final List _fields = [];
- final List _errors = [];
static const String defaultErrorMessage =
'There were errors in your submission. '
@@ -37,10 +36,11 @@ class Form {
fields?.forEach(addField);
}
+ /// Returns the fields in this form.
List get fields => _fields;
- List get errors => _errors;
-
+ /// Helper for adding fields. Passing [matchers] will result in them
+ /// being applied to the [field].
Field addField(Field field, {Iterable matchers}) {
if (matchers != null) {
field = field.match(matchers);
@@ -49,15 +49,19 @@ class Form {
return field;
}
+ /// Deserializes the result of calling [validate].
Future deserialize(
RequestContext req, T Function(Map) f) {
return validate(req).then(f);
}
+ /// Uses the [codec] to [deserialize] the result of calling [validate].
Future decode(RequestContext req, Codec codec) {
return deserialize(req, codec.decode);
}
+ /// Calls [read], and returns the filtered request body.
+ /// If there is even one error, then an [AngelHttpException] is thrown.
Future