Link Client

A CLI-style gRPC client that creates multiple short links, looks them up, and cleans up after itself.

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/status"

	"shortener/pb"
)

func main() {
	conn, err := grpc.NewClient("localhost:50051",
		grpc.WithTransportCredentials(insecure.NewCredentials()),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	client := pb.NewLinkServiceClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	// Shorten a batch of URLs
	urls := []string{
		"https://go.dev/doc/effective_go",
		"https://protobuf.dev/programming-guides/proto3/",
		"https://grpc.io/docs/languages/go/quickstart/",
	}

	var codes_created []string
	fmt.Println("=== Creating links ===")
	for _, url := range urls {
		resp, err := client.CreateLink(ctx, &pb.CreateLinkRequest{Url: url})
		if err != nil {
			log.Fatalf("CreateLink(%s): %v", url, err)
		}
		link := resp.GetLink()
		codes_created = append(codes_created, link.GetShortCode())
		fmt.Printf("  %s -> %s\n", link.GetShortCode(), link.GetUrl())
	}

	// Resolve each short code back to the original URL
	fmt.Println("\n=== Resolving links ===")
	for _, code := range codes_created {
		resp, err := client.GetLink(ctx, &pb.GetLinkRequest{ShortCode: code})
		if err != nil {
			log.Fatalf("GetLink(%s): %v", code, err)
		}
		fmt.Printf("  %s resolves to %s\n", code, resp.GetLink().GetUrl())
	}

	// Delete the first link and verify it's gone
	fmt.Println("\n=== Deleting first link ===")
	_, err = client.DeleteLink(ctx, &pb.DeleteLinkRequest{ShortCode: codes_created[0]})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("  deleted %s\n", codes_created[0])

	_, err = client.GetLink(ctx, &pb.GetLinkRequest{ShortCode: codes_created[0]})
	if err != nil {
		st, _ := status.FromError(err)
		if st.Code() == codes.NotFound {
			fmt.Printf("  confirmed: %s is gone\n", codes_created[0])
		}
	}

	// The other links still work
	fmt.Println("\n=== Remaining links still resolve ===")
	for _, code := range codes_created[1:] {
		resp, err := client.GetLink(ctx, &pb.GetLinkRequest{ShortCode: code})
		if err != nil {
			log.Fatalf("GetLink(%s): %v", code, err)
		}
		fmt.Printf("  %s -> %s\n", code, resp.GetLink().GetUrl())
	}
}

Expected output:

=== Creating links ===
  a3f9wq -> https://go.dev/doc/effective_go
  k7m2px -> https://protobuf.dev/programming-guides/proto3/
  zt04bn -> https://grpc.io/docs/languages/go/quickstart/

=== Resolving links ===
  a3f9wq resolves to https://go.dev/doc/effective_go
  k7m2px resolves to https://protobuf.dev/programming-guides/proto3/
  zt04bn resolves to https://grpc.io/docs/languages/go/quickstart/

=== Deleting first link ===
  deleted a3f9wq
  confirmed: a3f9wq is gone

=== Remaining links still resolve ===
  k7m2px -> https://protobuf.dev/programming-guides/proto3/
  zt04bn -> https://grpc.io/docs/languages/go/quickstart/

Short codes will differ each run (they're randomly generated).

⚠️ Start the link server first (go run .), then run this client (go run ./cmd/client).

💻 Run locally

Copy the code above and run it on your machine

© 2026 ByteLearn.dev. Free courses for developers. · Privacy