Was this page helpful?
In this section, we will walk you through the CarePet commands and explain the code behind them.
As explained in Getting Started with CarePet, the project is structured as follows:
Migrate (/cmd/migrate) - Creates the CarePet keyspace and tables.
Collar (/cmd/sensor) - Simulates a pet’s collar by generating the pet’s health data and pushing the data into the storage.
Server (/cmd/server) - REST API service for tracking the pets’ health state.
The /migrate
command creates the keyspace and tables that will be used by the collar and server services.
Line 25 to 27 in the /cmd/migrate/migrate.go
file call the createKeyspace
, migrateKeyspace
then the printKeyspaceMetadata
functions.
func main() {
/// ...
createKeyspace()
migrateKeyspace()
printKeyspaceMetadata()
}
The createKeyspace
function creates a new session then executes the following CQL query stored in the db.go
file:
CREATE KEYSPACE IF NOT EXISTS carepet WITH replication = { 'class': 'NetworkTopologyStrategy', 'replication_factor': '3' } AND durable_writes = TRUE;
func createKeyspace() {
// Creates a new session
ses, err := config.Session()
if err != nil {
log.Fatalln("session: ", err)
}
defer ses.Close()
// Executes the CREATE KEYSPACE query and checks for errors
if err := ses.Query(db.KeySpaceCQL).Exec(); err != nil {
log.Fatalln("ensure keyspace exists: ", err)
}
}
The migrateKeyspace
function opens a new session with the carepet
keyspace and creates the following tables in the carepet keyspace using the CQL file located in /db/cql/care-pet-ddl.cql
:
owner
pet
sensor
measurement
sensor_avg
func migrateKeyspace() {
// Create a new session with the carepet keyspace
ses, err := config.Keyspace()
if err != nil {
log.Fatalln("session: ", err)
}
defer ses.Close()
// Execute the queries in the migration file om db/cql
if err := migrate.Migrate(context.Background(), ses, "db/cql"); err != nil {
log.Fatalln("migrate: ", err)
}
}
As the name suggests, the printKeyspaceMetadata
function will then print the metadata related to the carepet
keyspace and confirm that the tables were properly created.
The sensor service simulates the collar’s activity. The service uses the pet struct
and its functions defined in sensor/pet.go
to create a new pet
along with an owner
and sensorType
then saves it to the database.
func main() {
/// ...
// Create a new session with carepet keyspace
ses, err := config.Keyspace()
if err != nil {
log.Fatalln("session: ", err)
}
defer ses.Close()
// Generate new pet
pet := NewPet()
// Save new pet to the database
if err := pet.save(context.Background(), ses); err != nil {
log.Fatalln("pet save: ", err)
}
log.Println("New owner #", pet.p.OwnerID)
log.Println("New pet #", pet.p.PetID)
pet.run(context.Background(), ses)
}
The server service is a REST API for tracking the pets’ health state. The service allows users to query the database via http.
In the care-pet example, you will use $ curl http://127.0.0.1:8000/api/owner/{id}
and expect the following response:
[{"address":"home","age":57,"name":"tlmodylu","owner_id":"a05fd0df-0f97-4eec-a211-cad28a6e5360","pet_id":"a52adc4e-7cf4-47ca-b561-3ceec9382917","weight":5}]
Let’s first discuss the code from line 23 to 28 in server/main.go
.
func main() {
// ...
api := operations.NewCarePetAPI(spec())
server := restapi.NewServer(api)
defer server.Shutdown()
configure(server)
server.ConfigureAPI()
// ...
}
The api
object represent a list of functions and codes generated by the swagger tool. Those operations are then passed to the NewServer method to configure the API and handler methods:
// ConfigureAPI configures the API and handlers.
func (s *Server) ConfigureAPI() {
if s.api != nil {
s.handler = configureAPI(s.api)
}
}
One example of a handler method is the FindOwnerByID
in handler/owner.go
.
func FindOwnerByID(ses gocqlx.Session) operations.FindOwnerByIDHandlerFunc {
return func(params operations.FindOwnerByIDParams) middleware.Responder {
var owner model.Owner
if err := db.TableOwner.GetQuery(ses).Bind(params.ID.String()).GetRelease(&owner); err == gocql.ErrNotFound {
// Returns FindOwnerByIDDefault with with status code 404
return operations.NewFindOwnerByIDDefault(http.StatusNotFound)
} else if err != nil {
log.Println("find owner by id query: ", err)
// Returns FindOwnerByIDDefault with with status code 500
return operations.NewFindOwnerByIDDefault(http.StatusInternalServerError)
}
// Return status 200 and owner information
return &operations.FindOwnerByIDOK{Payload: &models.Owner{
Address: owner.Address,
Name: owner.Name,
OwnerID: conv.UUID(strfmt.UUID(owner.OwnerID.String())),
}}
}
}
Line 25 queries the owner
table then saves the result in the owner object or throws a not found 404 status error.
Line 32 returns a FindOwnerByIDOK object with code status 200 and the owner’s information.
Was this page helpful?