Main
A runnable Geblang example.
- Path
gebweb/examples/server_rendered_blog/main.gb- Category
- Server Rendered Blog
Server-rendered blog. One file, in-memory store, demonstrates
CSRF + flash + form-state rehydration + asset pipeline + CSP
nonce in a single working app.
Source
import gebweb;
import web.session as session;
import io;
class Post {
string title;
string body;
func Post(string title, string body) {
this.title = title;
this.body = body;
}
}
list<Post> posts = [];
any blogApp;
class PostForm {
@Assert.notBlank
@Assert.maxLength(120)
string title;
@Assert.notBlank
string body;
func PostForm(string title, string body) {
this.title = title;
this.body = body;
}
}
class BlogController {
@Get("/")
func index(dict<string, any> request): dict<string, any> {
return gebweb.htmlView(blogApp, request, "list.html", {
"title": "Blog",
"posts": posts
});
}
@Post("/posts")
func create(dict<string, any> request, PostForm form): dict<string, any> {
posts = posts.push(Post(form.title, form.body));
let response = {"status": 303, "headers": {"Location": "/"}, "body": ""};
return gebweb.flash(blogApp, request, response, "success", "Post published.");
}
}
let app = gebweb.app([BlogController()]);
gebweb.useViews(app, "templates");
let sessionStore = session.fileSessionStore(io.tempDir("blog-sess-*"), 3600);
gebweb.useSession(app, sessionStore);
gebweb.useCsrf(app, {"secret": "demo-secret-DO-NOT-USE-IN-PROD-XXXXX"});
gebweb.useStaticAssets(app, "public");
gebweb.useSecurity(app, {
"csp": {
"defaultSrc": ["'self'"],
"scriptSrc": ["'self'", "'nonce'"],
"styleSrc": ["'self'"],
"imgSrc": ["'self'", "data:"]
}
});
blogApp = app;
io.println("Server running on http://127.0.0.1:8080");
gebweb.serve(app, "127.0.0.1:8080");