enterprise: Strawman Proposal
A friend (Michael Zhang) and I may be working on a web framework for Rust, enterprise
. This post serves as a strawman proposal for this framework, and as documentation for what the framework may eventually be.
Also note that despite the authorial "we," this is almost entirely my vision (hence the S-expressions, use of Prolog, etc.), so expect this to be a strawman that's lit aflame rather than fortified.
Introduction
The model we use for webapps is described by a dependency diagram:
As well as a dataflow diagram for server-side rendering:
In the above diagrams, yellow components are provided by enterprise
, blue components are written by the application author in Rust, and pink components are written by the application author in a DSL.
The Schema and DAL components are taken from Ted Kaminski's "Stateless MVC," which describes them in detail.
Schema
The Schema component contains type declarations for each of the "domain objects." If a type ends up being sent over the network, it should probably be declared here. Derive macros are provided to allow the Router to validate these values.
The only exports of the Schema should be types -- if you find yourself exporting functions, they probably belong in the business logic.
Actions
Actions are the atomic primitive functions that are used to define the business logic. Macros are available to define CRUD actions for types in the Schema (relative to some data store supported by the DAL).
Business Logic
The Business Logic module transforms requests into data that can be handled directly by a View.
Views
Views are written in a React-like DSL.
View Adapters
View Adapters are backends for Views -- one exists to translate to HTML, another to translate to JSON, and another that performs tree-diffing to efficiently update HTML.
Auth
The generic phrase "auth" confusingly can refer to either "authentication" or "authorization." These are conflated both by the term and in many people's heads, so we avoid it, and make a strong split between the two.
Authentication
Authentication is the answer to the question "what user does this request correspond to?" As with other parts of a web application, enterprise
simplifies authentication by abstracting it heavily.
For our app, we want to allow a plethora of authentication methods, while also allowing a user to have multiple authentication methods. (This is useful since a user might forget whether they registered with their Google account or email, and it allows an anonymous user to add an email and stop being anonymous!)
In app.sexp
:
(authentication
(multiple true)
(providers
anonymous-cookie
(email-password :reset email)
oauth-facebook
oauth-google
oauth-twitter))
In views/login.sexp
:
TODO
Authorization
Authorization is the answer to the question "can this user perform this action?" This is almost entirely application-specific, so we leave the logic here to the app author.
But wait, we're using logic on a question with a boolean answer? Well, I know the best way to do this! enterprise
apps specify authorization information with a Prolog dialect.
For our app, TODO.
In src/authorization.pro
:
authorized(UserID, Action). # TODO