angel_validate 3.0.0-alpha

validate #

Pub build status

Strongly-typed form handlers and validators for Angel.

Validation library based on the matcher library, with Angel support. Why re-invent the wheel, when you can use the same validators you already use for tests?

For convenience's sake, this library also exports matcher.

Field #

The basic unit is the Field class, which is a type-safe way to read values from a RequestContext. Here is a simple example of using a TextField instance to read a value from the URL query parameters:

app.get('/hello', (req, res) async {
  var nameField = TextField('name');
  var name = await nameField.getValue(req, query: true); // String
  return 'Hello, $name!';
});

There are several included field types:

  • TextField
  • BoolField
  • NumField
  • DoubleField
  • IntField
  • DateTimeField
  • FileField
  • ImageField

Forms #

The Form class lets you combine Field instances, and decode request bodies into Map<String, dynamic>. Unrecognized fields are stripped out of the body, so a Form is effectively a whitelist.

var todoForm = Form(fields: [
  TextField('text'),
  BoolField('is_complete'),
]);

// Validate a request body, and deserialize it immediately.
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);

// Lower-level functionality, typically not called directly.
// Use it if you want to handle validation errors directly, without
// throwing exceptions.

@serializable
class _Todo {
  String text;
  bool isComplete;
}

Form Rendering #

TODO: Docs about this

Bundled Matchers #

This library includes some Matchers for common validations, including:

  • isAlphaDash: Asserts that a String is alphanumeric, but also lets it contain dashes or underscores.
  • isAlphaNum: Asserts that a String is alphanumeric.
  • isBool: Asserts that a value either equals true or false.
  • isEmail: Asserts that a String complies to the RFC 5322 e-mail standard.
  • isInt: Asserts that a value is an int.
  • isNum: Asserts that a value is a num.
  • isString: Asserts that a value is a String.
  • isNonEmptyString: Asserts that a value is a non-empty String.
  • isUrl: Asserts that a String is an HTTPS or HTTP URL.

The remaining functionality is effectively implemented by the matcher package.

3.0.0-alpha #

  • Rewrite, based on Field and Form, rather than strings.

2.0.2 #

  • Deduplicate error messages.

2.0.1+1 #

  • Fix bug in the implementation of maxLength.

2.0.1 #

  • Patch for updated body parsing.

2.0.0 #

  • Finish update for Angel 2.

2.0.0-alpha.1 #

  • Update for Angel 2.

1.0.5-beta #

  • Use wrapMatcher on explicit values instead of throwing.
  • Add async matchers.
  • Add context-aware matchers.

1.0.4 #

  • isNonEmptyString trims strings.
  • ValidationException extends AngelHttpException.
  • Added requireField and requireFields.

example/main.dart

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 todos = <Todo>[];

  /// We can combine fields into a form; this is most
  /// useful when we immediately deserialize the form into
  /// something else.
  var todoForm = Form(fields: [
    TextField('text'),
    BoolField('is_complete'),
  ]);

  /// We can directly use a `Form` to deserialize a
  /// request body into a `Map<String, dynamic>`.
  ///
  /// By calling `deserialize` or `decode`, we can populate
  /// concrete Dart objects.
  app.post('/', (req, res) async {
    var todo = await todoForm.deserialize(req, Todo.fromMap);
    todos.add(todo);
    await res.redirect('/');
  });

  /// You can also use `Field`s to read directly from the
  /// request, without `as` casts.
  ///
  /// In this handler, we read the value of `name` from the query.
  app.get('/hello', (req, res) async {
    var nameField = TextField('name');
    var name = await nameField.getValue(req, query: true);
    return 'Hello, $name!';
  });

  /// Simple page displaying a form and some state.
  app.get('/', (req, res) {
    res
      ..contentType = MediaType('text', 'html')
      ..write('''
    <!doctype html>
    <html>
      <body>
        <h1>angel_validate</h1>
        <ul>
          ${todos.map((t) {
        return '<li>${t.text} (isComplete=${t.isComplete})</li>';
      }).join()}
        </ul>
        <form method="POST">
          <label for="text">Text:</label>
          <input id="text" name="text">
          <br>
          <label for="is_complete">Complete?</label>
          <input id="is_complete" name="is_complete" type="checkbox">
          <br>
          <button type="submit">Add Todo</button>
        </form>
      </body>
    </html>
    ''');
  });

  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);
  print('Listening at ${http.uri}');
}

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);
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  angel_validate: ^3.0.0-alpha

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:angel_validate/angel_validate.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
84
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
95
Overall:
Weighted score of the above. [more]
91
Learn more about scoring.

We analyzed this package on Feb 11, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.5

Maintenance suggestions

Package is pre-release. (-5 points)

Pre-release versions should be used with caution; their API can change in breaking ways.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0 <3.0.0
angel_framework ^2.0.0 2.1.1
duration ^2.0.0 2.0.9
html_builder ^1.0.0 1.0.5
http_parser ^3.0.0 3.1.3
image ^2.0.0 2.1.12
matcher ^0.12.5 0.12.6
Transitive dependencies
angel_container 1.1.0
angel_http_exception 1.1.0
angel_model 1.0.3
angel_route 3.1.0+1
archive 2.0.13
args 1.5.2
charcode 1.1.2
code_buffer 1.0.1
collection 1.14.12
combinator 1.1.0
convert 2.1.1
crypto 2.1.4
dart2_constant 1.0.2+dart2
file 5.1.0
http2 1.0.0
http_server 0.9.8+3
intl 0.16.1
logging 0.11.4
merge_map 1.0.2
meta 1.1.8
mime 0.9.6+3
mock_request 1.0.6
path 1.6.4
petitparser 3.0.0
quiver 2.1.2+1
quiver_hashcode 2.0.0
recase 2.0.1 3.0.0
source_span 1.6.0
stack_trace 1.9.3
string_scanner 1.0.5
term_glyph 1.1.0
tuple 1.0.3
typed_data 1.1.6
uuid 2.0.4
xml 3.7.0
Dev dependencies
angel_orm ^2.1.0-beta
angel_orm_generator ^2.1.0-beta
angel_serialize ^2.0.0
angel_serialize_generator ^2.0.0
build_runner ^1.0.0
pedantic ^1.0.0
pretty_logging ^1.0.0
test ^1.0.0