Hi there,
Did you read my latest implementation of PostgreSQL with GoLang? PostgresWithGo If you said of course :) go head... Do you know have any knowledge about Cassandra? Don't worry neither am I've not. I like to share about the subjects I work on. So be relax. Are you curious about NOSQl and GoLang? In this post I'll share my Cassandra Db and GoLang knowledge. You'll ask these questions ask yourself, What is Cassandra Db then how to install Cassandra DB to your local machine, which package should I use for it. All of these are in here.
Step 1 : What is Cassandra DB
Step 2 : How to install it
Step 3 : Important commands
Step 4 : Connect to database
Step 5 : Implementation
Step 6 : Postman Tests
Let's go to work and I hope you'll enjoy it.
Step 1: What is Cassandra DB
NoSQL databases are called “Not Only SQL” or “Non-relational” databases. NoSQL databases store and retrieve data other than tabular relations such as relation databases.
Elastic scalability − Cassandra is highly scalable; it allows to add more hardware to accommodate more customers and more data as per requirement.
Always on architecture − Cassandra has no single point of failure and it is continuously available for business-critical applications that cannot afford a failure.
Fast linear-scale performance − Cassandra is linearly scalable, i.e., it increases your throughput as you increase the number of nodes in the cluster. Therefore it maintains a quick response time.
Flexible data storage − Cassandra accommodates all possible data formats including: structured, semi-structured, and unstructured. It can dynamically accommodate changes to your data structures according to your need.
Easy data distribution − Cassandra provides the flexibility to distribute data where you need by replicating data across multiple data centers.
Transaction support − Cassandra supports properties like Atomicity, Consistency, Isolation, and Durability (ACID).
Fast writes − Cassandra was designed to run on cheap commodity hardware. It performs blazingly fast writes and can store hundreds of terabytes of data, without sacrificing the read efficiency.
Data Types
Step 2: How to install
I'm using mac os. I've already installed Docker application on my machine. So may be you want to install only docker container. Install Docker
docker pull cassandra
docker run -d --name cassandra -p 9042:9042 cassandra
In this repository I created docker-compose.yml file that file contains with required images.
cassandra:
image: cassandra:latest
container_name: cassandra
ports:
- 7000:7000
- 7001:7001
- 7199:7199
- 9042:9042
- 9160:9160
restart: always
environment:
- CASSANDRA_BROADCAST_ADDRESS=host.docker.internal
- CASSANDRA_SEEDS=host.docker.internal
volumes:
- ./out/cassandra_data:/var/lib/cassandra
healthcheck:
test: ["CMD", "cqlsh", "-u cassandra", "-p cassandra" ,"-e describe keyspaces"]
interval: 15s
timeout: 10s
retries: 10
- 7199 - JMX (was 8080 pre Cassandra 0.8.xx)
- 7000 - Internode communication (not used if TLS enabled)
- 7001 - TLS Internode communication (used if TLS enabled)
- 9160 - Thrift client API
- 9042 - CQL native transport port
Step 3: Important Commands
After the installation since I want to create a database, I have to run this command. What is cqlsh? It is the interface. cqlsh is a command-line interface for interacting with Cassandra using CQL (the Cassandra Query Language). Documentation
docker exec -it cassandra cqlsh
Let's create a todo table.
Step 4: Connect to database
Install the VSCode extension for Cassandra.
Step 5 : Implementation
Project structure:
--> cmd
--> api(main.go) this file deal with read config.yml file
--> util(config.go & errors.go) config.go is related with application configurations, errors.go is a custom response implementation.
--> pkg
--> api (api.go) this file integrated to initialize
func Initialize(config utils.Configuration) {
// Creates a gin router with default middleware:
router := gin.Default()
fmt.Printf("%+v\n", config)
//register database ,repositories and handlers
session := cassandra.ConnectDatabase(config.Database.Url, config.Database.Keyspace)
repository := db.NewTodoRepository(session)
orderHandler := handler.NewTodoHandler(&repository)
router.GET("/ping", orderHandler.HealthCheck)
router.POST("/", orderHandler.CreateTodo)
router.GET("api/v1/todo/:id", orderHandler.GetTodoById)
//run the server :8080
router.Run(":8080")
}
--> client/cassandra
The ConnectDatabase function take 2 parameters from api.go file. After creation that function response session. This session
func ConnectDatabase(url string, keyspace string) *gocql.Session {
cluster := gocql.NewCluster(url)
cluster.Keyspace = keyspace
cluster.Consistency = gocql.Quorum
session, _ := cluster.CreateSession()
return session
}
Click fn+12 CreateSession
// CreateSession initializes the cluster based on this config and returns a
// session object that can be used to interact with the database.
func (cfg *ClusterConfig) CreateSession() (*Session, error) {
return NewSession(*cfg)
}
-->handler
TodoHandler related with request database and response JSON data also error handling is done for that level. All function take c *gin.Context parameter also these functions has receiver function (t *todoHandler) which means that you can access the repository with t.Save or t.GetById.
func (t *todoHandler) CreateTodo(c *gin.Context) {
var todo model.Todo
c.BindJSON(&todo)
todo.Id = uuid.New().String()
log.Info("Data is ", todo)
data, err := t.repo.Save(todo)
if err != nil {
c.JSON(http.StatusBadRequest, utils.BadRequestError("insert operation failed!", err))
}
c.JSON(http.StatusCreated, gin.H{"todo": data})
}
func (t *todoHandler) GetTodoById(c *gin.Context) {
id := c.Param("id")
todo, err := t.repo.GetById(id)
if err != nil {
c.JSON(http.StatusBadRequest, utils.BadRequestError("todo not found", err))
}
c.JSON(http.StatusOK, gin.H{"todo": todo})
}
GIN : c.JSON(http.StatusOK, gin.H{"todo": todo})
Echo: return c.JSON(http.StatusOK, data)
// JSON serializes the given struct as JSON into the response body.
// It also sets the Content-Type as "application/json".
func (c *Context) JSON(code int, obj interface{}) {
c.Render(code, render.JSON{Data: obj})
}
Binding JSON data in GIN
// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).
func (c *Context) BindJSON(obj interface{}) error {
return c.MustBindWith(obj, binding.JSON)
}
In repository layer has "github.com/gocql/gocql" package that's is related the queries and executions. Cassandra DB queries similar to PostgreSQL, MsSQL or MySQL queries.
func (t *todoRepository) Save(todo model.Todo) (*model.Todo, error) {
var query string = "INSERT INTO todo(id,title,content) VALUES(?,?,?)"
if err := t.session.Query(query, todo.Id, todo.Title, todo.Content).Exec(); err != nil {
return nil, err
}
return &todo, nil
}
func (t *todoRepository) GetById(id string) (*model.Todo, error) {
var todo model.Todo
var query string = `SELECT id,title,content FROM todo where id=?`
if err := t.session.Query(query, id).Scan(&todo.Id, &todo.Title, &todo.Content); err != nil {
if err == gocql.ErrNotFound {
return nil, err
}
return nil, err
}
return &todo, nil
}
Now Let's run the docker-compose file. Cassandra DB has own health check configuration.
docker-compose up
healthcheck:
test: ["CMD", "cqlsh", "-u cassandra", "-p cassandra" ,"-e describe keyspaces"]
interval: 15s
timeout: 10s
retries: 10
When database is running you can see the status is health
Step 6: Postman Test
- run the program
References
Thank you.
Top comments (1)
Thank you for this great post !! Cassandra is hot.
An improvement idea. In the first figure when you describe Cassandra I do not think the "schemaless" statement is true. As Cassandra is using tables with strong validation we cannot really say "schemaless".
Cheers !