To extend the core functionality of Kvarn, you’ll use extensions. They are ran in an async context, so you can call async APIs to fetch data. They provide options for attaching to all parts of the request pipeline, with virtually no overhead compared to editing Kvarn’s source.
Contents |
---|
1 Details |
2 Building an API |
3 The five *P*s |
3.1 Prime |
3.2 Prepare |
3.2.1 Single |
3.2.2 fn |
3.3 Present |
3.3.1 Internal |
3.3.2 File |
3.4 Package |
3.5 Post |
4 Writing an extension |
5 Example |
Details
The following pages are details on implementation useful to read if you’re working with Kvarn, even just as the web server to host your files.
- Redirects
- APIs under the path
/./
are not accessible from the outside, as Kvarn’s security guarantees forbid this.
A common pattern is to make Prime extensions which redirect to Prepare APIs located here. Then, you can conditionally change the path of a request to internal APIs (e.g. authentication, special admin panels).
Building an API
In Kvarn, you can attach to single URLs or provide a function which takes the request and determines whether or not your code should override the deafult.
In the immediate future, you should be able to say “I want to capture
/api/{string}/{0..=100}
”
You then get request, a reference to the target host, an optional path, and the
IP and port the request came from. You provide a response, which can be
asynchronous, and Kvarn will handle all comression, content-length
, delivery,
HTTP protocols, caching (according to your preference, returned as part of the
reponse), other extension, and encryption.
This is in contrast to Node.js where you have to handle all cases, resulting in
large if else
statements (if you don’t use a library, in which case Kvarn is a
lot faster and just as convenient).
The five Ps
Kvarn is very extensible. Therefore, several pluggable interfaces (called extensions) exist to make integration fast and seamless.
Here are the five Ps chronologically ordered from the request’s perspective.
Prime
- Not cached
This is where you can add cache redirects. If you for example want to load the
login page on all privileged pages (when the user is not logged in), you can
check for the authentication
HTTP header and from there decide to intercept
the request.
It is also here where all HTTP requests are upgraded to HTTPS, by redirecting the request to a special page where a 307 redirect is responded with.
Prepare
- Optional. If the response contains a future (WebSockets), it’ll never cache.
You provide either a URI or a function of when to activate your code. Will still get all other extensions applied.
The
path
variable you get here will beNone
if thefs
feature of aHost
isn’t enabled or percent decoding failed. Be sure to handle percent encoding when taking therequest.uri().path()
. Using thepath
handles this for you.
You have to handle all HTTP methods, as Kvarn passes all, except for HEAD
,
which it handles by simply omitting the body. If your response-type
is
something other than HTML, you must set the header.
It’s very useful for APIs (both REST and GraphQL!)
Here, you could, for example, implement reading from the file system, like Kvarn does by default.
Single
These bind to a single page.
fn
You provide a predicate which returns whether or not to run this extension.
Present
- Cached
Here, files can opt in to extensions to manipulate data, such as the template
system and hide
extension.
This type can modify most data in response and will be executed in series.
Extensions can also attach to filetypes.
Internal
These are declared on the first line in a file, acording to the following syntax:
!> extension arg1 arg2 &> second-extension-name with these four arguments &>
and-so-on
My blog...
There can be arbitrarily many extensions. The are separated by
&>
.
The first word (space-separated) is the extension name. The others are arguments. Extensions might not look for arguments, or error if any invalid input is given, just like applications.
You can naturally also give just one extension:
!> nonce
My vlog...
When Kvarn serves the file, this line is removed.
Extensi