Ecosystem packages
Install the packages that connect a Valk program to databases, caches and file formats.
On this page
Packages are installed per project with vman and imported by the name they were installed under.
The standard library covers HTTP, files, JSON, crypto and the rest; these packages cover what talks
to the world outside your program: databases, caches, tokens and file formats.
vman install github.com/ctxcode/valk-redis
That writes the dependency into valk.json, copies it into vendor/, and the program then uses it
by name:
use redis
Browse vpkg.dev for the full index, where each package lists its versions and
the lowest compiler version each one needs. See Projects & packages for how
dependencies, versions and valk.json work.
Databases#
| Package | What it is |
|---|---|
| valk-sql | One API over all three: query builder, migrations, pooling, rows read into your own classes |
| valk-sqlite | SQLite, bound to the C library, so the database is a file inside your program |
| valk-postgres | PostgreSQL, written in Valk, with prepared and cached statements |
| valk-mysql | MySQL, written in Valk |
Each driver works on its own, and each one also plugs into valk-sql, which is where the parts every
program writes again otherwise already live. Install the driver you use together with it:
vman install github.com/ctxcode/valk-sql
vman install github.com/ctxcode/valk-sqlite
use sql
use sqlite
let db = sqlite.database(sqlite.open("app.db") ! panic("%{E.message}"))
defer db.close()
// Statements are written with `?` whatever the database is; Postgres gets $1, $2 on the way out
db.exec("INSERT INTO users (name, age) VALUES (?, ?)", .{ sql.Value.of("Ada"), sql.Value.of_int(36) }) ! panic("%{E.message}")
let rows = sql.Query.select()
.on(db)
.from("users")
.where("age > ?", .{ sql.Value.of_int(18) })
.all() ! panic("%{E.message}")
Moving to another database is then a matter of the line that opens it. What differs between them —
placeholders, RETURNING, LIMIT/OFFSET, the id of an insert — is what valk-sql smooths over.
Caches and queues#
valk-redis speaks RESP to Redis and Valkey, with pipelines, transactions, scripts, pub/sub, streams, TLS, pools and Sentinel:
use redis
let con = redis.connect("127.0.0.1", 6379) ! panic("%{E.message}")
defer con.close()
con.set("greeting", "hello", 60) ! panic("%{E.message}") // with a 60 second lifetime
let visits = con.incr("visits") ! panic("%{E.message}")
let job = con.blpop("jobs", 5) ! panic("%{E.message}") // waits up to five seconds
Web services#
| Package | What it is |
|---|---|
| valk-jwt | JSON Web Tokens: HS256, HS384 and HS512, with decoding that verifies before it believes |
| valk-uuid | UUIDs: random (v4), time-ordered (v7) and name based (v5 and v3) |
use jwt
use uuid
let id = uuid.v7() // time-ordered, so it sorts by when it was made
let token = jwt.encode_of(Session { sub: id.to_string() }, secret, jwt.Algorithm.hs256, 3600)
let session = jwt.decode_to[Session](token, secret) ! panic("%{E.message}")
The algorithm is taken from the caller, never from the token, so a token that claims alg: none is
refused rather than believed.
File formats#
| Package | What it is |
|---|---|
| valk-toml | TOML 1.0, decoded into your own classes or a json.Value, and encoded back |
| valk-image | PNG, JPEG, WebP and BMP: reading, writing, resizing, cropping, flipping and rotating |
use toml
use valk.fs
let settings = toml.decode_to[Settings](fs.read("config.toml") !!) ! panic("%{E.message} at line %{E.line}")
Tooling#
valk-cli turns Array[String] into commands, options and
arguments, writes the help text, and prints the completion script for bash, zsh and fish:
use cli
fn main(args: Array[String]) {
let app = cli.App.new("greet", "Greet someone", "1.0.0")
app.root.flag("loud", "l", "Greet in capitals")
app.root.argument("name", "Who to greet", true)
app.root.on_run(fn(ctx: cli.Context) i32 !cli.Error {
let line = "Hello " + ctx.arg("name") + "!"
println(ctx.flag("loud") ? line.upper() : line)
return 0
})
exit(app.run(args))
}
vman itself is written with it, which is where its vman completion bash comes from.
A program that uses them together#
valk-starter-api is a small JSON API built out of
these parts: valk.http for the server, valk-sql with valk-sqlite for storage and migrations,
valk-redis for rate limiting, and valk-jwt with valk-uuid for sessions. It is a working
project to read rather than a package to install, and its README explains the few decisions that
are easy to get wrong the first time, such as opening connections per thread.