Role-filtered view model support for Hapi
hapi View Models
A plugin to provide a concept of 'view-models' to hapi.
Purpose
When rendering payloads from an API, we often want to provide different subsets (or supersets) of data to users with different roles, or scopes. By leveraging lodash.omit
and server.decorate
, we can contain the complexity of doing this as a fairly neat abstraction, reducing the overall complexity of payload modification and filtering, and keeping our controllers clean.
With hapi-view-models
it is possible to render a variety of different versions of a single entity (payload) from a single endpoint.
Installing
Installing is done in the usual way
npm install hapi-view-models
Usage
The vm
reply helper allows you to render views of your data:
const KeyPairViewModel = require('...') server.route({ ... handler (request, reply) { reply.vm(KeyPairViewModel, response) } })
Where vm takes the KeyPairViewModel and filters the data inside response according to the user's scope. Response can be a single entity or an array of entities.
If you're returning a response envelope you can provide a path to the entity as a third argument to the vm reply helper.
-- -------------------- ---- ------- ----- ---------------- - -------------- -------------- --- ------- --------- ------ - -------------------------- - ------- - ----- ----- - -- -------------- - --
Real World Example
Suppose we owned a cryptocurrency exchange. That's very 'of the moment', isn't it?
Lets say our wallet owner has a role of 'owner', and a visitor doesn't have this role.
We'd want to build a view model to render a wallet's data in a secure way. We declare a set of properties that are included in the payload for each role. Including a property in a role automatically excludes that data from all other roles.
Roles are defined by hapi in request.auth.credentials.scope
and are controlled by your auth mechanism.
Our view model extends ViewModel and looks like this:
-- -------------------- ---- ------- ----- - --------- - - --------------------------- ----- ---------------- ------- --------- - --- -------- -- - ------ - ------ ----------- - - -
And our handler would look something like this:
-- -------------------- ---- ------- ----- - ------ - - --------------------------- ----- ---------------- - -------------------------------------- -- -------- --- ------ ---- ---- ----------------------- --- -- - ------------------- -- -------- ------------- --------- - -- ------- ---- - --------- ---- ---- ------- ----- ------- - - -------- -------- ------- ------- - - -------------- ------- ------ ----- -------------------- -------- -------- --------- ------ - ----- ------- - ------------------------------------- -------------------------- -------- - --
The rendered data would look something like this:
-- -------------------- ---- ------- -- -- --- ----- -------- --- ------ - -------- -------- ------- ------- - -- --- -- - ------- -------- --- ------ - ------- ------- -
Understanding get includes()
The getter method get includes()
or just .includes
as a property on your view model is a mapping of scope
to an array of properties that are (deep) filtered from the resultant payload. This means we also support nesting!
This means you can do:
-- -------------------- ---- ------- ----- ---- - - -- - ---- ----- -- -- - -- ------ ------ -- - -- ----------- - - - ----- ------------- ------- --------- - --- -------- -- - ------ - ------ ------ -- ---- - --- --- -------- --- ------ ----- ---- -- ---- - --- --- -------- --- --- --- ------ --------- -- ------- ---- ----- --- --- --- - --- ---- --- --- -------- -- --- ---- -- ---- -- ------- -- ------- - - -
You'll notice something going on here with includes. Includes is an 'exclusive' mapping. This means that if you declare a property visible by a role, it is hidden for all other roles. This means that you can minimally hide role-sensitive data, without having to re-iterate yourself or risk the leak of private properties leaking through.
TL;DR: Once a property is declared as visible to a role, it is automatically invisible to all other roles.
Ideally your user should have all the roles it needs to see all the data it needs, but if you like, you can 're-declare' visibility as we have done in the ase of role2
above. A user wanting to see a
can have roles role1
, role2
, or both. a
(and as a result a.foo
) isn't visible to any other roles.
Structure
The plugin exports two modules:
plugin
which is thehapi
plugin providingreply.vm()
ViewModel
which is the base class your view models should extend.
The plugin uses a slightly stricter extension of standard-style
Contributing
To contribute to the plugin, fork it to your own github account, create a branch, make your changes, and submit a PR.
Note that Vendigo Finance Ltd requires that you include tests to cover your new code, along with your PR in order to get it merged.
To run our test suite:
npm install npm test npm run lint
HomePage
https://github.com/vendigo-group/hapi-view-models#readme
Repository
git+https://github.com/vendigo-group/hapi-view-models.git
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/60056c7581e8991b448e5f23