Industrial code needs safer code, not easier code. But when you're developing a blog at 8 PM, long template errors are annoying.
You need CRUD and RDBMS. It's simple.
CWIST is for that kind of work.
It sacrifices memory safety, smart pointers, and modern C++ abstractions. In return, compile errors are more predictable.
#include <stdio.h>
#include <cwist/app.h>
#include <cwist/core/db/pool.h>
#include <cwist/core/template/template.h>
static cwist_db_pool_t *g_db_pool;
static void send_error(cwist_http_response *res, const char *msg) {
res->status_code = CWIST_HTTP_INTERNAL_ERROR;
cwist_http_header_add(&res->headers, "Content-Type", "text/plain");
cwist_sstring_assign(res->body, msg);
}
static void render(cwist_http_response *res, const char *path, cJSON *ctx) {
cwist_sstring *html = cwist_template_render_file(path, ctx);
if (html) {
cwist_http_header_add(&res->headers, "Content-Type", "text/html");
cwist_sstring_assign(res->body, html->data);
cwist_sstring_destroy(html);
}
cJSON_Delete(ctx);
}
static void handle_index(cwist_http_request *req, cwist_http_response *res) {
(void)req;
cJSON *ctx = cJSON_CreateObject();
cJSON_AddStringToObject(ctx, "title", "CWIST Example");
cJSON_AddStringToObject(ctx, "greeting", "Hello from CWIST");
render(res, "templates/index.html", ctx);
}
static void handle_users(cwist_http_request *req, cwist_http_response *res) {
(void)req;
if (!g_db_pool) return send_error(res, "database pool unavailable");
cwist_db_pool_exec(g_db_pool,
"CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT);"
"INSERT INTO users (name) SELECT 'Alice' WHERE NOT EXISTS "
"(SELECT 1 FROM users WHERE name = 'Alice');"
"INSERT INTO users (name) SELECT 'Bob' WHERE NOT EXISTS "
"(SELECT 1 FROM users WHERE name = 'Bob');");
cJSON *rows = NULL;
if (cwist_db_pool_query(g_db_pool,
"SELECT id, name FROM users ORDER BY id;", &rows).error.err_i16)
return send_error(res, "failed to query database");
cJSON *ctx = cJSON_CreateObject();
cJSON_AddItemToObject(ctx, "users", rows ? rows : cJSON_CreateArray());
render(res, "templates/users.html", ctx);
}
static void handle_health(cwist_http_request *req, cwist_http_response *res) {
(void)req;
cwist_http_header_add(&res->headers, "Content-Type", "text/plain");
cwist_sstring_assign(res->body, "ok");
}
int main(void) {
g_db_pool = cwist_db_pool_create("./app.db", 1);
if (!g_db_pool) return 1;
cwist_app *app = cwist_app_create();
cwist_app_get(app, "/", handle_index);
cwist_app_get(app, "/users", handle_users);
cwist_app_get(app, "/health", handle_health);
cwist_app_use_https(app, "cert.pem", "key.pem");
cwist_app_listen(app, 8082);
cwist_app_destroy(app);
cwist_db_pool_destroy(g_db_pool);
return 0;
}
Code style is old and still small. The code is simple and stupid.CWIST functions use the same `cwist_xx_xx` naming format. It's consistent. It's harder to make a slop in CWIST.
Features
- CWIST GC for fast prototyping. It's closer to a garbage sweeper than a traditional GC, and lighter. - Dev blog engine - HTML Template Engine - WASM
External benchmark: https://web-frameworks-benchmark.netlify.app/compare?f=cwist...
Latest results may be masked: https://github.com/the-benchmarker/web-frameworks/issues/977...
Unofficial results (not reliable): https://github.com/c4punks/CWIST/actions/runs/39000473564/jo...
Dev blog: https://oborona.zip Org: https://c4punks.github.io
It doesn't help my portfolio, but please star the project if you enjoyed it.
Special thanks to https://github.com/thegoodengineer for inviting organization members.