Skip to content

Latest commit

 

History

History
298 lines (251 loc) · 9.61 KB

README.md

File metadata and controls

298 lines (251 loc) · 9.61 KB

HTTP REST/Websocket API endpoint

EJDB engine provides the ability to start a separate HTTP/Websocket endpoint worker exposing network API for quering and data modifications. SSL (TLS 1.2) is supported by jbs server.

The easiest way to expose database over the network is use the standalone jbs server. (Of course if you want to avoid C API integration).

jbs server

Usage:

	 ./jbs [options]

	-v, --version		Print program version.
	-f, --file=<>		Database file path. Default: ejdb2.db
	-p, --port=NUM		HTTP server port numer. Default: 9191
	-l, --listen=<>		Network address server will listen. Default: localhost
	-k, --key=<>		PEM private key file for TLS 1.2 HTTP server.
	-c, --certs=<>		PEM certificates file for TLS 1.2 HTTP server.
	-a, --access=TOKEN|@FILE		Access token to match 'X-Access-Token' HTTP header value.
	-r, --access-read		Allows unrestricted read-only data access.
	-C, --cors		Enable COSR response headers for HTTP server
	-t, --trunc		Cleanup/reset database file on open.
	-w, --wal		use the write ahead log (WAL). Used to provide data durability.

Advanced options:
	-S, --sbz=NUM		Max sorting buffer size. If exceeded, an overflow temp file for data will be created.
                  Default: 16777216, min: 1048576
	-D, --dsz=NUM		Initial size of buffer to process/store document on queries. Preferable average size of document. 
                  Default: 65536, min: 16384
	-T, --trylock Exit with error if database is locked by another process. 
                If not set, current process will wait for lock release.

HTTP API

HTTP endpoint may be protected by a token specified with --access flag or C API EJDB_HTTP struct. If access token was set, client should provide X-Access-Token HTTP header. If token is required but not provided by client 401 HTTP code will be reported. If access token is not matched to the token provided by client server will respond with 403 HTTP code.

REST API

POST /{collection}

Add a new document to the collection.

  • 200 success. Body: a new document identifier as int64 number

PUT /{collection}/{id}

Replaces/store document under specific numeric id

  • 200 on success. Empty body

DELETE /{collection}/{id}

Removes document identified by id from a collection

  • 200 on success. Empty body
  • 404 document not found

PATCH /{collection}/{id}

Patch a document identified by id by rfc7396, rfc6902 data.

  • 200 on success. Empty body

GET | HEAD /{collections}/{id}

Retrieve document identified by id from a collection.

  • 200 on success. Body: JSON document text.
    • content-type:application/json
    • content-length:
  • 404 document not found

POST /

Query a collection by provided query as POST body. Body of query should contains collection name in use in the first filter element: @collection_name/... Request headers:

  • X-Hints comma separated extra hints to ejdb2 database engine.
    • explain Show query execution plan before first element in result set separated by -------------------- line. Response:
  • Response data transfered using HTTP chunked transfer encoding
  • 200 on success.
  • JSON documents separated by \n in the following format:
    \r\n<document id>\t<document JSON body>
    ...
    

Example:

curl -v --data-raw '@family/[age > 18]' -H 'X-Access-Token:myaccess01' http://localhost:9191
* Rebuilt URL to: http://localhost:9191/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 9191 (#0)
> POST / HTTP/1.1
> Host: localhost:9191
> User-Agent: curl/7.58.0
> Accept: */*
> X-Access-Token:myaccess01
> Content-Length: 18
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 18 out of 18 bytes
< HTTP/1.1 200 OK
< connection:keep-alive
< content-type:application/json
< transfer-encoding:chunked
<

4	{"firstName":"John","lastName":"Ryan","age":39}
3	{"firstName":"Jack","lastName":"Parker","age":35,"pets":[{"name":"Sonic","kind":"mouse","likes":[]}]}
1	{"firstName":"John","lastName":"Doe","age":28,"pets":[{"name":"Rexy rex","kind":"dog","likes":["bones","jumping","toys"]},{"name":"Grenny","kind":"parrot","likes":["green color","night","toys"]}],"address":{"city":"New York","street":"Fifth Avenue"}}
* Connection #0 to host localhost left intact
curl --data-raw '@family/[lastName = "Ryan"]' -H 'X-Access-Token:myaccess01' -H 'X-Hints:explain' http://localhost:9191
[INDEX] MATCHED  STR|3 /lastName EXPR1: 'lastName = "Ryan"' INIT: IWKV_CURSOR_EQ
[INDEX] SELECTED STR|3 /lastName EXPR1: 'lastName = "Ryan"' INIT: IWKV_CURSOR_EQ
 [COLLECTOR] PLAIN
--------------------
4	{"firstName":"John","lastName":"Ryan","age":39}

OPTIONS /

Fetch ejdb JSON metadata and available HTTP methods in Allow response header. Example:

curl -X OPTIONS -H 'X-Access-Token:myaccess01'  http://localhost:9191/
{
 "version": "2.0.0",
 "file": "db.jb",
 "size": 16384,
 "collections": [
  {
   "name": "family",
   "dbid": 3,
   "rnum": 3,
   "indexes": [
    {
     "ptr": "/lastName",
     "mode": 4,
     "idbf": 64,
     "dbid": 4,
     "rnum": 3
    }
   ]
  }
 ]
}

Websocket API

EJDB supports simple text based protocol over HTTP websocket protocol. You can use interactive websocket CLI tool wscat to communicate with server by hands.

Commands

?

Will respond with the following help text message:

wscat  -H 'X-Access-Token:myaccess01' -c http://localhost:9191
> ?
<
<key> info
<key> get     <collection> <id>
<key> set     <collection> <id> <document json>
<key> add     <collection> <document json>
<key> del     <collection> <id>
<key> patch   <collection> <id> <patch json>
<key> idx     <collection> <mode> <path>
<key> rmi     <collection> <mode> <path>
<key> rmc     <collection>
<key> query   <collection> <query>
<key> explain <collection> <query>
<key> <query>
>

Note about <key> prefix before every command; It is an arbitrary key chosen by client and designated to identify particular websocket request, this key will be returned with response to request and allows client to identify that response for his particular request.

Errors are returned in the following format:

<key> ERROR: <error description>

<key> info

Get database metadatas as JSON document.

<key> get <collection> <id>

Retrieve document identified by id from a collection. If document is not found IWKV_ERROR_NOTFOUND will be returned.

Example:

> k get family 3
< k     3       {
 "firstName": "Jack",
 "lastName": "Parker",
 "age": 35,
 "pets": [
  {
   "name": "Sonic",
   "kind": "mouse",
   "likes": []
  }
 ]
}

If document not found we will get error:

> k get family 55
< k ERROR: Key not found. (IWKV_ERROR_NOTFOUND)
>

<key> set <collection> <id> <document json>

Replaces/add document under specific numeric id. Collection will be created automatically if not exists.

<key> add <collection> <document json>

Add new document to <collection> New id of document will be generated and returned as response. `Collection> will be created automatically if not exists.

Example:

> k add mycollection {"foo":"bar"}
< k     1
> k add mycollection {"foo":"bar"}
< k     2
>

<key> del <collection> <id>

Remove document identified by id from the collection. If document is not found IWKV_ERROR_NOTFOUND will be returned.

<key> patch <collection> <id> <patch json>

Apply rfc7396 or rfc6902 patch to the document identified by id. If document is not found IWKV_ERROR_NOTFOUND will be returned.

<key> query <collection> <query>

Execute query on documents in specified collection. Response: A set of WS messages with document boidies terminated by the last message with empty body.

> k query family /* | /firstName
< k     4       {"firstName":"John"}
< k     3       {"firstName":"Jack"}
< k     1       {"firstName":"John"}
< k

Note about last message: <key> with no body.

<key> explain <collection> <query>

Same as <key> query <collection> <query> but the first response message will be prefixed by <key> explain and contains query execution plan.

Example:

> k explain family /* | /firstName
< k     explain [INDEX] NO [COLLECTOR] PLAIN

< k     4       {"firstName":"John"}
< k     3       {"firstName":"Jack"}
< k     1       {"firstName":"John"}
< k

Execute query text. Body of query should contains collection name in use in the first filter element: @collection_name/.... Behavior is the same as for: <key> query <collection> <query>

<key> idx <collection> <mode> <path>

Ensure index with specified mode (bitmask flag) for given json path and collection. Collection will be created if not exists.

Index mode Description
0x01 EJDB_IDX_UNIQUE Index is unique
0x04 EJDB_IDX_STR Index for JSON string field value type
0x08 EJDB_IDX_I64 Index for 8 bytes width signed integer field values
0x10 EJDB_IDX_F64 Index for 8 bytes width signed floating point field values.
Example

Set unique string index (0x01 & 0x04) = 5 on /name JSON field:

k idx mycollection 5 /name

<key> rmi <collection> <mode> <path>

Remove index with specified mode (bitmask flag) for given json path and collection. Return error if given index not found.

<key> rmc <collection>

Remove collection and all of its data. Note: If collection is not found no errors will be reported.