The purpose of this sample application is to show that Aerospike APIs on top of a key-value store are an effective way to write applications with Aerospike as the only database. To demonstrate, this sample app describes the design and implementation of a "twitter-like" application called Tweetaspike.
The code is easy to follow and substantial enough to be a foundation in learning how to leverage Aerospike's technology and it can also be used as a "seed" application that you can expand.
This application is built using -- Aerospike + Express + Angular + Node -- ASEAN (/a-shawn/) Stack :)
- Register | Login | Logout
- Tweet — post new tweets
- Follow — follow other users
- Unfollow — unfollow users you are following
- Following — list of users you follow including their posts
- Followers — list of users that follow you including their posts
- Alerts — real-time alerts when users you are following add new posts
- Aerospike Server
- Aerospike Node.js Client
- OS:
- CentOS/RHEL 6.x, Debian 6+, Ubuntu 12.04, Ubuntu 14.04, Mac OS X (IMP: Aerospike Node.js Client currently does not have support for Windows)
- Mac OS X:
- 10.8 or greater
- Xcode 5 or greater
- Xcode Dev Tools
- Aerospike Server – To install the latest version, click here. The server should be running and accessible from this app.
- Node.js – To install latest stable version, click here
Note: To easily manage your existing Node.js installations and switch between versions, use version manager such as nvm. To install nvm, visit https://www.npmjs.com/package/nvm. Once installed, you can install different versions of Node.js using command nvm install version or switch to a different version that you already have installed using command nvm use version
Even though this is a pretty lightweight application, I’ve used different technologies to make it decent enough – visually & functionally – and covering all aspects as well as walking through the entire codebase is beyond the scope of this README. So, good understanding and working knowledge of the following technologies is presumed.
- Node.js
- AngularJS
- Express
- Socket.io
- Angular UI
To build the application and resolve dependencies, run command sudo npm update from the application root folder.
In aerospike_config.js, update aerospikeCluster and aerospikeClusterPort such that it points to your instance running Aerospike Server.
To run the application, run command node server from the application root folder.
You should see message Connection to Aerospike cluster succeeded!
If you see Connection to Aerospike cluster failed!, please make sure your instance of Aerospike Server is running and available. Also confirm that aerospikeCluster and aerospikeClusterPort are set correctly as described above in the Config section.
If all is well, open web browser and point it to: http://localhost:9000
In a different terminal window, browse to the application root folder. Then run command grunt — and keep it running while you are updating app.scss or main.scss. This will compile your updates in .scss files and generate respective .css files in real-time.
Stores one user record per User.
Key: uid
Bins:
- uid - String
- username - String
- password - String
- auth - String
- tweetCount - Integer
Sample Record:
{ ns: 'test', set: 'users', key: 'dash' }
{ uid: 'dash',
username: 'dash',
password: 'dash',
auth: 'c18d1b9a-19fb-4b2b-b4d3-560c8af07ef6',
tweetCount: 3 }
Note: For simplicity, password is stored in plain-text
Stores one tweet record per Tweet.
Key: uid:tweetcount
Bins:
- key - String
- username - String
- tweet - String
- ts - Integer
Sample Record:
{ ns: 'test', set: 'tweets', key: 'dash:0' }
{ key: 'dash:0',
username: 'dash',
tweet: 'Put.a.Bird.On.It',
ts: 1427945664001 }
Note: Key for Tweet record includes tweet counter so you can use Aerospike's Batch operation to retrieve all tweets for a given user with one API call.
Stores one tweet record per User.
Key: uid
Bin:
- tweets - Map
Sample Record:
{ ns: 'test', set: 'tweets', key: 'dash' }
{ 1428433280390: 'hello budapest!',
1428433295094: 'good morning to you all!' }
Note: tweets Map entries would contain key-value pairs; where key is the timestamp and value is the tweet.
Stores one record per User.
Key: uid
Bin:
- followers - Array of Strings
Sample Record:
{ ns: 'test', set: 'followers', key: 'dash’ }
{ followers:
[ 'joe',
'jane',
'moe',
'homer',
'peter'] }
Stores one record per User.
Key: uid
Bin:
- following - Array of Objects
Sample Record:
{ ns: 'test', set: 'following', key: 'dash' }
{ following:
[ { tweets: [], handle: 'claire' },
{ tweets: [], handle: 'brandon' },
{ tweets: [], handle: 'donovan' },
{ tweets: [], handle: 'mary' },
{ tweets: [], handle: 'mike' },
{ tweets: [], handle: 'eva' },
{ tweets: [], handle: 'mark' }] }
Note: The empty tweets array gets populated on-demand in the client when user clicks / wants to see the tweets for a given user.
- Enforces unique usernames
- Requires username and password
- Creates User record
- Check if User record with username key exists
* If it does not exist, username entered is invalid
* If it exists, check if entered password matches the User record
- If it does not, password entered is invalid
- If passwords match:
- Store auth in HTML5 Web/Local Storage
- This value is used to check if user is logged in when browsing to various pages within the app. If this value is not found, user is routed back to Login
- This value is cleared when user Logs out
- Log user in
- Store auth in HTML5 Web/Local Storage
- Increments tweet count (tweetCount) by 1 in the User record
- Adds new Tweet record with key <uid>:<tweetCount>
- Adds new object (tweets/posts array and handle of user-to-follow) to array of objects stored and accessed via uid key for the current user
- Retrieves followers (array accessed via uid key) of user-to-follow user and adds current user as a follower
- Removes object (tweets/posts array and handle of user-to-unfollow) from array of objects stored and accessed via uid key for the current user
- Retrieves followers (array accessed via uid key) of user-to-unfollow user and removes current user as a follower
- Shows a list of users that current user is following
- On initial load, only the list of
following
users is retrieved using uid key - The tweets/posts of
following
users are retrieved on-demand when user clicks on their row
- Shows a list of users that are following current user
- On initial load, only the list of
followers
users is retrieved using uid key - The tweets/posts of
followers
users are retrieved on-demand when user clicks on their row
- The technology used in this app to deliver real-time alerts is Socket.io
- The app is setup to listen for
tweet
event -- which is triggered when a new tweet/post gets added by a user. The object sent as a message to Socket.io client emit API looks like{uid: uid, tweet: tweetText}
- Upon receiving a
tweet
event it then gets emitted out (in our case as abroadcast
event) to the connected clients along with data object{uid: uid, tweet: tweetText}
it received - Individual clients are setup to listen on
socket:broadcast
event emitted as described above -- here the listener loops through users that the current user is following and if one of the users’ uid matches that of the data object it received{uid: uid, tweet: tweetText}
, an alert is displayed
- Clears out auth stored in HTML5 Web/Local Storage and routes the user back to Login