cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
Build a CRUD blog with CWIST

This guide builds a small JSON blog API backed by CWIST's SQLite integration. It intentionally keeps SQL explicit so that the request, validation, and response boundaries are easy to inspect.

1. Create the application

(void)req;
/* Query through your existing cwist_db handle and serialize rows as JSON. */
cwist_http_header_add(&res->headers, "Content-Type", "application/json");
}
int main(void) {
cwist_app_use_db(app, "blog.db");
cwist_app_get(app, "/posts", list_posts);
int rc = cwist_app_listen(app, 8080);
return rc;
}
Database operations wrapper (SQLite3).
cwist_error_t cwist_sstring_assign(cwist_sstring *str, const char *data)
Assign a C string.
Definition sstring.c:504
cwist_error_t cwist_http_header_add(cwist_http_header_node **head, const char *key, const char *value)
Add a header to the list.
Definition http.c:1861
HTTP Protocol Definitions and Helpers.
size_t cap
Definition otel.c:56
Main Application Context.
Definition app.h:155
HTTP Response Object. Supports standard string body or Zero-Copy pointer body.
Definition http.h:82
cwist_sstring * body
Definition http.h:87
cwist_http_header_node * headers
Definition http.h:86
Core Application Structure and Lifecycle Management.
int cwist_app_listen(cwist_app *app, int port)
Serve app on port until SIGTERM, SIGINT or cwist_shutdown_request(); blocks the calling thread.
Definition app.c:4628
void cwist_app_get(cwist_app *app, const char *path, cwist_handler_func handler)
Registers a GET route handler.
Definition app.c:2216
cwist_error_t cwist_app_use_db(cwist_app *app, const char *db_path)
Open a SQLite database and attach it as the shared application handle.
Definition app.c:1851
void cwist_app_destroy(cwist_app *app)
Destroys the application and frees all resources.
Definition app.c:1464
cwist_app * cwist_app_create(void)
Creates a new CWIST application instance.
Definition app.c:1292

Create the table during application startup with a migration:

CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
body TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);

2. Define the routes

Use one handler per operation and parameterized routes for a post identifier.

Method Path Action
GET /posts List posts
GET /posts/:id Read one post
POST /posts Create a post
PATCH /posts/:id Update title/body
DELETE /posts/:id Delete a post
cwist_app_get(app, "/posts", list_posts);
cwist_app_get(app, "/posts/:id", get_post);
cwist_app_post(app, "/posts", create_post);
cwist_app_patch(app, "/posts/:id", update_post);
cwist_app_delete(app, "/posts/:id", delete_post);
void cwist_app_delete(cwist_app *app, const char *path, cwist_handler_func handler)
Definition app.c:2275
void cwist_app_post(cwist_app *app, const char *path, cwist_handler_func handler)
Register a POST handler with default endpoint options.
Definition app.c:2267
void cwist_app_patch(cwist_app *app, const char *path, cwist_handler_func handler)
Definition app.c:2279

Read the route parameter with cwist_query_map_get(req->path_params, "id"). Treat it as untrusted input: parse the whole integer, reject non-positive values, and bind it to a prepared statement. Never interpolate JSON fields or route parameters into SQL.

3. Validate JSON and return HTTP semantics

Require title and body strings on create. Return 201 Created after an insert, 204 No Content after a successful delete, 400 Bad Request for a malformed request, and 404 Not Found when an id has no row. Always set Content-Type: application/json for JSON responses.

For browser clients, add CORS only for the origins you control and use CSRF middleware when cookie authentication is enabled. The existing WAF middleware is a useful additional boundary, but it does not replace parameterized SQL.

4. Test the API

Use cwist_test_client to dispatch requests without binding a port. Cover the entire lifecycle: create, list, fetch, patch, delete, then fetch again and assert 404. Run the same tests against :memory: for fast isolation and a temporary on-disk database to exercise migrations.