---
title: B. Validation
---

## Validating Twirp Input

Our standard layout for validation in a Twirp Handler is as follows:

```go
func (s *Server) GetItem(ctx context.Context, req *rpc.GetItemRequest) (*rpc.GetItemResponse, error) {
    if err := s.validateGetItemRequest(req); err != nil {
        return nil, err
    }

    // ... rest of handler code here
}

func (s *Server) validateGetItemRequest(req *rpc.GetItemRequest) error {
    if req == nil {
        return twirp.RequiredArgumentError("body")
    }
    if req.GetItemId() == "" {
        return twirp.RequiredArgumentError("item_id")
    }
    return nil
}
```
This separates the basic input validation from the main business logic. You should then follow up with a
validation-specific table-driven test for the method:

```go
func TestGetItem_Validation(t *testing.T) {
    testCases := []struct{
        name string
        argument string
        req *rpc.GetItemRequest
    }{
        {
            name: "nil request",
            argument: "body",
            req: nil,
        },
        {
            name: "empty item id",
            argument: "item_id",
            req: &rpc.GetItemRequest{ ItemId: "" },
        },
    }

    for _, tt := range testCases {
        t.Run(tt.name, func(t *testing.T) {
            s := setupTest(t)
            _, err := s.server.GetItem(context.Background(), tt.req)
            require.Error(t, err)
            twErr, ok := err.(twirp.Error)
            require.True(t, ok)
            require.Equal(t, twirp.InvalidArgument, twErr.Code())
        })
    }
}
```