# JSON API
When running `mix exograph.web`, a JSON API is available alongside the web UI.
## Endpoints
### POST /api/search
Structural or text search.
curl -X POST http://localhost:4200/api/search \
-H "Content-Type: application/json" \
-d '{"pattern": "Repo.get!(_, _)", "limit": 10}'
Parameters:
- `pattern` (required) — search pattern or text query
- `mode` — `"structural"` (default), `"text"`, or `"regex"`
- `limit` — max results (default: 50, max: 200)
- `cursor` — pagination cursor from previous response
- `package_id` — scope to a specific package
Response:
{
"results": [{"type": "def", "file": "lib/repo.ex", "package": "ecto", ...}],
"count": 10,
"elapsed_ms": 23.4,
"next_cursor": "MTA"
}
### POST /api/query
Execute a DSL query.
curl -X POST http://localhost:4200/api/query \
-H "Content-Type: application/json" \
-d '{"query": "from(d in Definition, where: d.kind == :def, where: prefix_search(d.name, \"handle\"))"}'
Parameters:
- `query` (required) — DSL query string
- `cursor` — pagination cursor
### GET /api/packages
List indexed packages sorted by fragment count.
curl http://localhost:4200/api/packages
### GET /api/stats
Index statistics.
curl http://localhost:4200/api/stats
## Rate Limiting
The API is rate limited to 60 requests per minute per IP.
Headers `x-ratelimit-limit` and `x-ratelimit-remaining` are included in responses.
Exceeding the limit returns HTTP 429.
## Security
Query execution uses a safe AST interpreter — no `Code.eval_string`.
Dangerous operations (`System.cmd`, `File.read!`, etc.) are rejected at parse time.
Value expressions in predicates are evaluated through the Dune sandbox.