Cassandra Day Chicago 2015: 0 to App Faster with Node.js and Ruby
-
Upload
planet-cassandra -
Category
Technology
-
view
266 -
download
0
Transcript of Cassandra Day Chicago 2015: 0 to App Faster with Node.js and Ruby
The situation
• REST interface to Cassandra data • Support CRUD operations • It’s Friday and…
2
Umm yeah, and I’m going to need that by Monday morning.
DataStax NodeJS driver
• Works with current OSS Cassandra • Apache Licensed
7
https://github.com/datastax/nodejs-driver
Based on node-cassandra-cql by Jorge Bay
DataStax Ruby driver
9
https://github.com/datastax/ruby-driver
• Works with current OSS Cassandra • Apache Licensed
Based on cql-rb by Theo Hultberg (@iconara)
DataStax Cassandra Drivers
• Load Balancing Policies • Retry Policies • Asynchronous • Prepared statements • Connection and cluster management
11
A Cassandra Driver should have…
REST methods
• Operates on the “USERS” table in Cassandra
13
POST Insert a user
GET Select a user
PUT Update a user
DELETE Delete a user
CREATE TABLE users ( firstname text, lastname text, age int, email text, city text, PRIMARY KEY (lastname));
Connection for NodeJS• Express as the web server • body-parser to get POST data
15
var client = new cassandra.Client({ contactPoints: ['127.0.0.1'], keyspace: 'demo', policies: { retry: new cassandra.policies.retry.RetryPolicy(), loadBalancing: new cassandra.policies.loadBalancing.DCAwareRoundRobinPolicy('datacenter1') } });
var express = require('express') var bodyParser = require('body-parser'); var cassandra = require('cassandra-driver');
var client = new cassandra.Client({ contactPoints: ['127.0.0.1'], keyspace: 'demo', policies: { retry: new cassandra.policies.retry.RetryPolicy(), loadBalancing: new cassandra.policies.loadBalancing.DCAwareRoundRobinPolicy('datacenter1') } });
Connection for NodeJS• Express as the web server • body-parser to get POST data
16
var express = require('express') var bodyParser = require('body-parser'); var cassandra = require('cassandra-driver');
var client = new cassandra.Client({ contactPoints: ['127.0.0.1'], keyspace: 'demo', policies: { retry: new cassandra.policies.retry.RetryPolicy(), loadBalancing: new cassandra.policies.loadBalancing.DCAwareRoundRobinPolicy('datacenter1') } });
Connection for NodeJS• Express as the web server • body-parser to get POST data
17
var express = require('express') var bodyParser = require('body-parser'); var cassandra = require('cassandra-driver');
var client = new cassandra.Client({ contactPoints: ['127.0.0.1'], keyspace: 'demo', policies: { retry: new cassandra.policies.retry.RetryPolicy(), loadBalancing: new cassandra.policies.loadBalancing.DCAwareRoundRobinPolicy('datacenter1') } });
Connection for NodeJS• Express as the web server • body-parser to get POST data
18
var express = require('express') var bodyParser = require('body-parser'); var cassandra = require('cassandra-driver');
Load balancing
19
Client 10.0.0.1 00-25
10.0.0.4 76-100
10.0.0.2 26-50
10.0.0.3 51-75
SELECT firstNameFROM usersWHERE lastname = ‘mills’;
datacenter1
datacenter1
Node Primary Replica Replica
10.0.0.1 00-25 76-100 51-75
10.0.0.2 26-50 00-25 76-100
10.0.0.3 51-75 26-50 00-25
10.0.0.4 76-100 51-75 26-50
loadBalancing: new DCAwareRoundRobinPolicy('datacenter1')
Insert a user with a POST
20
app.post('/users', function (req, res) { var lastname = req.body.lastname; var age = req.body.age; var city = req.body.city; var email = req.body.email; var firstname = req.body.firstname; var query = "INSERT INTO users (lastname, age, city, email, firstname) VALUES ( ?,?,?,?,?)"; var params = [lastname, age, city, email, firstname]; client.execute(query, params, {prepare: true}, function (err, result) { if (!err) { res.send("Inserted"); } else { res.sendStatus(404) } })})
Insert a user with a POST
21
app.post('/users', function (req, res) { var lastname = req.body.lastname; var age = req.body.age; var city = req.body.city; var email = req.body.email; var firstname = req.body.firstname; var query = "INSERT INTO users (lastname, age, city, email, firstname) VALUES ( ?,?,?,?,?)"; var params = [lastname, age, city, email, firstname]; client.execute(query, params, {prepare: true}, function (err, result) { if (!err) { res.send("Inserted"); } else { res.sendStatus(404) } })})
Insert a user with a POST
22
app.post('/users', function (req, res) { var lastname = req.body.lastname; var age = req.body.age; var city = req.body.city; var email = req.body.email; var firstname = req.body.firstname; var query = "INSERT INTO users (lastname, age, city, email, firstname) VALUES ( ?,?,?,?,?)"; var params = [lastname, age, city, email, firstname]; client.execute(query, params, {prepare: true}, function (err, result) { if (!err) { res.send("Inserted"); } else { res.sendStatus(404) } })})
Insert a user with a POST
23
app.post('/users', function (req, res) { var lastname = req.body.lastname; var age = req.body.age; var city = req.body.city; var email = req.body.email; var firstname = req.body.firstname; var query = "INSERT INTO users (lastname, age, city, email, firstname) VALUES ( ?,?,?,?,?)"; var params = [lastname, age, city, email, firstname]; client.execute(query, params, {prepare: true}, function (err, result) { if (!err) { res.send("Inserted"); } else { res.sendStatus(404) } })})
Select user with GET
24
app.get('/users/:lastname',function (req, res) { var query = "SELECT lastname, age, city, email, firstname FROM users WHERE lastname= ?"; var params = [req.params.lastname]; client.execute(query, params, {prepare: true}, function (err, result) { if (!err){ if ( result.rows.length > 0 ) { var user = result.rows[0]; console.log("name = %s, age = %d", user.firstname, user.age); res.send(user) } else { res.sendStatus(404); } } }); })
Select user with GET
25
app.get('/users/:lastname',function (req, res) { var query = "SELECT lastname, age, city, email, firstname FROM users WHERE lastname= ?"; var params = [req.params.lastname]; client.execute(query, params, {prepare: true}, function (err, result) { if (!err){ if ( result.rows.length > 0 ) { var user = result.rows[0]; console.log("name = %s, age = %d", user.firstname, user.age); res.send(user) } else { res.sendStatus(404); } } }); })
Select user with GET
26
app.get('/users/:lastname',function (req, res) { var query = "SELECT lastname, age, city, email, firstname FROM users WHERE lastname= ?"; var params = [req.params.lastname]; client.execute(query, params, {prepare: true}, function (err, result) { if (!err){ if ( result.rows.length > 0 ) { var user = result.rows[0]; console.log("name = %s, age = %d", user.firstname, user.age); res.send(user) } else { res.sendStatus(404); } } }); })
Select user with GET
27
app.get('/users/:lastname',function (req, res) { var query = "SELECT lastname, age, city, email, firstname FROM users WHERE lastname= ?"; var params = [req.params.lastname]; client.execute(query, params, {prepare: true}, function (err, result) { if (!err){ if ( result.rows.length > 0 ) { var user = result.rows[0]; console.log("name = %s, age = %d", user.firstname, user.age); res.send(user) } else { res.sendStatus(404); } } }); })
Select user with GET
28
app.get('/users/:lastname',function (req, res) { var query = "SELECT lastname, age, city, email, firstname FROM users WHERE lastname= ?"; var params = [req.params.lastname]; client.execute(query, params, {prepare: true}, function (err, result) { if (!err){ if ( result.rows.length > 0 ) { var user = result.rows[0]; console.log("name = %s, age = %d", user.firstname, user.age); res.send(user) } else { res.sendStatus(404); } } }); })
Update a user with PUT
29
app.put('/users/:lastname', function (req, res) { var age = req.body.age; console.log("lastname = " + req.params.lastname + ", age= " + age); var query = "UPDATE users SET age = ? WHERE lastname = ?"; var params = [age, req.params.lastname]; client.execute(query, params, {prepare: true}, function (err, result) { if (!err) { res.send("Updated"); } else { res.sendStatus(404) } }); })
Remove a user with DELETE
30
app.delete('/users/:lastname', function (req, res) { var query = "DELETE FROM users WHERE lastname = ?"; var params = [req.params.lastname]; client.execute(query, params, {prepare: true}, function (err, result) { if (!err) { res.send("Deleted"); } else { res.sendStatus(404) } }); })
Connection with Ruby
• Sinatra as the web server • JSON for returning formatted results
32
cluster = Cassandra.cluster( :hosts => ['127.0.01'], :load_balancing_policy => Cassandra::LoadBalancing::Policies::RoundRobin.new, :retry_policy => Cassandra::Retry::Policies::Default.new, logger: log) keyspace = 'demo'session = cluster.connect(keyspace)
require 'sinatra'require 'JSON'require 'cassandra'require 'logger'
Connection with Ruby
• Sinatra as the web server • JSON for returning formatted results
33
cluster = Cassandra.cluster( :hosts => ['127.0.01'], :load_balancing_policy => Cassandra::LoadBalancing::Policies::RoundRobin.new, :retry_policy => Cassandra::Retry::Policies::Default.new, logger: log) keyspace = 'demo'session = cluster.connect(keyspace)
require 'sinatra'require 'JSON'require 'cassandra'require 'logger'
Connection with Ruby
• Sinatra as the web server • JSON for returning formatted results
34
cluster = Cassandra.cluster( :hosts => ['127.0.01'], :load_balancing_policy => Cassandra::LoadBalancing::Policies::RoundRobin.new, :retry_policy => Cassandra::Retry::Policies::Default.new, logger: log) keyspace = 'demo'session = cluster.connect(keyspace)
require 'sinatra'require 'JSON'require 'cassandra'require 'logger'
Connection with Ruby
• Sinatra as the web server • JSON for returning formatted results
36
cluster = Cassandra.cluster( :hosts => ['127.0.01'], :load_balancing_policy => Cassandra::LoadBalancing::Policies::RoundRobin.new, :retry_policy => Cassandra::Retry::Policies::Default.new, logger: log) keyspace = 'demo'session = cluster.connect(keyspace)
require 'sinatra'require 'JSON'require 'cassandra'require 'logger'
Insert a user with a POST
37
post '/users' do begin session.execute(userInsertStatement, :arguments => [params[:firstname], params[:lastname], params[:age].to_i, params[:city], params[:email]]) "Inserted" rescue Exception => e log.error 'Error in insert a user' log.error(e) halt(404) endend
userInsertStatement = session.prepare("INSERT INTO users (firstname, lastname, age, city, email) VALUES (?,?,?,?,?)")
Insert a user with a POST
38
post '/users' do begin session.execute(userInsertStatement, :arguments => [params[:firstname], params[:lastname], params[:age].to_i, params[:city], params[:email]]) "Inserted" rescue Exception => e log.error 'Error in insert a user' log.error(e) halt(404) endend
userInsertStatement = session.prepare("INSERT INTO users (firstname, lastname, age, city, email) VALUES (?,?,?,?,?)")
…
Insert a user with a POST
39
post '/users' do begin session.execute(userInsertStatement, :arguments => [params[:firstname], params[:lastname], params[:age].to_i, params[:city], params[:email]]) "Inserted" rescue Exception => e log.error 'Error in insert a user' log.error(e) halt(404) endend
userInsertStatement = session.prepare("INSERT INTO users (firstname, lastname, age, city, email) VALUES (?,?,?,?,?)")
…
Select user with GET
40
get '/users/:lastname' do begin result = session.execute(userSelectStatement, :arguments => [params[:lastname]]) if result.size < 1 halt(404) end result.first.to_json rescue Exception => e log.error 'Error in select a user' log.error(e) halt(404) endend
userSelectStatement = session.prepare("SELECT firstname,lastname, age, email, city FROM users where lastname = ?")
Select user with GET
41
get '/users/:lastname' do begin result = session.execute(userSelectStatement, :arguments => [params[:lastname]]) if result.size < 1 halt(404) end result.first.to_json rescue Exception => e log.error 'Error in select a user' log.error(e) halt(404) endend
userSelectStatement = session.prepare("SELECT firstname,lastname, age, email, city FROM users where lastname = ?") …
Select user with GET
42
get '/users/:lastname' do begin result = session.execute(userSelectStatement, :arguments => [params[:lastname]]) if result.size < 1 halt(404) end result.first.to_json rescue Exception => e log.error 'Error in select a user' log.error(e) halt(404) endend
userSelectStatement = session.prepare("SELECT firstname,lastname, age, email, city FROM users where lastname = ?")
…
Select user with GET
43
get '/users/:lastname' do begin result = session.execute(userSelectStatement, :arguments => [params[:lastname]]) if result.size < 1 halt(404) end result.first.to_json rescue Exception => e log.error 'Error in select a user' log.error(e) halt(404) endend
userSelectStatement = session.prepare("SELECT firstname,lastname, age, email, city FROM users where lastname = ?")
…
Quick note on Async
• Generates a Future • Non-blocking until get
44
future = session.execute_async(statement)# register success listenerfuture.on_success do |rows| rows.each do |row| puts "#{row["artist"]}: #{row["title"]} / #{row["album"]}" endend
Quick note on Async
• Generates a Future • Non-blocking until get
45
future = session.execute_async(statement)# register success listenerfuture.on_success do |rows| rows.each do |row| puts "#{row["artist"]}: #{row["title"]} / #{row["album"]}" endend
Quick note on Async
• Generates a Future • Non-blocking until get
46
future = session.execute_async(statement)# register success listenerfuture.on_success do |rows| rows.each do |row| puts "#{row["artist"]}: #{row["title"]} / #{row["album"]}" endend
Update a user with PUT
47
put '/users' do begin session.execute(userUpdateStatement, :arguments => [params[:age].to_i, params[:lastname]]) "Updated" rescue Exception => e log.error 'Error in update a user' log.error(e) halt(404) endend
userUpdateStatement = session.prepare("UPDATE users SET age = ? WHERE lastname = ?")
Remove a user with DELETE
48
delete '/users/:lastname' do begin session.execute(userDeleteStatement, :arguments => [params[:lastname]]) "Deleted" rescue Exception => e log.error 'Error in delete a user' log.error(e) halt(404) endend
userDeleteStatement = session.prepare("DELETE FROM users WHERE lastname = ?")
Get the code! Try yourself!
50
https://github.com/beccam/rest_server_ruby
https://github.com/beccam/rest_server_nodejs
NodeJS Code
Ruby Code