shelf_rest 0.1.4 shelf_rest: ^0.1.4 copied to clipboard
Shelf components that makes it easy to create uniform, hierarchical REST resources.
REST Handler for Dart Shelf #
Introduction #
Provides Shelf components that makes it easy to create uniform, hierarchical REST resources.
Usage #
In Shelf REST each REST resource is represented by a class containing methods that correspond to the REST http methods.
REST resources are typically hierarchical and this is modeled in Shelf REST as child resources.
Shelf REST uses shelf_bind to create handlers from the methods of the resource class and shelf_route to create routes for them.
For example a RESTful resource for a bank account
might have the following types of operations
Search Accounts
GET /accounts?name='Freddy'
Fetch a single Account
GET /accounts/1234
Create an Account
POST /accounts
Update an Account
PUT /accounts/1234
Delete an Account
DELETE /accounts/1234
This is the standard pattern in Shelf REST and can be implemented as follows
@RestResource('accountId')
class AccountResource {
List<Account> search(String name) => .....;
Account create(Account account) => .....;
Account update(Account account) => .....;
Account find(String accountId) => ...;
void delete(String accountId) => ...;
}
The @RestResource('accountId')
annotation tells Shelf REST to use accountId
as the path variable. The route for DELETE would look like
DELETE /accounts/{accountId}
You can then create the routes for this resource using the restRouter
function
var router = restRouter('/accounts', new AccountResource());
Shelf REST follows a standard naming convention to minimise configuration. This also serves to promote consistency in how you name your methods.
You can however override the default naming with annotations
@ResourceMethod(operation: RestOperation.FIND)
Account fetchAccount(String accountId) => ...;
Hierarchical Resources #
It is common to create hierarchical REST resources.
For example, we might want to allow deposits to be made to our account as follows
PUT -> /accounts/1234/deposits/999
This is referred to in Shelf REST as a child resource. The deposit resource is a child of the account resource.
To create a child resource we add a childResources
property to our account resource. This is a map from child path -> resource
@RestResource('accountId')
class AccountResource {
....
Map<dynamic, dynamic> childResources = {
'/deposits' : new DepositResource()
};
}
And then create the DepositResource
@RestResource('depositId')
class DepositResource {
@ResourceMethod(method: 'PUT')
Deposit create(Deposit deposit) => ...;
}
Note, that the default HTTP method for a create
operation is POST
. PUT
is often used when we know the primary key of the resource when we invoke the create.
In Shelf REST we do that by overriding the HTTP method with the ResourceMethod
annotation.
Note the routes for the DepositResource
will be created automatically when you create the router for the AccountResource
. You only pass the top resource into createRouter
(or related functions like createHandler
, bindResource
).
To see this in action simply call Shelf Route's printRoutes
function
printRoutes(router);
You can see that the following routes were created
GET -> /accounts{?name} => bound to search method
POST -> /accounts => bound to create method
GET -> /accounts/{accountId} => bound to find method
PUT -> /accounts/{accountId} => bound to update method
DELETE -> /accounts/{accountId} => bound to delete method
PUT -> /accounts/{accountId}/deposits/{depositId} => bound to create method of DepositResource
Note that any arguments that are not existing path variables will be added to the query of the uri template. So
List<Account> search(String name) => .....;
produces
GET -> /accounts{?name}
Middleware #
You can add middleware that will be included in the route created for a resource method using the ResourceMethod
annotation.
@ResourceMethod(middleware: logRequests)
Account find(String accountId) => ...;
In the future middleware will likely be supported in the RestResource
annotation and possibly the childResources
property
Validation #
As shelf_bind is used to create Shelf handlers from the resource methods, validation of request parameters comes for free (courtesy of constrain).
See the shelf_bind and constrain doco for details.
Validation settings can be set at the bindResource
(and related) function and overridden via the ResourceMethod
annotation.
var router = restRouter('/accounts', new AccountResource(),
validateParameters: false);
@ResourceMethod(validateParameters: true)
Account find(String accountId) => ...;
Conventions #
Shelf REST uses the following conventions by default. Each can be overriden with annotations.
- create ... POST
TODO: more doco