Claude-skill-registry grpc-patterns

gRPC service implementation patterns. Use when building gRPC services.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/grpc-patterns" ~/.claude/skills/majiayu000-claude-skill-registry-grpc-patterns && rm -rf "$T"
manifest: skills/data/grpc-patterns/SKILL.md
source content

gRPC Patterns Skill

gRPC service implementation for Go.

When to Use

Use when building gRPC services.

Protocol Buffer Definition

syntax = "proto3";

package user.v1;

option go_package = "github.com/user/project/proto/user/v1;userv1";

service UserService {
  rpc GetUser(GetUserRequest) returns (User);
  rpc ListUsers(ListUsersRequest) returns (stream User);
  rpc CreateUser(CreateUserRequest) returns (User);
}

message GetUserRequest {
  int32 id = 1;
}

message User {
  int32 id = 1;
  string name = 2;
  string email = 3;
}

message ListUsersRequest {
  int32 page_size = 1;
  string page_token = 2;
}

message CreateUserRequest {
  string name = 1;
  string email = 2;
}

Service Implementation

type server struct {
    userv1.UnimplementedUserServiceServer
    service *Service
}

func (s *server) GetUser(ctx context.Context, req *userv1.GetUserRequest) (*userv1.User, error) {
    user, err := s.service.GetUser(ctx, int(req.Id))
    if err != nil {
        return nil, status.Errorf(codes.NotFound, "user not found: %v", err)
    }

    return &userv1.User{
        Id:    int32(user.ID),
        Name:  user.Name,
        Email: user.Email,
    }, nil
}

func (s *server) ListUsers(req *userv1.ListUsersRequest, stream userv1.UserService_ListUsersServer) error {
    users, err := s.service.ListUsers(stream.Context(), int(req.PageSize))
    if err != nil {
        return status.Errorf(codes.Internal, "failed to list users: %v", err)
    }

    for _, user := range users {
        if err := stream.Send(&userv1.User{
            Id:    int32(user.ID),
            Name:  user.Name,
            Email: user.Email,
        }); err != nil {
            return err
        }
    }

    return nil
}

Server Setup

func main() {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }

    s := grpc.NewServer(
        grpc.UnaryInterceptor(loggingInterceptor),
    )

    userv1.RegisterUserServiceServer(s, &server{
        service: NewService(),
    })

    log.Println("Server listening on :50051")
    if err := s.Serve(lis); err != nil {
        log.Fatalf("failed to serve: %v", err)
    }
}

Interceptors (Middleware)

func loggingInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    start := time.Now()
    resp, err := handler(ctx, req)
    log.Printf("method=%s duration=%v error=%v", info.FullMethod, time.Since(start), err)
    return resp, err
}

Client Usage

conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

client := userv1.NewUserServiceClient(conn)

user, err := client.GetUser(context.Background(), &userv1.GetUserRequest{Id: 1})
if err != nil {
    log.Fatal(err)
}
fmt.Println(user)

Best Practices

  • Use proper error codes (codes.NotFound, codes.InvalidArgument)
  • Implement interceptors for cross-cutting concerns
  • Use streaming for large datasets
  • Set timeouts on client calls
  • Handle metadata for auth
  • Implement health checks