Date: 2021-01-27
Proposed
- The Controller is responsible for the lifecycle of the framework. It reflects the starting point and the means of controll of all the needed actions that the framework must do (load deps, render views, generate routes etc).
- The framework requires a simple and easy controll to the end user.
- In turn the interaction of the user with the controller should be simple understandable and destructured in smaller steps that would provide a better grain of detail in the controll of the application, validation and error management etc.
- The framework rational requires a functional approach but in a way that would be easy for new users and in a way that it would use user's previous concept knowledge from similar frameworks in other programming languages.
The Controller would be a composition of different functions in steps as was created in the initial draft by Lukáš Rychtecký.
This would provide the user with the ability to controll each step on it's creation.
(defn controller
[]
(-> {}
(set-routes)
(set-template)
(set-response )
(set-middlewares )
(set-actions )
(set-deps)
(set-session))
)
The Controller would be 'feeded' with an initial state-map that the user would provide. The state-map would hold the data that would be needed to build the Controller. This approach is similar to the State monad but it would return only the result of the configuration and discard the initial state.
This helps in two ways:
- We can enforce a specific stucture in the definition of the state-map to the user. This would give a clearer understanding on the 'ingredients' that a controller would need to created to the user, as it would be a map which its keys would represent the different stages of the controller.
- We would be able to validate the state-map and its data.
(def state {:http-request {:method :get
:url "/hi"
:request {:action :select :params {}}}
:response {:headers (list {"Content-Type" "txt/html"}
{"charset" "UTF-8"})
:body nil}
:request-data {:model Foo
:template (comp temp)
:middlewares []}
:session-data {}
:deps {}})
;; mali schema for the State Map
(def State-map
[:map
[:http-request [:map
[:method [:enum :get :post :put]]
[:url [:vector]]
[:request [:action [:enum :select :update :delet :insert]]]]]
[:response [:map
[:headers [:vector]]
[:body [:or [:string] [:vector] [:nil]]]
]]
[:request-data [:map
[:model ;;malli schema
[:vector]]
[:template ;; hiccup or static
[:or [:vector]
[:string]]]
[:middlewares ;; list of functions to used for the middleware
[:vector]]]]
[:deps [:map]]
[:session [:map]]])
(defn controller
[state-map]
(-> {}
(set-routes state-map)
(set-template state-map)
(set-response state-map)
(set-middlewares state-map)
(set-actions state-map)
(set-deps state-map)
(set-session state-map))
)
The controller would be wraped in a thin reitit wrapper with initial approach.
- Elevates the use of reitit and its already implemented functionality and safeguards.
- Availability to perform validation on map to gurantee the correct definition of each stage.
{:route ["/hi" :get],
:template #function[poc.core/temp],
:response
{:headers ({"Content-Type" "txt/html"} {"charset" "UTF-8"}), :body nil},
:middlewares [],
:actions {:action :select, :params {}},
:deps {},
:session nil}
;; internal schema of an instance of a state-map
(def instance-map
[:map
[:route [:vector]]
[:respones [:map [:headers [:list]
:body [:or [:string] [:vector]]]]]
[:template [:or [:string] [:vector]]]
[:actions [:vector [:and [:enum :select :delete :update :insert] [:map]]]]
[:deps [:map]]
[:middlewares [:list]]
[:session [:map]]])
;;
(defn build-controller
[ctrl]
)
(defn generate-routes
[ctrl]
(ring/ring-handler
(ring/router
["/api"
(:route ctrl)]
{:data {:coercion reitit.coercion.spec/coercion
:middleware [rrc/coerce-exceptions-middleware
rrc/coerce-request-middleware
rrc/coerce-response-middleware]}})))