# Build an IoT App with Go

## Introduction

In this section, we will walk you through the CarePet commands and explain the code behind them.

As explained in [Getting Started with CarePet](https://iot.scylladb.com/stable/getting-started.md), 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.

## Migrate

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.

```default
func main() {
	
	/// ...

	createKeyspace()
	migrateKeyspace()
	printKeyspaceMetadata()
}
```

The `createKeyspace` function creates a new session then executes the following CQL query stored in the  `db.go` file:

```default
CREATE KEYSPACE IF NOT EXISTS carepet;
```

The CQL query above creates a new keyspace named carepet using the default replication strategy. This syntax requires ScyllaDB 2026.1 or later.

```default
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`

```default
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.

## Sensor

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.

```default
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)
}
```

## Server

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:

```default
[{"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`.

```default
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:

```default
// 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`.

```default
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.

## Resources

* [ScyllaDB Go driver on Github](https://github.com/scylladb/gocql)
* [Go and ScyllaDB on ScyllaDB University](https://university.scylladb.com/courses/the-mutant-monitoring-system-training-course/lessons/golang-and-scylla-part-1/)
* [Scylla Go driver documentation page](https://docs.scylladb.com/stable/using-scylla/drivers/cql-drivers/scylla-go-driver.html)
