Dlang is a fine language to do web development.
Here a tutorial. It's going to be an application where you must login as user x and password x then you can go to calculate page which asks 2 numbers then product is returned.
Make a project
Create the logic
zed ./source/app.d
Create the views.
zed ./views/status_bar..dt
zed ./views/index.dt
zed ./views/login.dt
zed ./views/logout.dt
zed ./views/calculate.dt
zed ./views/result.dt
zed ./public/css/style.css
Run :
THATS ALL FOLKS !
Here a tutorial. It's going to be an application where you must login as user x and password x then you can go to calculate page which asks 2 numbers then product is returned.
Code:
pkg install zed ldc dub
Make a project
Code:
dub init test -t vibe.d
Code:
cd test
mkdir public
mkdir public/css
mkdir public/js
mkdir source
mkdir views
Create the logic
zed ./source/app.d
Code:
import vibe.vibe;
import std.conv : to;
// Step 1: Definition of the hook function.
// It returns a boolean status string which will be injected into the method parameter.
string checkAuthentication(HTTPServerRequest req, HTTPServerResponse res)
{
if (!req.session || !req.session.isKeySet("username")) {
res.redirect("/index.html");
// Throwing stops Vibe.d from executing the protected method after redirecting
throw new HTTPStatusException(HTTPStatus.found, "Redirecting to home...");
}
return "authorized";
}
class WebInterface {
// Helper to get the logged-in username safely
private string getLoggedInUser(HTTPServerRequest req)
{
if (req.session && req.session.isKeySet("username")) {
return req.session.get!string("username");
}
return null;
}
// 1. Home Page (Public - ONLY maps to /index.html)
// Renamed to getHomeHtml to remove implicit default "/" mapping
@path("/index.html")
void getHomeHtml(HTTPServerRequest req, HTTPServerResponse res)
{
string username = getLoggedInUser(req);
string message = "Hello from the specific index.html controller!";
res.render!("index.dt", message, username);
}
// 2. Show Login Page (Public)
@path("/login.html")
void getLoginHtml(HTTPServerRequest req, HTTPServerResponse res, string error = null)
{
string username = getLoggedInUser(req);
res.render!("login.dt", error, username);
}
// 3. Process Login Form (Public)
@path("/login.html")
@method(HTTPMethod.POST)
void postLoginHtml(HTTPServerRequest req, HTTPServerResponse res)
{
string user = req.form.get("username");
string pass = req.form.get("password");
if (user == "x" && pass == "x") {
auto session = res.startSession();
session.set("username", user);
res.redirect("/index.html");
} else {
getLoginHtml(req, res, "Invalid username or password.");
}
}
// 4. Logout (Public)
@path("/logout.html")
void getLogoutHtml(HTTPServerRequest req, HTTPServerResponse res)
{
if (req.session) {
res.terminateSession();
}
string username = null;
res.render!("logout.dt", username);
}
// 5. Show the Calculation Form Page (Protected via Annotation)
// Passes "_" as a dummy parameter name to satisfy Vibe.d syntax requirements.
@before!checkAuthentication("_")
@path("/calculate.html")
void getCalculateHtml(string _, HTTPServerRequest req, HTTPServerResponse res)
{
string username = getLoggedInUser(req);
res.render!("calculate.dt", username);
}
// 6. Process Form and Render Result (Protected via Annotation)
@before!checkAuthentication("_")
@path("/result.html")
@method(HTTPMethod.POST)
void postResultHtml(string _, HTTPServerRequest req, HTTPServerResponse res)
{
string username = getLoggedInUser(req);
string x1Str = req.form.get("x1", "0");
string x2Str = req.form.get("x2", "0");
double val1 = x1Str.to!double;
double val2 = x2Str.to!double;
double calculationResult = val1 * val2;
res.render!("result.dt", calculationResult, username);
}
}
void main()
{
auto settings = new HTTPServerSettings;
settings.port = 8080;
settings.bindAddresses = ["::1", "127.0.0.1"];
settings.sessionStore = new MemorySessionStore;
auto router = new URLRouter;
auto webInterface = new WebInterface;
// --- REGULAR WEB INTERFACE ROUTER ---
auto webSettings = new WebInterfaceSettings;
webSettings.urlPrefix = "/";
router.registerWebInterface(webInterface, webSettings);
// --- FALLBACK STATIC ASSETS ---
router.get("*", serveStaticFiles("public/"));
auto listener = listenHTTP(settings, router);
scope (exit)
{
listener.stopListening();
}
logInfo("Please open http://127.0.0.1:8080 in your browser.");
runApplication();
}
Create the views.
zed ./views/status_bar..dt
Code:
cat status_bar.dt
hr
div.status-bar(style="background: #f0f0f0; padding: 10px; margin-top: 20px;")
- if (username !is null)
p(style="color: #000000; margin: 0;") Status: Logged in as #[strong(style="color: #000000;") #{username}]
- else
p(style="color: #000000; margin: 0;") Status: Logged out
zed ./views/index.dt
Code:
doctype html
html
head
title Explicit Route Example
link(rel="stylesheet", href="/css/style.css")
body
h1 Hello World!
p= message
hr
p
a(href="/login.html") Login
| |
a(href="/logout.html") Logout
| |
a(href="/calculate.html") Go to Calculate Page
include status_bar
zed ./views/login.dt
Code:
doctype html
html
head
title Login
link(rel="stylesheet", href="/css/style.css")
body
h1 Login Required
- if (error !is null)
p(style="color: red;") #{error}
form(action="login.html", method="POST")
div
label(for="username") Username:
input(type="text", name="username", id="username", required=true)
div
label(for="password") Password:
input(type="password", name="password", id="password", required=true)
div
button(type="submit") Login
include status_bar
zed ./views/logout.dt
Code:
doctype html
html
head
title Logged Out
body
h1 You have been logged out.
p Thank you for using the calculator application.
p
a(href="/login.html") Click here to log back in.
include status_bar
zed ./views/calculate.dt
Code:
doctype html
html
head
title Calculator
link(rel="stylesheet", href="/css/style.css")
body
div.nav
a(href="/") Home
| |
a(href="/logout.html") Logout
hr
h1 Calculator
label Let's calculate:
form(action="/result.html", method="POST")
div
label(for="x1") Input X1:
input(type="number", name="x1", id="x1", step="any", required=true)
div
label(for="x2") Input X2:
input(type="number", name="x2", id="x2", step="any", required=true)
div
button(type="submit") Result
include status_bar
Code:
doctype html
html
head
title Calculation Result
link(rel="stylesheet", href="/css/style.css")
body
div.nav
a(href="/") Home
| |
a(href="/logout.html") Logout
hr
h1 Calculation Complete
p The calculated product of x1 and x2 is:
h2= calculationResult
hr
a(href="/calculate.html") Calculate another number
include status_bar
zed ./public/css/style.css
Code:
/* Reset body background and default text color */
body {
background-color: #0b1a10; /* Very dark forest green */
color: #4af626; /* Retro matrix green */
font-family: sans-serif;
padding: 2rem;
}
/* Make all headings bright neon green */
h1, h2, h3, h4, h5, h6 {
color: #76ff03;
text-shadow: 0 0 10px rgba(118, 255, 3, 0.3);
}
/* Style paragraphs and generic text */
p, span, li {
color: #a2ff86;
}
/* Style links with interactive greens */
a {
color: #00e676;
text-decoration: none;
border-bottom: 1px dashed #00e676;
}
a:hover {
color: #76ff03;
border-bottom-style: solid;
}
/* Optional: Make containers look like a green terminal board */
div, section, article {
border-color: #1b5e20;
}
Run :
Code:
dub run &
firefox http://127.0.0.1/index.html
THATS ALL FOLKS !