In this video, we are going to be looking at the concept of error handling and defining error responses within our gRPC microservice.
We’ll take a look at how we can define errors and the various codes we can return so that we can help our downstream client applications when an error does occur.
Updating the AddRocket gRPC Handler
Let’s add some validation within the AddRocket gRPC handler method that will validate an incoming UUID within the Rocket object:
if _, err := uuid.Parse(req.Rocket.Id); err != nil {
errorStatus := status.Error(codes.InvalidArgument, "uuid is not valid")
log.Print("given uuid is not valid")
return &rkt.AddRocketResponse{}, errorStatus
}
Acceptance Tests
With this in place, let’s now add a new acceptance test which validates that whenever we hit the endpoint with an invalid UUID it will return the appropriate error message:
// +acceptance
package test
import (
"context"
"testing"
"github.com/TutorialEdge/tutorial-protos/rocket/v1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type RocketTestSuite struct {
suite.Suite
}
func (s *RocketTestSuite) TestAddRocket() {
s.T().Run("adds a new rocket successfully", func(t *testing.T) {
client := GetClient()
resp, err := client.AddRocket(
context.Background(),
&rocket.AddRocketRequest{
Rocket: &rocket.Rocket{
Id: "ae7b0bf0-fe75-4176-b20a-3ca1371f3226",
Name: "V1",
Type: "Falcon Heavy",
},
},
)
assert.NoError(s.T(), err)
assert.Equal(s.T(), "ae7b0bf0-fe75-4176-b20a-3ca1371f3226", resp.Rocket.Id)
})
s.T().Run("validates the uuid in the new rocket is a uuid", func(t *testing.T) {
client := GetClient()
_, err := client.AddRocket(
context.Background(),
&rocket.AddRocketRequest{
Rocket: &rocket.Rocket{
Id: "not-a-valid-uuid",
Name: "V1",
Type: "Falcon Heavy",
},
},
)
assert.Error(s.T(), err)
st := status.Convert(err)
assert.Equal(s.T(), codes.InvalidArgument, st.Code())
})
}
func TestRocketService(t *testing.T) {
suite.Run(t, new(RocketTestSuite))
}
Running Our Tests
In one terminal, let’s kick off our gRPC microservice and the postgres container using docker-compose
:
$ docker-compose up --build
Next, let’s run our acceptance tests and hit our endpoints with the improved validation:
$ go test ./test -tags=acceptance -v
=== RUN TestRocketService
=== RUN TestRocketService/TestAddRocket
=== RUN TestRocketService/TestAddRocket/adds_a_new_rocket_successfully
=== RUN TestRocketService/TestAddRocket/validates_the_uuid_in_the_new_rocket_is_a_uuid
--- PASS: TestRocketService (0.02s)
--- PASS: TestRocketService/TestAddRocket (0.02s)
--- PASS: TestRocketService/TestAddRocket/adds_a_new_rocket_successfully (0.01s)
--- PASS: TestRocketService/TestAddRocket/validates_the_uuid_in_the_new_rocket_is_a_uuid (0.01s)
PASS
ok github.com/TutorialEdge/go-grpc-services-course/test 0.234s
Awesome, we now have the first of our acceptance tests up and running for our gRPC microservice.