Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

HTTP Gateway

The HTTP Gateway provides a RESTful HTTP/JSON interface to the Laurus search engine. It runs alongside the gRPC server and proxies requests internally:

Client (HTTP/JSON) --> HTTP Gateway (axum) --> gRPC Server (tonic) --> Engine

Enabling the HTTP Gateway

The gateway starts when http_port is configured:

# Via CLI argument
laurus serve --http-port 8080

# Via environment variable
LAURUS_HTTP_PORT=8080 laurus serve

# Via config file
laurus serve --config config.toml
# (set http_port in [server] section)

If http_port is not set, only the gRPC server starts.

Endpoints

MethodPathgRPC MethodDescription
GET/v1/healthHealthService/CheckHealth check
POST/v1/indexIndexService/CreateIndexCreate a new index
GET/v1/indexIndexService/GetIndexGet index statistics
GET/v1/schemaIndexService/GetSchemaGet the index schema
PUT/v1/documents/:idDocumentService/PutDocumentUpsert a document
POST/v1/documents/:idDocumentService/AddDocumentAdd a document (chunk)
GET/v1/documents/:idDocumentService/GetDocumentsGet documents by ID
DELETE/v1/documents/:idDocumentService/DeleteDocumentsDelete documents by ID
POST/v1/commitDocumentService/CommitCommit pending changes
POST/v1/searchSearchService/SearchSearch (unary)
POST/v1/search/streamSearchService/SearchStreamSearch (Server-Sent Events)

API Examples

Health Check

curl http://localhost:8080/v1/health

Create an Index

curl -X POST http://localhost:8080/v1/index \
  -H 'Content-Type: application/json' \
  -d '{
    "schema": {
      "dynamic_field_policy": "dynamic",
      "fields": {
        "title": {"text": {"indexed": true, "stored": true, "term_vectors": true}},
        "body": {"text": {"indexed": true, "stored": true, "term_vectors": true}}
      },
      "default_fields": ["title", "body"]
    }
  }'

The dynamic_field_policy key is optional. It controls how fields absent from the schema are handled at ingest time. Accepted values: "strict", "dynamic" (default), "ignore". See Schema & Fields for the full semantics and the warning about silent truncation under "dynamic".

Get Index Statistics

curl http://localhost:8080/v1/index

Get Schema

curl http://localhost:8080/v1/schema

Upsert a Document (PUT)

Replaces the document if it already exists:

curl -X PUT http://localhost:8080/v1/documents/doc1 \
  -H 'Content-Type: application/json' \
  -d '{
    "document": {
      "fields": {
        "title": "Hello World",
        "body": "This is a test document."
      }
    }
  }'

Add a Document (POST)

Adds a new chunk without replacing existing documents with the same ID:

curl -X POST http://localhost:8080/v1/documents/doc1 \
  -H 'Content-Type: application/json' \
  -d '{
    "document": {
      "fields": {
        "title": "Hello World",
        "body": "This is a test document."
      }
    }
  }'

Get Documents

curl http://localhost:8080/v1/documents/doc1

Delete Documents

curl -X DELETE http://localhost:8080/v1/documents/doc1

Commit

curl -X POST http://localhost:8080/v1/commit
curl -X POST http://localhost:8080/v1/search \
  -H 'Content-Type: application/json' \
  -d '{"query": "body:test", "limit": 10}'

Search with Field Boosts

curl -X POST http://localhost:8080/v1/search \
  -H 'Content-Type: application/json' \
  -d '{
    "query": "rust programming",
    "limit": 10,
    "field_boosts": {"title": 2.0}
  }'
curl -X POST http://localhost:8080/v1/search \
  -H 'Content-Type: application/json' \
  -d '{
    "query": "body:rust",
    "query_vectors": [{"vector": [0.1, 0.2, 0.3], "weight": 1.0}],
    "limit": 10,
    "fusion": {"rrf": {"k": 60}}
  }'

Streaming Search (SSE)

The /v1/search/stream endpoint returns results as Server-Sent Events (SSE). Each result is sent as a separate event:

curl -N -X POST http://localhost:8080/v1/search/stream \
  -H 'Content-Type: application/json' \
  -d '{"query": "body:test", "limit": 10}'

The response is a stream of SSE events:

data: {"id":"doc1","score":0.8532,"document":{...}}

data: {"id":"doc2","score":0.4210,"document":{...}}

JSON Field Value Inference

When the gateway accepts a document body (PUT /v1/documents/:id or POST /v1/documents/:id), each value inside document.fields is converted to the engine’s DataValue type using the same inference rules as schema-less ingestion. This keeps the HTTP and gRPC paths in sync.

JSON valueResulting field typeNotes
null(skipped)The field is emitted as a NullValue and dropped during ingest.
true / falseboolean
integer (fits in i64)integer
float / large integerfloat
"text"text
[1, 2, 3] (all integers)integer with multi_valued: trueMulti-valued numeric field.
[1.0, 2.5] (any non-integer number)float with multi_valued: true
[] (empty array)(skipped)Element type cannot be determined, so the field is skipped.
{"latitude": ..., "longitude": ...}geo
{"lat": ..., "lon": ...} / {"lat": ..., "lng": ...}geoShort aliases for latitude / longitude are accepted.
{"x": ..., "y": ..., "z": ...}geo3dAll three keys required, finite numbers, ECEF meters. Mixing with lat/lon keys is rejected.

The gateway returns an HTTP 400 (Bad Request) when:

  • An array contains mixed types or non-numeric elements (e.g. [1, "x"]).
  • An object is not a valid geographic point (missing latitude / longitude keys for 2D, or missing any of x / y / z for 3D).
  • A geographic latitude is outside [-90, 90] or a longitude is outside [-180, 180].
  • A 3D ECEF coordinate is non-finite (NaN / Inf).
  • An object mixes 2D (lat / lon) and 3D (x / y / z) keys.

Vector and bytes fields cannot be inferred from JSON alone and must be declared in the schema. Numeric arrays sent against a declared vector field are coerced to a vector of f32 values automatically, so REST clients can post embeddings as plain JSON arrays.

3D Geographic Queries

3D ECEF queries reuse the lexical DSL string passed via query. The gateway forwards it unchanged to the engine, so the same forms work over HTTP as over gRPC:

curl -X POST http://localhost:8080/v1/search \
  -H 'Content-Type: application/json' \
  -d '{
    "query": "position:geo3d_distance(-3955182, 3350553, 3700276, 5000)",
    "limit": 10
  }'

See Query DSL → 3D Geographic Queries for geo3d_bbox and geo3d_nearest syntax.

Request/Response Format

All request and response bodies use JSON. The JSON structure mirrors the gRPC protobuf messages. See gRPC API Reference for the full message definitions.