StashKu
StashKu is a data agnostic, flat-data framework that provides a full-stack API for RESTful operations against common data storage and communication mediums served up from built-in and pluggable custom engines. The framework provides the tools needed to begin leveraging and extending it out of the box.
Engines act as the translator and handlers of StashKu RESTful requests - whether they are relaying data from a hard disk, a hardware sensor, a database, or even an API. They are responsible for crafting standardized responses which StashKu hands back off to the requestor. As long as it can be interacted with through RESTful requests such as GET, POST, PUT, PATCH, DELETE, and OPTIONS, StashKu could potentially have an engine for it. If you'd like to create your own engine, check out the tutorials on our formal documentation site.
🔩 Two engines are provided out of the box:
memory
andfetch
which are the defaults for node and the browser respectively. Check out our express+browser demo to see them both in action.
StashKu supports some amazing features:
- Can be used in modern browsers or on server-side (node). ─=≡Σ(((ノ☉ヮ⚆)ノ
- CRUD via RESTful requests, paging, sorting, constraining properties, and even filtering via conditional expressions.
- Sorting through objects or string expressions:
e.g.{FirstName} DESC
{LastName} ASC
- Filtering through objects, chained callback objects, or string expressions:
e.g.({FirstName} CONTAINS "Chris" OR {Age} >= 30) AND {Ticket} == true
- Support of models with JSDoc & VS Code intellisense.
- A command line interface which allows you to make GET and OPTIONS requests (generate models).
See: Going next-level with Models. - Middleware support.
See: Writing your own middleware tutorial. - Pluggable engine support.
See: Writing your own engine tutorial. - Built-in logging extensibility through standard logger callbacks.
Check out our console/file log middleware stashku-log.
You may be interested in these other engines:
- stashku-sql: A library for interacting with Microsoft SQL Server and Postgres databases through StashKu.
- stashku-log: A logging library that taps into the logging interface of StashKu and provides reusable log handling and output options for applications.
Getting Started
npm i --save @appku/stashku
Once installed, you can begin using the StashKu package in your code and the stashku
CLI.
Code Quick-Start
Using StashKu is meant to be painless - easy to learn but advanced when needed.
To use StashKu from the browser, you can bring in StashKu from a CDN, or copy the latest bundle from the
web/stashku-*.js
repository path, or use the npm
installed package in your bundling project (React, Vue, etc.).
When StashKu starts, if an engine is not configured then a default one will be loaded. In-browser, the fetch
engine
is the default. On node, the memory
engine is the default. You can use another engine by specifying it's package
name (on node), or setting the engine value to the custom engine's instance.
import StashKu from '@appku/stashku';
//...
let stash = new StashKu();
//...or
let stash = new StashKu({ engine: '@appku/stashku-sql' });
//...or
let myEngine = new WhateverEngine();
await myEngine.configure({ /* custom engine settings */ }, stash.log);
let stash = new StashKu({ engine: myEngine });
Making RESTful Requests
The beauty of StashKu is it's alignment with REST. Out-of-the-box, StashKu provides six (6) request methods:
- GET: For retrieving resource data.
- POST: For creating resource data.
- PUT: For updating keyed resource data.
- PATCH: For updating any resource data.
- DELETE: For destroying resource data.
- OPTIONS: For retrieving resource schema.
You can use these methods to submit a RESTful request to your loaded engine and act on it's resources.
No matter the engine, the request and response structure and interface is the same.
(ღ˘⌣˘ღ)
For Example
The@appku/stashku-sql
engine provides an interface to a database. Submitting a GET request through StashKu would be handed to the engine and translated into aSELECT
SQL query and run on the database to retrieve table or view ("resources") data. The engine grabs the database query results and translates them into a standardized StashKuResponse
and hands them back to the requestor.
GET
import StashKu, { Filter } from '@appku/stashku';
let stash = new StashKu();
let name = 'Bob\'s Car Wash'
let response = await stash.get(r => r
.from('Contacts')
.properties('ID', 'First_Name', 'Last_Name')
.skip(5)
.take(10)
.where(Filter.tmpl`{First_Name} CONTAINS "${name}" AND {Year} GTE 1953`)
.sort('{ID} ASC', 'First_Name', 'Last_Name')
);
//Response { data: [...], total, returned, affected }
POST
let stash = new StashKu();
let response = await stash.post(r => r
.to('Contacts')
.objects(
{ First_Name: 'Bob', Last_Name: 'Gorbermon', Age: 55 },
{ First_Name: 'Susan', Last_Name: 'Miller', Age: 23 },
{ First_Name: 'Christopher', Last_Name: 'Eaton', Age: 967 }
)
);
//Response { data: [...], total, returned, affected }
PUT
let stash = new StashKu();
let response = await stash.put(r => r
.to('Contacts')
.pk('ID')
.objects({ ID: 344, Last_Name: 'Geeberman' })
);
//Response { data: [...], total, returned, affected }
PATCH
let stash = new StashKu();
let response = await stash.patch(r => r
.to('Contacts')
.template({ Attended_Event: true })
.where( f => f
.and('Ticket', f.OP.EQUALS, true)
.and('Attended_Event', f.OP.EQUALS, false)
.or('Age', f.OP.GREATERTHAN, 40)
.or('First_Name', f.OP.STARTSWITH, 'B')
)
);
//Response { data: [...], total, returned, affected }
DELETE
let stash = new StashKu();
let response = await stash.delete(r => r
.from('Contacts')
.where( f => f
.or('First_Name', f.OP.ISNULL)
.or('Age', f.OP.LESSTHAN, 18)
)
);
//Response { data: [...], total, returned, affected }
OPTIONS
let stash = new StashKu();
let response = await stash.options(r => r.from('Contacts'));
//Response { data: [...], total, returned, affected }
Responses That Make Life Easy
The great thing about StashKu, is that no matter what engine you use, the request & response is standard. The response from a request always has the following properties:
data
-Array.<*>
: An array of the objects or values resulting from the request to the engine.total
-Number
: The number of objects or values resulting from the request in consideration of anywhere
conditions (if applicable), but disregarding anyskip
andtake
paging limitations (only on GET requests).affected
-Number
: The number of objects or values affected (altered/touched/created) in storage as a result of the request This number is always0
for GET requests.returned
-Number
: The number of objects or values to be returned from the engine as a result of the request.
Every Response
also includes a single helper function: one()
which will return the first value of the data, if it is present, otherwise it returns null
.
CLI Quick-Start
Stashku provides a CLI that is available via the stashku
command. This can be used when installed locally with the
npx
command. Optionally you can npm i @appku/stashku -g
, and with the -g
flag the command is available anywhere
on your system.
Want to know more? Check out the CLI tutorial on the official documentation site.
npx stashku
The CLI currently supports running GET and OPTIONS queries using the settings discovered from your environment
(including a .env
file).
Using the CLI, you can retrieve data directly from the configured engine with a get
command:
npx stashku get "ContactRecords"
and even do advanced queries with where
and sort
logic:
npx stashku get "ContactRecords" -w '{Name} CONTAINS "joe"' -sb '{ID} DESC'
You can also gain an understanding of your resource schema using the options
command:
npx stashku options "Products"
Taking it a step further, you can generate extensible JavaScript models representing your resource:
npx stashku options "Products" -x ./models/
Optionally, supplying a JSON array from a file of resource names to export:
npx stashku options ./model-list.json -x ./models/
The generated models are 100% usable in StashKu and are designed to provide VS-Code compatible intellisense proper JSdoc tags.
Curious about models? Find the model tutorial here.
Configuration
StashKu can be configured using the following variables.
-
STASHKU_ENGINE
Specifies the name of the StashKu engine (or package) to initialize. The built-in options are:"memory"
and"fetch"
.- Type:
String
- Default:
"memory"
(node) or"default"
(browser) - StashKu configuration property:
engine
.
JavaScript Example
new StashKu({ engine: '@appku/stashku-sql' })
Shell/Environment Example
export STASHKU_ENGINE='@appku/stashku-sql'
- Type:
-
STASHKU_MODEL_NAME_REMOVE
Used by theModelUtility
for defining regular expressions that match text to be removed from a generated model's class name (derived from a resource name). By default the configured expressions will strip "dbo.", "etl.", and "rpt." prefixes from resource names. The regular expressions must be declared within a JSON array in string format.- Type:
String
- Default:
["/^\\[?dbo\\]?\\./i", "/^\\[?etl\\]?\\./i", "/^\\[?rpt\\]?\\./i"]
Shell/Environment Example
export STASHKU_MODEL_NAME_REMOVE='["/^\\[?schema\\]?\\./i"]'
- Type:
-
STASHKU_MODEL_NAME_CASE
Defines the generated model class name case format. Can be either"camel"
or"pascal"
(default).- Type:
String
- Default:
"pascal"
Shell/Environment Example
export STASHKU_MODEL_NAME_CASE='pascal'
- Type:
-
STASHKU_MODEL_PROPERTY_CASE
Defines the generated property name case format. Can be either"camel"
(default) or"pascal"
.- Type:
String
- Default:
"camel"
Shell/Environment Example
export STASHKU_MODEL_PROPERTY_CASE='camel'
- Type:
-
STASHKU_MODEL_PROPERTY_RESERVED_PREFIX
When StashKu generates a model for a resource - property names that collide with the keywords "prototype" and "name" will be prefixed with this value to avoid breakage.- Type:
String
- Default:
"Resource"
Shell/Environment Example
export STASHKU_MODEL_PROPERTY_CASE='camel'
- Type:
-
STASHKU_MODEL_HEADER
Instructs StashKu to add a headermodel
with the value of the$stashku
definition to all modelled RESTful requests. Certain engines, such asfetch
may offer advanced features that leverage model information in their operation. This is disabled by default.- Type:
Boolean
- Default:
false
- StashKu configuration property:
model.header
.
JavaScript Example
new StashKu({ model: { header: false } })
Shell/Environment Example
export STASHKU_MODEL_HEADER=false
- Type:
The built-in engines all have their own supported configuration's as well, you can find them described through their API documentation or the available tutorials:
Development
StashKu is developed under the AppKu umbrella, sponsored and backed by Append. It is built using JavaScript in module format.
Generating Documentation
You can generate a static JSDoc site under the docs/
path using the command npm run docs
. Once generated, you can run npm run serve-docs
to run a local web server that shows the generated documentation.
Generating a Web Bundle
To generate a new web bundle, run npm run build
. This will compile StashKu into a single .js
file under the web/
directory with the local version number.
Testing
This project uses jest
to perform unit tests.
Running Tests
Run npm test
to run jest unit tests.
Run npm run lint
to run ESLint, optionally install the Visual Studio Code ESLint extension to have linting issues show in your "Problems" tab and be highlighted.
If you are writing unit tests, you may need to npm install @types/jest
to get intellisense in Visual Studio Code if for some reason it did not get installed.
Publishing
Only maintainers with proper access can publish this package to npm. To do so as maintainers, you can publish by running the following command:
npm publish --registry=https://registry.npmjs.org --access=public