The document discusses using NodeJS and Ruby to build a REST API that interacts with a Cassandra database. It provides code examples for connecting to Cassandra using the DataStax drivers for NodeJS and Ruby, and implementing CRUD operations on a "users" table. For NodeJS, it shows setting up an Express server and executing queries using the Cassandra driver. For Ruby, it shows using Sinatra and executing queries via the Ruby driver session. The document also covers topics like load balancing, retry policies, and prepared statements when interacting with Cassandra.
Dev Dives: Streamline document processing with UiPath Studio Web
NodeJS and Ruby to App faster with Cassandra
1. 0 to App faster with NodeJS and Ruby
Rebecca Mills @RebccaMills
Patrick McFadin @PatrickMcFadin
2. 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.
3. Choose your language
• Support for all Cassandra features
• Easy to work with
• Performant
3
7. 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
11. DataStax Cassandra Drivers
• Load Balancing Policies
• Retry Policies
• Asynchronous
• Prepared statements
• Connection and cluster management
11
A Cassandra Driver should have…
12. On to the code!
• RESTful web server
• Need a few helpers
12
+ +
13. 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)
);
15. 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');
16. 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');
17. 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');
18. 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');
20. 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)
}
})
})
21. 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)
}
})
})
22. 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)
}
})
})
23. 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)
}
})
})
24. 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);
}
}
});
})
25. 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);
}
}
});
})
26. 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);
}
}
});
})
27. 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);
}
}
});
})
28. 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);
}
}
});
})
29. 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)
}
});
})
30. 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)
}
});
})
32. 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'
33. 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'
34. 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'
35. Retry Policies
• Retry requests on server errors
• Write Timeout
• Read Timeout
• Unavailable
35
36. 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'
37. 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)
end
end
userInsertStatement = session.prepare("INSERT INTO users (firstname, lastname, age, city, email)
VALUES (?,?,?,?,?)")
38. 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)
end
end
userInsertStatement = session.prepare("INSERT INTO users (firstname, lastname, age, city, email)
VALUES (?,?,?,?,?)")
…
39. 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)
end
end
userInsertStatement = session.prepare("INSERT INTO users (firstname, lastname, age, city, email)
VALUES (?,?,?,?,?)")
…
40. 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)
end
end
userSelectStatement = session.prepare("SELECT firstname,lastname, age, email, city
FROM users where lastname = ?")
41. 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)
end
end
userSelectStatement = session.prepare("SELECT firstname,lastname, age, email, city
FROM users where lastname = ?")…
42. 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)
end
end
userSelectStatement = session.prepare("SELECT firstname,lastname, age, email, city
FROM users where lastname = ?")
…
43. 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)
end
end
userSelectStatement = session.prepare("SELECT firstname,lastname, age, email, city
FROM users where lastname = ?")
…
44. Quick note on Async
• Generates a Future
• Non-blocking until get
44
future = session.execute_async(statement)
# register success listener
future.on_success do |rows|
rows.each do |row|
puts "#{row["artist"]}: #{row["title"]} / #{row["album"]}"
end
end
45. Quick note on Async
• Generates a Future
• Non-blocking until get
45
future = session.execute_async(statement)
# register success listener
future.on_success do |rows|
rows.each do |row|
puts "#{row["artist"]}: #{row["title"]} / #{row["album"]}"
end
end
46. Quick note on Async
• Generates a Future
• Non-blocking until get
46
future = session.execute_async(statement)
# register success listener
future.on_success do |rows|
rows.each do |row|
puts "#{row["artist"]}: #{row["title"]} / #{row["album"]}"
end
end
47. 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)
end
end
userUpdateStatement = session.prepare("UPDATE users SET age = ? WHERE lastname = ?")
48. 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)
end
end
userDeleteStatement = session.prepare("DELETE FROM users WHERE lastname = ?")