JSON, Networking and Web Development

44.1 JSON

Typed (de)serialization: vibe.data.json (serializeToJson/deserializeJson!T), asdf, mir-ion (very fast; JSON/YAML/MsgPack/Ion), jsonizer, painlessjson.

Other formats: std.csv (csvReader!Record(text, null)), dyaml (YAML), toml (toml-d), sdlang-d, msgpack-d, protobuf-d.

import std.json;
auto j = parseJSON(`{"name": "Ana", "tags": ["a", "b"], "age": 30}`);
writeln(j["name"].str, " ", j["age"].integer, " ", j["tags"][0].str);
if ("missing" in j) {}
JSONValue obj = ["id": JSONValue(1), "ok": JSONValue(true)];
obj["list"] = JSONValue([1, 2, 3]);
writeln(obj.toString, "\n", obj.toPrettyString);

44.2 HTTP Client and Sockets

Third-party: requests (ikod/dlang-requests), the vibe.d HTTP client, arsd.http2.

import std.net.curl;
auto html = get("https://dlang.org");
auto resp = post("https://httpbin.org/post", ["key": "value"]);
download("https://example.com/file.zip", "file.zip");
auto http = HTTP("https://api.github.com/repos/dlang/dmd");
http.addRequestHeader("User-Agent", "d-client");
http.onReceive = (ubyte[] data) { write(cast(string) data); return data.length; };
http.perform();

import std.socket;
auto server = new TcpSocket();
server.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true);
server.bind(new InternetAddress(8080));
server.listen(10);
auto client = server.accept();
char[1024] buf;
auto n = client.receive(buf[]);
client.send(buf[0 .. n]);
client.close();

44.3 vibe.d Web Framework

Features: fiber-based async I/O, REST interface generation (server and client from one interface), Diet templates, WebSockets, sessions, MongoDB/Redis drivers, TLS, an HTTP/2 add-on.

Other web frameworks: handy-httpd, serverino, hunt-framework, arsd.cgi (CGI/FastCGI/SCGI/embedded server), archttp.

// dub.json: "dependencies": { "vibe-d": "~>0.10" }
import vibe.vibe;

void main()
{
    auto router = new URLRouter;
    router.get("/", (req, res) { res.writeBody("Hello from vibe.d!"); });
    router.get("/hello/:name", &hello);
    router.registerWebInterface(new WebApp);
    router.registerRestInterface(new ApiImpl);

    auto settings = new HTTPServerSettings;
    settings.port = 8080;
    settings.bindAddresses = ["127.0.0.1"];
    listenHTTP(settings, router);
    runApplication();
}

void hello(HTTPServerRequest req, HTTPServerResponse res)
{
    res.writeJsonBody(["greeting": "Hello " ~ req.params["name"]]);
}

class WebApp
{
    void index() { render!("index.dt"); }             // Diet templates (Pug-like)
    void postLogin(string username, string password) { redirect("/"); }   // form fields auto-mapped
}

@path("/api")
interface Api { @method(HTTPMethod.GET) string getStatus(); User getUser(int id); }
class ApiImpl : Api { string getStatus() { return "ok"; } User getUser(int id) { return User(id, "Ana"); } }

44.4 Databases

ddbc (JDBC-like for MySQL/PostgreSQL/SQLite), dpq2 (PostgreSQL), mysql-native, d2sqlite3, hibernated (ORM), the vibe.d MongoDB/Redis clients, arsd.database.

import d2sqlite3;
auto db = Database("app.db");
db.run("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)");
auto stmt = db.prepare("INSERT INTO users (name) VALUES (:name)");
stmt.inject("Ana");                                   // parameterized
foreach (row; db.execute("SELECT id, name FROM users")) writeln(row["id"].as!int, " ", row["name"].as!string);