Skip to content
v0.5.1GitHub

Getting started

First five minutes

applies to v0.5.1

This walk-through stores a key, a JSON document and a relational table in a fresh installation, using only curl. It assumes the service from Install is running and that KEY holds the admin key:

Terminal window
KEY=lura_… # your admin key from /etc/luradb/luradb.toml

Response headers are shortened to the ones that matter; timestamps and generated keys differ on your machine.

Every engine starts with a domain called default. Create a domain of your own for sessions and store a key in it that expires after an hour:

Terminal window
curl -s -X POST http://127.0.0.1:3000/store-api/domains \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"name": "sessions"}'
{ "name": "sessions", "created_at": 1793741597, "require_conditional_writes": false }
Terminal window
curl -s -X PUT "http://127.0.0.1:3000/store-api/kv/sessions/keys/s-4f2a?ttl=3600" \
-H "Authorization: Bearer $KEY" -d '{"user": "jane"}'

The write answers 200 with an empty body. Read the key back with -i to see the headers:

Terminal window
curl -si http://127.0.0.1:3000/store-api/kv/sessions/keys/s-4f2a \
-H "Authorization: Bearer $KEY"
HTTP/1.1 200 OK
content-type: application/octet-stream
x-expires-at: 1793745198
etag: "1a1a354a9f90000"
content-length: 16
{"user": "jane"}

A value is plain bytes; LuraDB does not interpret it. X-Expires-At is the absolute expiry in Unix seconds and the ETag names this version of the key, which conditional writes use. Once the hour is over, the key answers 404.

JSON documents live in their own domains. Create orders, index the field status and store two documents:

Terminal window
curl -s -X POST http://127.0.0.1:3000/store-api/json/domains \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"name": "orders"}'
curl -s -X POST http://127.0.0.1:3000/store-api/json/orders/indexes \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"field": "status", "type": "string"}'
curl -s -X POST http://127.0.0.1:3000/store-api/json/orders/documents \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"customer": "Jane Doe", "status": "open", "total": 42.5}'
curl -s -X POST http://127.0.0.1:3000/store-api/json/orders/documents \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"customer": "Omar Haddad", "status": "shipped", "total": 19}'

Each document comes back with the key LuraDB generated and its version:

{ "_key": "64780537-af9d-4d79-8326-540691f325ba", "_version": 1, "customer": "Jane Doe", "status": "open", "total": 42.5 }

Search accepts filters on indexed fields only; a filter on a field without an index answers 400. Create the index before you store documents, or reindex afterwards.

Terminal window
curl -s -X POST http://127.0.0.1:3000/store-api/json/orders/search \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"filter": {"status": "open"}}'
{
"documents": [
{ "_key": "64780537-af9d-4d79-8326-540691f325ba", "_version": 1, "customer": "Jane Doe", "status": "open", "total": 42.5 }
],
"total": 1,
"offset": 0,
"limit": 50
}

Relational tables are created and queried through one endpoint that takes one LuraSQL statement per request. The domain is again called orders; the relational engine has its own domains. Values go in as parameters:

Terminal window
curl -s -X POST http://127.0.0.1:3000/store-api/rel/domains \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"name": "orders"}'
curl -s -X POST http://127.0.0.1:3000/store-api/rel/orders/sql \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"sql": "CREATE TABLE customers (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, city TEXT)"}'
curl -s -X POST http://127.0.0.1:3000/store-api/rel/orders/sql \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"sql": "INSERT INTO customers (name, city) VALUES (?, ?)", "params": ["Jane Doe", "Lisbon"]}'
curl -s -X POST http://127.0.0.1:3000/store-api/rel/orders/sql \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"sql": "INSERT INTO customers (name, city) VALUES (?, ?)", "params": ["Omar Haddad", "Tunis"]}'

The statements answer {"ok":true} and {"affected":1,"last_pk":1}. A SELECT returns typed columns and rows:

Terminal window
curl -s -X POST http://127.0.0.1:3000/store-api/rel/orders/sql \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"sql": "SELECT id, name, city FROM customers WHERE city = ?", "params": ["Lisbon"]}'
{
"columns": [
{ "name": "id", "type": "INTEGER" },
{ "name": "name", "type": "TEXT" },
{ "name": "city", "type": "TEXT" }
],
"limit_applied": false,
"row_count": 1,
"rows": [[1, "Jane Doe", "Lisbon"]]
}

Turn the Swagger UI on in /etc/luradb/luradb.toml and restart the service:

[server]
swagger_enabled = true

The UI is served at server.swagger_url (default /test-ui) and the OpenAPI contract at /api-docs/openapi.json. While authentication is on, both need the Bearer key, and that includes the page of the UI itself. A browser that opens /test-ui/ sends no such header and gets 401 Unauthorized; the contract is available to curl:

Terminal window
curl -s http://127.0.0.1:3000/api-docs/openapi.json -H "Authorization: Bearer $KEY"

To click through the API in a browser on a machine of your own, start the server with auth.enabled set to false, which LuraDB accepts only on a loopback address, and open http://127.0.0.1:3000/test-ui/. Every endpoint, with its status codes and conditions, is also in the generated pages under REST API.