Skip to content

Latest commit

 

History

History
118 lines (90 loc) · 3.97 KB

http-api.md

File metadata and controls

118 lines (90 loc) · 3.97 KB

HTTP API

The dirsql server (default localhost:7117) exposes two endpoints: POST /query and GET /events. It sends no CORS headers unless started with --cors-origin, so a browser page on another origin can reach it only after that opt-in.

POST /query

Run a read-only SQL query — statements SQLite classifies as writes are rejected. That rule governs SQL against the index; dirsql separately never modifies the files it indexes, which is permanent by design. Request body is JSON:

{"sql": "SELECT title, author FROM posts WHERE draft = 0"}

The 200 response is a JSON array of row objects keyed by column name:

[
  {"title": "Hello World", "author": "alice"},
  {"title": "Second Post", "author": "bob"}
]
curl -s http://localhost:7117/query \
  -H 'content-type: application/json' \
  -d "{\"sql\":\"SELECT COUNT(*) AS n FROM './'\"}" \
  | jq

Value serialization

SQLite value JSON
NULL null
INTEGER number
REAL number; NaN / ±Infinity become null
TEXT string
BLOB lowercase hex string (e.g. "deadbeef")

Internal tracking columns (_dirsql_file_path, _dirsql_row_index) are excluded from SELECT * results.

Status codes

Status When
200 Query succeeded. Body: array of row objects.
400 Malformed JSON body, missing or empty sql field, or a SQL error (syntax error, unknown table, or a statement SQLite classifies as a write — queries are read-only).
405 GET /query. Plain-text body method not allowed.
408 The query exceeded the 30-second per-query timeout.
500 Internal server fault.
503 The server is in degraded mode (the config file exists but failed to load).

All error responses (except 405) are application/json:

{"error": "syntax error near \"SLECT\""}

GET /events

Opens a Server-Sent Events stream of row-change events.

curl -N http://localhost:7117/events

On open, the server emits a single ready frame signalling the subscription is attached. Every subsequent frame is named row:

event: ready
data: {}

event: row
data: {"action":"insert","table":"posts","file_path":"posts/hello.json","row":{"title":"Hello World"},"old_row":null}

Event payloads

The data: payload is one JSON object per row-level change:

Field insert update delete error
action "insert" "update" "delete" "error"
table table name table name table name table name, or null when the failure isn't tied to one table
file_path path relative to the root same same same
row the new row the new row the deleted row — (absent)
old_row null the previous row null — (absent)
error — — — message string

Row values serialize as in POST /query.

Stream semantics

  • Errors do not terminate the stream. A malformed file produces an error event; the stream continues.
  • Slow consumers skip, not crash. A subscriber that lags behind the event buffer silently misses the overflowed events and keeps receiving new ones.
  • The server sends periodic SSE keep-alive comments.
  • The stream closes when the server shuts down.

Status codes

Status When
200 Stream opened (text/event-stream).
405 POST /events. Plain-text body method not allowed.
503 The server is in degraded mode, or its filesystem watcher failed to start (for example, the inotify limit is exhausted, or the instance has no named tables). JSON {"error": …} body; for a watcher failure the message starts filesystem watcher failed to start: and gives the reason. POST /query keeps working.