Customers
Sample REST server demonstrating various styles of REST endpoints
- Static
-
resource names are predefined at endpoint registration time, e.g.
{/customers}
- Dynamic
-
the resource name (or part of it) is supplied at call-time, e.g.
/db/{tbl}/{col}
- API-like
-
same as static but uses verbs instead of names, e.g.
/getCustomers
.rest:.com_kx_rest; / Alias namespace for convenience
//
// @desc App initialization.
//
init:{
.rest.init[enlist[`autoBind]!enlist[1b]]; / Initialize
initStatic[]; / Sample static endpoints
initDynamic[]; / Sample dynamic endpoints
initApi[]; / Sample API-like endpoints
.rest.register[`get;"/help"; / Returns information about registered endpoints
"Retrieves information about registered REST endpoints";
{.rest.t};
()!()];
.rest.register[`get;"/hc"; / health-check
"health-check endpoint";
{"ok"};
()!()];
.rest.register[`get;"/_ping";
"for testing";
{"pong"};
()!()]; }
//
// Sample parameter subset to support paging.
//
pagingParams:.rest.reg.data[`i;-6h;0b;0;"Offset of first row"],
.rest.reg.data[`cnt;-6h;0b;10;"Number of rows to return"];
//
// Wraps `#` to limit to data size.
//
take:{[n;d]min[(n;count d)]#d}
//
// Initialization examples.
//
//
// Static endpoints, and various styles of versioning.
//
initStatic:{
.rest.register[`get;"/customers";
"Returns all customers";
{take[x[`arg;`cnt]]select from customers where i>=x[`arg;`i]};
pagingParams
];
.rest.register[`get;"/customers.2";
"Returns all customers (version 2)";
{take[x[`arg;`cnt]]update newCol:1 from select from customers where i>=x[`arg;`i]};
pagingParams
];
.rest.register[`get;"/v3/customers";
"Returns all customers (version 3)";
{take[x[`arg;`cnt]]update newCol:1, newCol2:10 from select from customers where i>=x[`arg;`i]};
pagingParams
];
.rest.register[`get;"/customers/{id}";
"Returns one or more customers by their IDs";
{select from customers where id in x[`arg;`id]};
.rest.reg.data[`id;6h;1b;0Ni;"One or more customer IDs"]
]; }
initDynamic:{
.rest.register[`get;"/db";
"Retrieves list of table names";
{tables[]};
()!()
];
.rest.register[`get;"/db/{table}";
"Retrieves a table";
.tbl.getData;
.rest.reg.data[`table;-11h;1b;`;"Table name"],
pagingParams
];
.rest.register[`get;"/db/{table}/meta";
"Retrieves metadata of a table";
{0!meta x[`arg;`table]};
.rest.reg.data[`table;-11h;1b;`;"Table name"]
];
.rest.register[`get;"/db/{table}/{col}";
"Retrieves a column subset of a table";
.tbl.getData;
.rest.reg.data[`table;-11h;1b;`;"Table name"],
.rest.reg.data[`col;11h;1b;0#`;"Result columns"],
pagingParams
]; }
initApi:{
.rest.register[`get;"/getCustomers";
"Returns all customers";
{([] id:til 10; nm:10?`5)};
::
]; }
//
// Automatic data retrieval
//
//
// @desc Generic data retrieval handler. Look for {tbl}, {id}, and {rel} arguments
//
.tbl.getData:{
tn:x[`arg;`table];
i_:$[`i in key x[`arg];x[`arg;`i];0];
cnt:$[`cnt in key x[`arg];x[`arg;`cnt];0W];
if[not tn in tables[]; 'table]; / Check whether table exists
w:$[""~0N!flt:x[`data];();enlist parse flt]; / If request is a POST, then data is expected to be the where clause
c:$[`col in key x`arg;{x!x}x[`arg;`col];()]; / Columns to retrieve
take[cnt]select from ?[tn;w;0b;c] where i>=i_ }
init[]
//
// Test data
//
n:100
customers:([] id:1+til n; name:n?`7)
sn:`aapl`goog`msft`nke`ftse
symbols:1!([] sym:`aapl`goog`msft`nke`ftse; src:count[sn]?`8);
trades:([] ts:$[12h;.z.d]+$[`minute;1]*til n;
sym:n?(0!symbols)[`sym];
price:n?10.0;
size:n?1000)