README.md
1# HTTP REST/Websocket API endpoint
2
3EJDB engine provides the ability to start a separate HTTP/Websocket endpoint worker exposing network API for quering and data modifications.
4
5The easiest way to expose database over the network is using the standalone `jbs` server. (Of course if you plan to avoid `C API` integration).
6
7## jbs server
8
9```
10jbs -h
11
12EJDB 2.0.0 standalone REST/Websocket server. http://ejdb.org
13
14 --file <> Database file path. Default: db.jb
15 -f <> (same as --file)
16 --port ## HTTP port number listen to. Default: 9191
17 -p ## (same as --port)
18 --bind <> Address server listen. Default: localhost
19 -b <> (same as --bind)
20 --access <> Server access token matched to 'X-Access-Token' HTTP header value
21 -a <> (same as --access)
22 --trunc Cleanup existing database file on open
23 -t (same as --trunc)
24 --wal Use write ahead logging (WAL). Must be set for data durability.
25 -w (same as --wal)
26
27Advanced options
28 --sbz ## Max sorting buffer size. If exceeded, an overflow temp file for data will be created. Default: 16777216, min: 1048576
29 --dsz ## Initial size of buffer to process/store document on queries. Preferable average size of document. Default: 65536, min: 16384
30 --bsz ## Max HTTP/WS API document body size. Default: 67108864, min: 524288
31
32Use any of the following input formats:
33 -arg <value> -arg=<value> -arg<value>
34
35Use the -h, -help or -? to get this information again.
36```
37
38## HTTP API
39
40Access to HTTP endpoint can be protected by a token specified with `--access`
41command flag or by C API `EJDB_HTTP` options. If access token specified on server, client must provide `X-Access-Token` HTTP header value. If token is required and not provided by client the `401` HTTP code will be reported. If access token is not matched to the token provided the `403` HTTP code will be returned.
42For any other errors server will respond with `500` error code.
43
44## REST API
45
46### POST /{collection}
47Add a new document to the `collection`.
48* `200` success. Body: a new document identifier as `int64` number
49
50### PUT /{collection}/{id}
51Replaces/store document under specific numeric `id`
52* `200` on success. Empty body
53
54### DELETE /{collection}/{id}
55Removes document identified by `id` from a `collection`
56* `200` on success. Empty body
57* `404` if document not found
58
59### PATCH /{collection}/{id}
60Patch a document identified by `id` by [rfc7396](https://tools.ietf.org/html/rfc7396),
61[rfc6902](https://tools.ietf.org/html/rfc6902) data.
62* `200` on success. Empty body
63
64### GET | HEAD /{collections}/{id}
65Retrieve document identified by `id` from a `collection`.
66* `200` on success. Body: JSON document text.
67 * `content-type:application/json`
68 * `content-length:`
69* `404` if document not found
70
71### POST /
72Query a collection by provided query as POST body.
73Body of query should contains collection name in use in the first filter element: `@collection_name/...`
74Request headers:
75* `X-Hints` comma separated extra hints to ejdb2 database engine.
76 * `explain` Show query execution plan before first element in result set separated by `--------------------` line.
77Response:
78* Response data transfered using [HTTP chunked transfer encoding](https://en.wikipedia.org/wiki/Chunked_transfer_encoding)
79* `200` on success.
80* JSON documents separated by `\n` in the following format:
81 ```
82 \r\n<document id>\t<document JSON body>
83 ...
84 ```
85
86Example:
87
88```
89curl -v --data-raw '@family/[age > 18]' -H 'X-Access-Token:myaccess01' http://localhost:9191
90* Rebuilt URL to: http://localhost:9191/
91* Trying 127.0.0.1...
92* TCP_NODELAY set
93* Connected to localhost (127.0.0.1) port 9191 (#0)
94> POST / HTTP/1.1
95> Host: localhost:9191
96> User-Agent: curl/7.58.0
97> Accept: */*
98> X-Access-Token:myaccess01
99> Content-Length: 18
100> Content-Type: application/x-www-form-urlencoded
101>
102* upload completely sent off: 18 out of 18 bytes
103< HTTP/1.1 200 OK
104< connection:keep-alive
105< content-type:application/json
106< transfer-encoding:chunked
107<
108
1094 {"firstName":"John","lastName":"Ryan","age":39}
1103 {"firstName":"Jack","lastName":"Parker","age":35,"pets":[{"name":"Sonic","kind":"mouse","likes":[]}]}
1111 {"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"}}
112* Connection #0 to host localhost left intact
113```
114
115```
116curl --data-raw '@family/[lastName = "Ryan"]' -H 'X-Access-Token:myaccess01' -H 'X-Hints:explain' http://localhost:9191
117[INDEX] MATCHED STR|3 /lastName EXPR1: 'lastName = "Ryan"' INIT: IWKV_CURSOR_EQ
118[INDEX] SELECTED STR|3 /lastName EXPR1: 'lastName = "Ryan"' INIT: IWKV_CURSOR_EQ
119 [COLLECTOR] PLAIN
120--------------------
1214 {"firstName":"John","lastName":"Ryan","age":39}
122```
123
124### OPTIONS /
125Fetch ejdb JSON metadata and available HTTP methods in `Allow` response header.
126Example:
127```
128curl -X OPTIONS -H 'X-Access-Token:myaccess01' http://localhost:9191/
129{
130 "version": "2.0.0",
131 "file": "db.jb",
132 "size": 16384,
133 "collections": [
134 {
135 "name": "family",
136 "dbid": 3,
137 "rnum": 3,
138 "indexes": [
139 {
140 "ptr": "/lastName",
141 "mode": 4,
142 "idbf": 64,
143 "dbid": 4,
144 "rnum": 3
145 }
146 ]
147 }
148 ]
149}
150```
151
152## Websocket API
153
154EJDB supports simple text based protocol over HTTP websocket protocol.
155You can use interactive websocket CLI tool [wscat](https://www.npmjs.com/package/@softmotions/wscat) to communicate with server by hands.
156
157### Commands
158
159#### ?
160Will respond with the following help text message:
161```
162wscat -H 'X-Access-Token:myaccess01' -c http://localhost:9191
163> ?
164<
165<key> info
166<key> get <collection> <id>
167<key> set <collection> <id> <document json>
168<key> add <collection> <document json>
169<key> del <collection> <id>
170<key> patch <collection> <id> <patch json>
171<key> idx <collection> <mode> <path>
172<key> rmi <collection> <mode> <path>
173<key> rmc <collection>
174<key> query <collection> <query>
175<key> explain <collection> <query>
176<key> <query>
177>
178```
179
180Note 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.
181
182Errors are returned in the following format:
183```
184<key> ERROR: <error description>
185```
186
187#### `<key> info`
188Get database metadatas as JSON document.
189
190#### `<key> get <collection> <id>`
191Retrieve document identified by `id` from a `collection`.
192If document is not found `IWKV_ERROR_NOTFOUND` will be returned.
193
194Example:
195```
196> k get family 3
197< k 3 {
198 "firstName": "Jack",
199 "lastName": "Parker",
200 "age": 35,
201 "pets": [
202 {
203 "name": "Sonic",
204 "kind": "mouse",
205 "likes": []
206 }
207 ]
208}
209```
210If document not found we will get error:
211```
212> k get family 55
213< k ERROR: Key not found. (IWKV_ERROR_NOTFOUND)
214>
215```
216
217#### `<key> set <collection> <id> <document json>`
218Replaces/add document under specific numeric `id`.
219`Collection` will be created automatically if not exists.
220
221#### `<key> add <collection> <document json>`
222Add new document to `<collection>` New `id` of document will be generated
223and returned as response. `Collection> will be created automatically if not exists.
224
225Example:
226```
227> k add mycollection {"foo":"bar"}
228< k 1
229> k add mycollection {"foo":"bar"}
230< k 2
231>
232```
233
234#### `<key> del <collection> <id>`
235Remove document identified by `id` from the `collection`.
236If document is not found `IWKV_ERROR_NOTFOUND` will be returned.
237
238#### `<key> patch <collection> <id> <patch json>`
239Apply [rfc7396](https://tools.ietf.org/html/rfc7396) or
240[rfc6902](https://tools.ietf.org/html/rfc6902) patch to the document identified by `id`.
241If document is not found `IWKV_ERROR_NOTFOUND` will be returned.
242
243#### `<key> query <collection> <query>`
244Execute query on documents in specified `collection`.
245**Response:** A set of WS messages with document boidies terminated by the last
246message with empty body.
247```
248> k query family /* | /firstName
249< k 4 {"firstName":"John"}
250< k 3 {"firstName":"Jack"}
251< k 1 {"firstName":"John"}
252< k
253```
254Note about last message: `<key>` with no body.
255
256#### `<key> explain <collection> <query>`
257Same as `<key> query <collection> <query>` but the first response message will
258be prefixed by `<key> explain` and contains query execution plan.
259
260Example:
261```
262> k explain family /* | /firstName
263< k explain [INDEX] NO [COLLECTOR] PLAIN
264
265< k 4 {"firstName":"John"}
266< k 3 {"firstName":"Jack"}
267< k 1 {"firstName":"John"}
268< k
269```
270
271#### <key> <query>
272Execute 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>`
273
274#### `<key> idx <collection> <mode> <path>`
275Ensure index with specified `mode` (bitmask flag) for given json `path` and `collection`.
276Collection will be created if not exists.
277
278Index mode | Description
279--- | ---
280<code>0x01 EJDB_IDX_UNIQUE</code> | Index is unique
281<code>0x04 EJDB_IDX_STR</code> | Index for JSON `string` field value type
282<code>0x08 EJDB_IDX_I64</code> | Index for `8 bytes width` signed integer field values
283<code>0x10 EJDB_IDX_F64</code> | Index for `8 bytes width` signed floating point field values.
284
285##### Example
286Set unique string index `(0x01 & 0x04) = 5` on `/name` JSON field:
287```
288k idx mycollection 5 /name
289```
290
291#### `<key> rmi <collection> <mode> <path>`
292Remove index with specified `mode` (bitmask flag) for given json `path` and `collection`.
293Return error if given index not found.
294
295#### `<key> rmc <collection>`
296Remove collection and all of its data.
297Note: If `collection` is not found no errors will be reported.
298
299