Components
Widgets
Widgets are the main building blocks of Reblocks (hence the name).
At the heart of Reblocks is a tree of widgets that is manipulated by the clients requests. When a client sends its first request to a Reblocks application then a new session is started for it and a widget tree is associated with this session.
This initial widget tree 1 is computed as defined by the application developer.
A generic-function reblocks/session:init
is called by Reblocks
to initialize a new session. This function should return a single widget which become
a root of a tree:
TODO> (defmethod reblocks/session:init ((app tasks))
(declare (ignorable app))
(make-task-list "Make my first Reblocks app"
"Deploy it somewhere"
"Have a profit"))
The initial content and structure of the widget tree may depend on arbitrary factors; it is conceivable (although probably not very sensible) to generate different widget trees depending on the time of day.
A client's request for a specific URI
modifies the widget tree: widgets
called dispatchers choose their one child based on the current request
URI
.
Old version of Weblocks had a MAKE-WIDGET
function. You was able to use strings
and function designators 3 instead of widgets in this context.
Probably, we will return this functionality some day.
Actions
Apart from session initialization the widget tree may be modified by actions.
Actions are plain functions that are stored in a session hash table the keys of which are unique identifiers. This way they can be called by the browser.
When Javascript is available actions will be called via AJAX
, otherwise
a normal request will be initiated.
It is often useful to set up closures as actions.
Example of typical action usage:
(reblocks/widget:defwidget counter ()
((count :accessor count-of :initform 0)))
(defmethod reblocks/widget:render ((widget counter))
(with-html
(:p (format nil "The counter is at ~D." (count-of widget)))
(:p (:button :onclick (reblocks/actions:make-js-action
(lambda (&rest args)
;; closes over WIDGET.
(incf (count-of widget))))
"Count up!"))))
Navigations and dispatchers
Dispatchers are widgets that configure themselves and their children
(i.e. broadly speaking the widget tree) based on the URI
of the request.
Navigations are dispatchers that maintain a simple one-to-one association between
an URI
token 2 a widget.
Old versions of Weblocks supported such dispatchers out of the box,
but during refactoring this functionality was moved into a separate
REBLOCKS-NAVIGATION-WIDGET
system. Read its documentation to learn more.
Servers
To make everything work, you need to start one or more webservers on some TCP
ports.
When you are starting a server, usually you specify an interface and port to listen on and a list os Reblocks apps to serve.
You might define your own server class and inherit it from reblocks/server:server
class.
This will allow to customize a list of HTTP
middlewares.
Here is the list of functions useful when working with Reblocks servers:
Base class for all Reblocks servers. Redefine it if you want to add additional HTTP
midlewares, etc.
Starts reblocks framework hooked into Clack server.
Set DEBUG
to true in order for error messages and stack traces to be shown
to the client (note: stack traces are temporarily not available due to changes
in Hunchentoot 1.0.0).
Server will start all apps declared having autostart t
in their definition
unless APPS
argument is provided.
Sometimes you might want your app respond on /some-uri and / return 404.
In this case it is useful to set DISABLE-WELCOME-APP
argument to T.
Stops Reblocks servers matching given INTERFACE
and PORT
.
This function deactivates all applications bound to the server and stopps a Clack server.
Returns stopped server objects.
Returns a list of Reblocks servers.
Returns T if server is running and NIL
otherwise.
Adds a route to serve given object by static URI
.
Returns a new stack of layers inserting LAYER
before or after a layer with given name.
You should not give both BEFORE
and AFTER
arguments. If given layer not found,
the function will signal error.
Original alist LAYERS
is not modified.
Returns an alist where keys are keywords and values are Lack middlewares or apps.
Default primary method returns alist with two keys :SESSION
and :APP
, where
:SESSION
is a middleware and :APP
is the main application.
To modify middlewares list, define method for a server subclass
and use insert-middleware
function on the results of CALL-NEXT-METHOD
.
SAMESITE-POLICY
argument if given, should be a keyword. It's semantic
is described at Mozilla docs.
It's default value is taken from *default-samesite-policy*
variable.
Here is an example, how this generic-function can be used to run
a HTTP
API
on URL
s with path starting from /api/:
(defmethod reblocks/server:make-middlewares ((server ultralisp-server) &rest rest)
(declare (ignore rest))
(flet ((test-app (env)
(declare (ignore env))
'(200
(:content-type "text/plain")
("Hello, World"))))
(reblocks/server:insert-middleware
(call-next-method)
(cons
:some-api
(lambda (app)
(funcall (lack.util:find-middleware :mount)
app
"/api/"
#'test-app)))
:before :app)))
Default value for SameSite header.
You will find more at Mozilla docs.