Rychlý start
Rychlý start
Získejte funkční API nad svou databází PostgreSQL za pár minut — a volejte ho z obyčejné webové stránky. Vaše databáze je váš backend: žádný framework, žádný boilerplate, žádná JavaScriptová knihovna. Krok za krokem postavíme jeden „Hello World": funkci s parametrem, real-time notifikaci a vygenerovaný soubor.
Veškerý kód tohoto návodu je k dispozici jako hotový příklad:
hello_world.sql (databáze) a
index.html (webová stránka).
Každý endpoint je podrobně popsán na své referenční stránce: JSON-RPC,
Real-time notifikace (SSE) a Stahování souborů (/file).
1. Instalace
Stáhněte binárku
# macOS (Homebrew)
brew install heptau/tap/pgarachne
# or download the latest release for your OS:
# https://github.com/heptau/pgarachne/releases/latest2. Příprava databáze
Vytvořte databázi, servisní roli, pod kterou se PgArachne připojuje, a nahrajte schéma PgArachne
(sql/schema.sql najdete v repozitáři):
createdb my_database
psql -d my_database -c "CREATE ROLE pgarachne LOGIN PASSWORD 'pgarachne_password'"
psql -d my_database -f sql/schema.sql3. Konfigurace a spuštění
Vytvořte soubor pgarachne.env (server ho najde v aktuálním adresáři).
Díky STATIC_FILES_PATH bude PgArachne obsluhovat i webovou stránku, kterou vytvoříte v kroku 5, takže stránka
a API sdílejí jeden origin a nemusíte nastavovat CORS:
DB_HOST=localhost
DB_PORT=5432
DB_USER=pgarachne
DB_SSLMODE=disable # local PostgreSQL without TLS only
STATIC_FILES_PATH=/path/to/web # folder with your index.html
# Optional: enables JWT sessions (POST /db//token); generate with openssl rand -hex 32
# JWT_SECRET=… Spusťte server (heslo servisní role se čte z PGPASSWORD nebo z ~/.pgpass):
PGPASSWORD=pgarachne_password ./pgarachne4. Hello World — funkce s parametrem
Každá metoda API je funkce PostgreSQL s jediným argumentem typu jsonb. Vytvořte roli pro webovou stránku
a funkci; JSON objekt, který klient pošle jako params, dorazí jako payload:
CREATE ROLE demo_user WITH LOGIN PASSWORD 'user_password';
GRANT USAGE ON SCHEMA api TO demo_user;
CREATE OR REPLACE FUNCTION api.hello_world(payload jsonb DEFAULT '{}'::jsonb)
RETURNS json LANGUAGE sql AS $$
SELECT json_build_object(
'message', 'Hello, ' || COALESCE(payload->>'name', 'World') || '!');
$$;
GRANT EXECUTE ON FUNCTION api.hello_world(jsonb) TO demo_user;Přístup řídí samotný PostgreSQL: demo_user může volat přesně ty funkce, na které dostal
EXECUTE — nic jiného není dosažitelné.
5. Zavolejte ji — z curlu i z webové stránky
Váš API endpoint je živý. Uživatelské jméno a heslo role PostgreSQL se posílají pomocí HTTP Basic autentizace:
curl -X POST http://localhost:8080/db/my_database/jsonrpc \
-u demo_user:user_password \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"api.hello_world","params":{"name":"Alice"},"id":1}'
# → {"jsonrpc":"2.0","result":{"message":"Hello, Alice!"},"id":1}Totéž volání z prohlížeče pomocí vestavěného fetch(). Uložte tento kód jako index.html do složky
z STATIC_FILES_PATH a otevřete http://localhost:8080/:
<input id="name" value="Alice">
<button id="hello">Say hello</button>
<pre id="out"></pre>
<script>
// HTTP Basic header: "user:password" in base64 (TextEncoder handles non-ASCII)
const bytes = new TextEncoder().encode("demo_user:user_password");
const auth = "Basic " + btoa(String.fromCharCode(...bytes));
const base = location.origin + "/db/my_database"; // /{API_PREFIX}/{database}
async function rpc(method, params) {
const res = await fetch(base + "/jsonrpc", {
method: "POST",
headers: { "Authorization": auth, "Content-Type": "application/json" },
body: JSON.stringify({ jsonrpc: "2.0", method, params, id: 1 }),
});
const body = await res.json();
if (!res.ok || body.error) throw new Error(body.error.message);
return body.result;
}
document.getElementById("hello").onclick = async () => {
const result = await rpc("api.hello_world", { name: document.getElementById("name").value });
document.getElementById("out").textContent = result.message; // Hello, Alice!
};
</script>6. Real-time — nechte databázi poslat zprávu (SSE)
PostgreSQL umí publikovat zprávy pomocí pg_notify; PgArachne je přeposílá do prohlížečů jako Server-Sent Events.
Rozšiřte funkci: když volající předá "notify": true, publikuje pozdrav navíc
na kanál hello:
CREATE OR REPLACE FUNCTION api.hello_world(payload jsonb DEFAULT '{}'::jsonb)
RETURNS json LANGUAGE plpgsql AS $$
DECLARE
greeting text := 'Hello, ' || COALESCE(payload->>'name', 'World') || '!';
BEGIN
IF COALESCE((payload->>'notify')::boolean, false) THEN
PERFORM pg_notify('hello', json_build_object('message', greeting)::text);
END IF;
RETURN json_build_object('message', greeting);
END; $$;Na stránce se nejdřív přihlaste k odběru a pak zavolejte funkci. Vestavěný EventSource neumí poslat
hlavičku Authorization, proto se stream čte pomocí fetch() (asi 15 řádků):
async function listen(channels, onMessage) {
const res = await fetch(base + "/sse?channels=" + encodeURIComponent(channels), {
headers: { "Authorization": auth },
});
if (!res.ok) throw new Error((await res.json()).error);
const reader = res.body.getReader(), decoder = new TextDecoder();
let buffer = "";
for (;;) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
let end;
while ((end = buffer.indexOf("\n\n")) >= 0) { // an event ends with a blank line
const event = buffer.slice(0, end);
buffer = buffer.slice(end + 2);
for (const line of event.split("\n"))
if (line.startsWith("data: ")) onMessage(JSON.parse(line.slice(6)));
}
}
}
listen("hello", (m) => console.log("event:", m.data.message)); // m = {channel, data}
rpc("api.hello_world", { name: "Alice", notify: true }); // the event arrives immediatelyNOTIFY je transakční — PostgreSQL ho doručí, až se transakce funkce
potvrdí (commit), tedy právě ve chvíli, kdy volání skončí. Přihlaste se k odběru před voláním: PostgreSQL si
notifikace pro posluchače, kteří ještě nejsou připojeni, neuchovává. Kanály SSE nejsou omezeny rolemi
(viz Real-time notifikace (SSE)).7. Stažení souboru
Funkci, která vrací řádky (path, content, mime_type, store_only), lze stáhnout přes endpoint
/file — jako surové bajty, bez base64 uvnitř JSON. Tato vrací hello-world.md:
CREATE OR REPLACE FUNCTION api.hello_world_file(payload jsonb DEFAULT '{}'::jsonb)
RETURNS TABLE (path text, content bytea, mime_type text, store_only boolean)
LANGUAGE sql AS $$
SELECT 'hello-world.md',
convert_to('# Hello, ' || COALESCE(payload->>'name', 'World') || E'!\n\nGenerated by PostgreSQL at ' || now() || E'.\n', 'UTF8'),
'text/markdown',
false;
$$;
GRANT EXECUTE ON FUNCTION api.hello_world_file(jsonb) TO demo_user;Na stránce můžete obsah zobrazit nebo nabídnout ke stažení (vrátíte-li víc řádků, dostanete automaticky ZIP):
async function getFile() {
const res = await fetch(base + "/file", {
method: "POST",
headers: { "Authorization": auth, "Content-Type": "application/json" },
body: JSON.stringify({ method: "api.hello_world_file", params: { name: "Alice" } }),
});
if (!res.ok) throw new Error((await res.json()).error.message); // errors are JSON, never binary
return res.blob();
}
// show it:
console.log(await (await getFile()).text());
// or download it:
const url = URL.createObjectURL(await getFile());
const a = Object.assign(document.createElement("a"), { href: url, download: "hello-world.md" });
document.body.appendChild(a); a.click(); a.remove();
URL.revokeObjectURL(url);Vyzkoušejte to s curlem: curl -u demo_user:user_password -H "Content-Type: application/json" -d '{"method":"api.hello_world_file"}' http://localhost:8080/db/my_database/file -OJ.
Více v kapitole Stahování souborů (/file).
Než půjdete do produkce
- Používejte HTTPS. Přihlašovací údaje Basic putují s každým požadavkem; viz Nasazení a HTTPS. Změňte demo hesla.
- Přihlašovací údaje držte jen v paměti (JavaScriptová proměnná), nikdy v
localStorage. Abyste heslo neposílali opakovaně, nastavteJWT_SECRETa požádejte o token naPOST /db/my_database/token(viz Bezpečnost a autentizace). - Webová stránka na jiném originu (CDN, jiný port)? Nastavte
ALLOWED_ORIGINS=https://app.example.com; cross-origin požadavky jsou ve výchozím stavu blokované. - Nejmenší oprávnění: jedna role PostgreSQL pro každý druh uživatele,
EXECUTEjen na funkce, které potřebují, Row-Level Security pro data jednotlivých uživatelů aALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC, aby nové funkce nebyly zpřístupněny omylem.
8. Připojte AI agenta (MCP)
Zpřístupněte stejné funkce jako nástroje pro Claude Desktop nebo Cursor přes endpoint MCP:
POST http://localhost:8080/db/my_database/mcpÚplné pokyny k připojení najdete v kapitole Model Context Protocol (MCP).
9. Získejte specifikaci OpenAPI (Swagger, Postman, generování kódu)
Každá zpřístupněná funkce je popsána také v dokumentu OpenAPI 3.1, filtrovaném podle toho, co smí autentizovaný volající zavolat:
curl http://localhost:8080/db/my_database/openapi.json \
-u demo_user:user_password
# or as YAML: .../openapi.yamlImportujte URL přímo do Swagger UI, Postmanu nebo generátoru kódu z OpenAPI. Každá metoda stále běží přes jediný endpoint JSON-RPC z kroku 5 — proč specifikace uvádí cestu pro každou metodu bez odpovídající skutečné trasy, vysvětlují Architektonická rozhodnutí.
To je vše. Přečtěte si referenci JSON-RPC o formátu požadavků, psaní funkcí, chybách a idempotenci, nebo srovnání s PostgREST, abyste pochopili, kam PgArachne zapadá.