shelf_bind 0.3.0 copy "shelf_bind: ^0.3.0" to clipboard
shelf_bind: ^0.3.0 copied to clipboard

outdatedDart 1 only

A binding handler for shelf

Binding Handler for Dart Shelf #

Introduction #

Provides Shelf middleware for binding Shelf request and response data to class properties.

Shelf Bind currently supports the following bindings:

  • Binding to Shelf Route path variables
  • Binding request Json Body

No response bindings yet.

Using #

Binding to Shelf Route Path Variables #

Binding via Constructor

Binding a simple path variable

final routeHandler = route.router()
      ..get('/person/{name}', bind.bind(Person, {'name': #firstname}, _handlePerson))
      .handler

This binds the path variable called name as defined in the path /person/{name} to the named argument called firstname of the Person.build constructor and calling the _handlePerson function when matched.

The constructor looks like

Person.build({String firstname}) : this(firstname);

The handlers for Shelf Bind differ from the standard Shelf handlers as folows:

  • They take the bound object as the first argument
  • They optionally take the request as a second argument
  • They can return either a Response / Future<Response> as normal or else any object that has a toJson method. For example Person / Future<Person>

The handler in this example looks like

Person _handlePerson(Person person) { 
  return person; 
}

Note build is the default name for the constructor. It can be overriden by passing the constructor parameter to bind

final routeHandler = route.router()
      ..get('/person/{name}', bind.bind(Person, {'name': #firstname}, _handlePerson, 
      		constructor: #foo))
      .handler

Would look for a constructor Person.foo({String firstname}).

Query Params

To bind to a query parameter

final routeHandler = route.router()
      ..get('/person{?name}', bind.bind(Person, {'name': #firstname}, _handlePerson))
      .handler

The only change was that path passed to get is now '/person{?name}'

Binding via Properties

If you prefer, you can bind via properties (fields or setters) instead of via the constructor.

To do that you specify the bindMode named argument as BindMode.PROPERTY (default is BindMode.CONSTRUCTOR) like

final routeHandler = route.router()
      ..get('/person/{name}', bind.bind(Person, {'name': #firstname}, _handlePerson,
      		bindMode: BindMode.PROPERTY))
      .handler

plus you must have a default (unnamed) constructor that takes no mandatory arguments. For example a constructor like

class Person {
  String name;
  
  Person();
}

Binding to a Json Body #

Binding to a Json body is very similar. Instead you call the bindJsonBody function.

final routeHandler = route.router()
      ..post('/person', bind.bindJsonBody(Person, _handlePerson)))
      .handler

As this is binding to a Json map it does not take the binding map as above.

Details: Handler Functions #

Handler functions in Shelf Bind can take the following forms:

1/ A handler with an additional argument

Response handler(someType boundObject, Request request);   
OR
Future<Response> handler(someType boundObject, Request request);

2/ A handler without the Request argument

Response handler(someType boundObject);   
OR
Future<Response> handler(someType boundObject);

3/ A handler that returns some other type (that has a toJson method)

Note the return type can be any type, not necessarily the same as the boundObject

someType handler(someType boundObject, Request request);   
OR
Future<someType> handler(someType boundObject, Request request);
OR
someType handler(someType boundObject);   
OR
Future<someType> handler(someType boundObject);

Example #

Full source at example/binding_example.dart

The domain objects

class Person {
  final String name;

  Person(this.name);

  Person.build({String name}) : this(name);

  Person.fromJson(Map json) : this(json['name']);

  Map toJson() => { 'name': name };

  String toString() => 'Person[name: $name]';
}

A simple handler that just echos back the bound person

Person _handlePerson(Person person) {
  print(person);
  return person;
}

The routes and bindings

  final pathBindHandler = bind.bind(Person, {'name': #name}, _handlePerson);

  var router = (route.router()
      ..get('/person/{name}', pathBindHandler)
      ..get('/person{?name}', pathBindHandler)
      ..post('/person', bind.bindJsonBody(Person, _handlePerson)))
      .handler;

  var handler = const shelf.Stack()
      .addMiddleware(shelf.logRequests())
      .addHandler(router);

Serve it up


  io.serve(handler, 'localhost', 8080).then((server) {
    print('Serving at http://${server.address.host}:${server.port}');
  });
}

Try it out

First route

curl http://localhost:8080/person/fred

The output should look like

GET http://localhost:8080/person/fred => {name: fred}

Second route

curl http://localhost:8080/person?name=fred

Third route (json POST)

curl -d '{"name": "fred"}' http://localhost:8080/person

TODO #

See open issues.

Contributing #

If you want to contribute, please:

  1. fork the repo and implement your changes with good unit test coverage of your changes
  2. create a pull request
  3. create an issue detailing the change and link the PR to it
0
likes
0
pub points
20%
popularity

Publisher

unverified uploader

A binding handler for shelf

Homepage

License

unknown (LICENSE)

Dependencies

shelf, shelf_route

More

Packages that depend on shelf_bind