CastMyData Server
Realtime database in a jiffy.
Table Of Contents
- Features
- Available Plugins
- Available Clients
- Requirements
- Installation
- How To Use
- Plugin
- Access Control Lists
- Data Storage
- Configuration
- RESTful API
- Testing
- License
Features
- Realtime client that syncs data with the server automatically using socket.io.
- Broadcasting messages
- RESTful HTTP API
- Server side access control list
- Plugin System
Available Plugins
Available Clients
Requirements
- Redis Server: link
- NodeJS & NPM
- Git
Installation
As a package:
$ npm install --save castmydata-server$ node node_modules/castmydata-server/setup$ npm run setup
As a base project:
$ git clone https://github.com/castmydata/castmydata-server.git && cd castmydata-server$ npm install$ npm run setup
Using Docker:
docker run -d --name redis -p 6374 redis:3docker run -d -p 8080 --link redis --name castmydata-server zulfajuniadi/castmydata-server
A .castmydata.env
file will be created in your directory that has configuration for castmydata-server.
How To Use
As a package:
// Load environment variablesvar dotenv = ; var CastMyData = ;var castmydata = // options; // Load plugins// Plugins are loaded according to castmydata; // The express instance is exposed castmydataexpress; // And so is the socket.io instancecastmydataio; // And so is the http instancecastmydatahttp; // OK LETS GO!castmydatastart;
As a base project:
run npm start
to start the server in background. Then navigate to http://localhost:8080 to view a sample client.
run npm stop
to stop the running server
run npm restart
to restart the server
Plugin
Plugins are a core feature in CastMyData. In fact, most of the application logic behind CastMyData is implemented as plugins.
CastMyData features a plugin system that are loaded during the application instantiation. Your custom plugins will be after all the core plugins has been loaded. This means that you;ll have access to express, socket.io, pubsub, nodejs http instance and all other goodies that's running in the background.
The plugin should have three functions: register
, startup
, and shutdown
.
Sample plugin:
// SamplePlugin.js{ thisapp = app;};// Code executed when the plugin is first instantiatedSamplePluginprototype {}// Code executed when castmydata.start() is calledSamplePluginprototype { ;}// Code executed when castmydata.shutdown() is calledSamplePluginprototype { ;} moduleexports = SamplePlugin;
Sample usage:
var castmydata = ;var SamplePlugin = ;castmydata;
Access Control Lists
ACL can be configured during the instantiation of the server as so:
acl: 'some-db': { // only allow author to update own record ifoldDatauserid != thisid return ; ; } ;
ACL callbacks provided are:
- sync => (callback)
- post => (newData, callback)
- put => (oldData, newData, callback)
- delete => (oldData, callback)
- clear => (callback)
- listen => (channel, callback)
- unlisten => (channel, callback)
- broadcast => (request, callback)
To deny an action, call the callback with an Error argument as: callback(new Error('Some Error'))
. If the callback is called without a first argument, the request will be processed.
In the event of the ACL error, the record will be reverted to it's original state.
Data Storage
By default CastMyData will use Redis as the default storage. You can change the data store to your preferred choice by supplying the db
property during start:
var SomeDatabase = ;var castmydata = db: SomeDatabase;
The database should be a Javascript function that will be instantiated during the app registering.
The database should implement all the following methods:
- register => function(app)
- startup => function(app, callback)
- all => function(tableName, callback)
- where => function(tableName, filter, callback) // filter is based on siftJS
- find => function(tableName, id, callback)
- post => function(tableName, record, callback)
- put => function(tableName, id, record, callback)
- delete => function(tableName, id, callback)
- clear => function(tableName, callback)
- shutdown => function(app, callback)
You can view the redis database as an example implementation.
Configuration
Configuration using .env file
Configurations are primarily set within the .castmydata.env
file
Redis Configuration:
- REDIS_HOST: Your Redis host. e.g. 127.0.0.1
- REDIS_PORT: Your Redis port. e.g. 6379
- REDIS_DB: Your Redis database. e.g. 0
- REDIS_PASS: Your Redis database password.
HTTP Configuration:
- HTTP_PUBLIC_DIR: Serve files from the public path. e.g. true
- HTTP_ORIGIN: CORS origin. e.g. *:* more
- HTTP_PORT: Binding port. e.g. 8080
- HTTP_BIND_ADDR: Binding address. e.g. localhost
- HTTP_SECURE: Use HTTPS. e.g. true
- HTTPS_CERT_FILE: Path to SSL certificate. e.g. ./certs/server.crt
- HTTPS_CERT_KEY: Path to SSL certificate private key. e.g. ./certs/server.key
- HTTPS_KEY_PASS: Password for private key
- REDIR_TO_HTTPS: Fire up a HTTP server to redirect traffic to HTTPS
- REDIR_TO_HTTPS_PORT: The HTTP redirect server port
API Configuration:
- API_ENABLED: Enable / disable RESTful API. e.g. true
- API_TOKEN: Random string for RESTful API calls
Others:
- IGNORE_INDEX: Ignore index.html file inside your public directory. e.g. false
options.config
argument
Configuration using the Alternatively, configurations can be overriddedn via the app options.config
argument:
var castmydata = config: // this will override REDIS_HOST value set // in the .castmydata.env file REDIS_HOST: '127.0.0.1' facebook: appId: 'xxxxxxx' accessToken: ''
Get & set application config
The application configuration can be accessed via the app.get
method. This may be useful if you want to access your configuration via a plugin or database. The app.get
method takes two arguments:
- The config key you want to access.
- A default value should the config key return a falsy value
// some plugin startup functionSomePluginprototype { var host = app; var port = app; // returns 6379 as default}
To access nested keys, you may use dot notation:
FacebookAuthprototype { var appId = app; // returns 'xxxxxxx'}
You are able to change the application configs via the app.set
:
FacebookAuthprototype { app; console; // returns { // appId: "xxxxxxx", // accessToken: "yyyyyyy" // }}
RESTful API
All API calls to the server must have the Authorization
header set to Bearer xxx
where xxx
is the API_TOKEN
string in your server .env
file.
You will get a
403 HTTP Error
if theAuthorization
header is not sent or is invalid
All requests' URL will begin with /db/{dbname}
where {dbname}
is your database name. The database will be auto created.
Once you have CastMyData server running, you can test it here:
Be sure to change the server URL and Authorization token to match your environment.
GET /db/some-db
Returns all records in the database some-db
.
Request:
$ curl -H "Authorization:Bearer ieiLHIvNCVne3CY2EiDWK089lWo6QuU3" \ http://localhost:8080/db/some-db
Success Response:
HTTP Code: 200
GET /db/some-db/some-id
Find record with id of some-id
in the database some-db
.
Request:
$ curl -H "Authorization:Bearer ieiLHIvNCVne3CY2EiDWK089lWo6QuU3" \ http://localhost:8080/db/some-db/7cb5696c-af0d-48c4-b48c-dfd457509b5e
Success Response:
HTTP Code: 200
Failed Response (Not Found):
HTTP Code: 404
"Not Found"
POST /db/some-db
Create new record inside some-db
.
If the data sent does not have an id property, the system will generate one for you.
Request:
$ curl -X POST -H "Authorization:Bearer ieiLHIvNCVne3CY2EiDWK089lWo6QuU3" \ -d "name=Bread" \ http://localhost:8080/db/some-db
Success Response:
HTTP Code: 201
PUT /db/some-db/some-id
Updates a record in some-db
by some-id
.
Request:
$ curl -X PUT -H "Authorization:Bearer ieiLHIvNCVne3CY2EiDWK089lWo6QuU3" \ -d "name=Fish" \ http://localhost:8080/db/some-db/a92981dd-395e-488f-97a0-43398e6b0c61
Success Response:
HTTP Code: 200
Failed Response (Not Found):
HTTP Code: 404
"Not Found"
DELETE /db/some-db/some-id
Deletes a record in some-db
by some-id
.
Request:
$ curl -X DELETE -H "Authorization:Bearer ieiLHIvNCVne3CY2EiDWK089lWo6QuU3" \ http://localhost:8080/db/some-db/a92981dd-395e-488f-97a0-43398e6b0c61
Success Response:
HTTP Code: 200
"OK"
Failed Response (Not Found):
HTTP Code: 404
"Not Found"
POST /db/some-db/broadcast
Broadcasts a message to all clients connected to some-db
Request:
$ curl -X POST -H "Authorization:Bearer ieiLHIvNCVne3CY2EiDWK089lWo6QuU3" \ -d "payload=Hello!" \ http://localhost:8080/db/testendpoint
Success Response:
HTTP Code: 200
"OK"
Failed Response (Missing Payload Parameter):
HTTP Code: 400
"Bad Request"
Testing
$ npm test CastMyData Tests ✓ should be able to get root ✓ should deny api request without auth token ✓ should be able to create a new record ✓ should be able list all records ✓ should be able to get a record by id ✓ should be able to update a record by id ✓ should be able to delete a record by id ✓ should be able to clear db ✓ should be able to broadcast data ✓ should be able to subscribe ✓ should be able to listen to a channel ✓ should be able to send broadcasts ✓ should be able to unlisten to a channel ✓ should be able to create a record ✓ should be able to find a record by id ✓ should be able to query an endpoint ✓ should be able to update query models when a new record is created ✓ should be able to update a record by id ✓ should be able to delete a record by id ✓ should be able to clear db ✓ should be able to unsubscribe ✓ should be able to close connection 22 passing
License
The MIT License (MIT) Copyright (c) 2016 Zulfa Juniadi bin Zulkifli
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.