15 Prompts for Go Development: Microservices, API, and CLI Tools

Go has become the default language for cloud-native infrastructure: Docker, Kubernetes, Terraform, and Prometheus are all written in Go. Yet a lot of Go development still means repeating the same boilerplate—setup handlers, write validation, glue packages together. AI assistants can cut this time significantly, but only if you give them the right context. This article is a curated list of 15 copy-paste-ready prompts for three common Go tasks: microservices, API development, and CLI utilities. Each prompt is designed to produce idiomatic, production-quality code using the standard library and trusted open-source packages.

Why Go is ideal for AI-assisted development

Go's syntax is small and predictable. The standard library is well documented, and the community follows clear patterns: http.Handler, context.Context, error return values, and interface{} for dependency injection. These conventions make it easy for language models to generate correct code. For example, when you specify “use net/http and return errors with fmt.Errorf”, the model understands exactly what you expect.

According to the Go Blog article “Effective Go”, idiomatic Go favors composition and explicit error handling. By including these requirements in your prompts, you’ll get results that integrate seamlessly with existing codebases. The Go documentation on context is another excellent source to mention.

How to get the most from these prompts

  • Always specify the Go version. Models are trained on historical data, so they may use deprecated functions like grpc.Dial or ioutil. Ask for “Go 1.22” to encourage modern APIs.
  • Mention the exact libraries you want. For example, chi vs gorilla/mux vs standard net/http.
  • Request tests. A prompt that asks for a _test.go file will produce more reliable code.
  • Ask for comments. Go developers value clear comments; this also helps you understand the generated code.
Area Prompts Core packages Output
Microservices 1-5 chi, gRPC, middleware Service skeleton, clean architecture
API Development 6-10 validator, Echo REST client, validation, error handling
CLI Utilities 11-15 Cobra, fsnotify CLI commands, progress bars

Microservices

Microservices are the most common production use case for Go. The following five prompts cover the lifecycle of a service: from skeleton to graceful shutdown and middleware.

1. RESTful Service Skeleton

When you need a new HTTP API service, starting from a solid skeleton saves you 30–45 minutes of manual wiring.

Prompt:

Generate a production-ready RESTful microservice in Go using the chi router. It should have a /health endpoint that returns JSON {"status":"ok"} and a /users endpoint with GET and POST handlers. Use in-memory storage with a mutex. Include main.go, go.mod, and a Makefile with run and test targets. Write idiomatic Go code with comments.

What you get: A project structure with main.go that configures http.Server timeouts, a chi router, a userStore struct, and a Makefile. You also get a main_test.go with a simple test for the health endpoint.

// Example generated main.go (excerpt)
func main() {
    r := chi.NewRouter()
    r.Get("/health", healthHandler)
    r.Route("/users", userRouter)
    srv := &http.Server{Addr: ":8080", Handler: r}
    log.Fatal(srv.ListenAndServe())
}

2. gRPC User Service

If you are moving to gRPC or need a reference server/client, this prompt produces both the proto file and the Go implementation.

Prompt:

Write a gRPC server and client in Go for a UserService with methods GetUser and CreateUser. Use google.golang.org/grpc and google.golang.org/protobuf. Provide the user.proto file, generated Go stubs, a server implementation, and a client example that makes a request with context timeout. Use grpc.NewClient and show the deprecated grpc.Dial for comparison.

What you get: A complete user.proto, generated .pb.go files, a server that implements the interface with in-memory storage, and a client that calls GetUser with a context timeout.

// The generated client call
conn, _ := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
client := pb.NewUserServiceClient(conn)
resp, err := client.GetUser(ctx, &pb.GetUserRequest{Id: "123"})

3. Clean Architecture for User Management

When you need to separate business rules from HTTP, clean architecture is the way. This prompt asks the AI to refactor a simple handler into layers.

Prompt:

Refactor the following Go HTTP handler into a clean architecture with repository, service, and handler layers. Use dependency injection with an interface for the repository. Provide handler.go, service.go, repository.go, and main.go that wires them together. The repository should use a map with sync.RWMutex.

func handler(w http.ResponseWriter, r *http.Request) {
    name := r.URL.Query().Get("name")
    fmt.Fprintf(w, "Hello %s", name)
}

What you get: Separate files with clearly defined interfaces. The service layer holds logic, the repository handles data, and the handler only deals with HTTP.

type UserRepository interface {
    GetUser(id string) (*User, error)
}
type UserService struct {
    repo UserRepository
}
func (s *UserService) GetUser(id string) (*User, error) { ... }

4. Graceful Shutdown

Deploying a service without graceful shutdown can lead to dropped requests. Use this prompt to add safe termination.

Prompt:

Generate Go code for graceful HTTP server shutdown with context timeout. Listen on port 8080 and handle SIGINT and SIGTERM signals. Use http.Server with ReadTimeout and WriteTimeout. On signal, call srv.Shutdown(ctx) with a 10-second timeout. Include comments and use log.Printf for lifecycle messages.

What you get: A main.go with a signal-notification channel and a shutdown sequence. The server runs in a goroutine, and the main function blocks until a signal is received.

srv := &http.Server{Addr: ":8080", ReadTimeout: 5 * time.Second}
go func() { log.Fatal(srv.ListenAndServe()) }()
<-sigCh
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
srv.Shutdown(ctx)

5. Middleware Chain

To add logging, recovery, CORS, and request IDs, this prompt composes a standard-library middleware pipeline.

Prompt:

Create a middleware chain for a Go HTTP server using only the standard library. It should include request ID generation, access logging, panic recovery, and CORS headers. Each middleware should be a function with signature func(next http.Handler) http.Handler. Provide a main.go that composes these with http.NewServeMux and a sample handler. Use the context to pass the request ID to the handler.

What you get: Four middleware functions and a main that wires them. The logging middleware prints method, path, status, and duration.

func RequestID(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("X-Request-ID", uuid.NewString())
        next.ServeHTTP(w, r)
    })
}

API Development

REST APIs are the most common Go output. These prompts cover mocking, validation, clients, and error handling.

6. OpenAPI Spec and Go Structs

When you are designing a new API, having a spec and matching Go code prevents drift.

Prompt:

Generate an OpenAPI 3.0 specification for a simple todo application with endpoints: GET /todos, POST /todos, GET /todos/{id}, PUT /todos/{id}, DELETE /todos/{id}. Then generate Go structs and Echo handlers that match the spec. Use the standard time.Time for the due_date field. Include JSON tags that match the property names.

What you get: An openapi.yaml file and a Go file with Todo struct and handlers. The Echo handlers return appropriate HTTP codes.

type Todo struct {
    ID        int       `json:"id"`
    Title     string    `json:"title"`
    DueDate   time.Time `json:"due_date"`
    Completed bool      `json:"completed"`
}

7. Request Validation

If you are tired of hand-writing validation, the validator package does the work for you.

Prompt:

Write Go code for request validation on a JSON API. Use github.com/go-playground/validator/v10 to validate structs and return a formatted 400 response with field errors. Include a Payload struct with Name, Email, and StartDate fields. Register a custom validator for datetime format YYYY-MM-DD. Show an example handler for POST /users.

What you get: A validation function and an HTTP 400 response that lists failed fields.

if err := validate.Struct(payload); err != nil {
    // map validation errors to {"field": "message"}
    http.Error(w, err.Error(), http.StatusBadRequest)
}

8. Typed REST Client (GitHub Example)

To avoid pulling in SDKs for a quick integration, this client uses only net/http.

Prompt:

Generate a typed Go client for the GitHub REST API, using the net/http package only. Implement functions GetUser(username string) and ListRepositories(username string). Handle pagination with the Link header and loop through all pages. Return errors on non-2xx status codes and on rate limit (403). Use the context parameter for cancellation.

What you get: A client.go with User and Repository structs, plus a pagination loop that follows next links.

for {
    resp, err := http.Get(url) // or c.do(req)
    var page []Repository
    json.NewDecoder(resp.Body).Decode(&page)
    repos = append(repos, page...)
    if next := parseLink(resp.Header.Get("Link")); next != "" {
        url = next
    } else { break }
}

9. Pagination, Filtering, and Sorting

When you need to implement list endpoints, consistent query parsing is essential.

Prompt:

Implement pagination, filtering, and sorting for a REST API endpoint in Go. Use query parameters page, page_size, filter, and sort. The filter should support field=value pairs separated by commas (e.g., color=red). Sort should support comma-separated fields with optional minus for descending. Return a JSON object with data, total, and next_page. Provide an example with a Product struct and a handler.

What you get: A listProducts function that processes query strings and returns a paginated response.

{"data": [...], "total": 42, "next_page": 3}

10. Error Handling Pattern with APIError

This prompt gives you a consistent error shape for every API endpoint.

Prompt:

Generate an error handling pattern for a Go REST API with custom error types. Define an APIError struct with Code, Message, and HTTPStatus. Provide a constructor, a WriteError(w, err) helper, and wrap errors from a database layer. Use errors.Is and errors.As to convert database errors into APIError. Show a sample handler that calls WriteError.

What you get: Code mapping sql.ErrNoRows to 404 and returning {"code":"NOT_FOUND", ...}.

type APIError struct {
    Code       string `json:"code"`
    Message    string `json:"message"`
    HTTPStatus int    `json:"-"`
}
func WriteError(w http.ResponseWriter, err error) { ... }

CLI Utilities

Go is the best language for command-line tools: fast, static, and easy to distribute. These prompts cover Cobra, config, JSON processing, file watching, and progress bars.

11. Cobra CLI with Subcommands

When you need a full-featured CLI, Cobra is the de-facto standard.

Prompt:

Create a CLI application in Go using github.com/spf13/cobra with three commands: serve, scan, and version. The serve command starts an HTTP server on port 8080. The scan command takes a directory path and prints all files. The version command prints the version. Add a --verbose flag to the root command and make it inherited by subcommands. Provide main.go and root.go.

What you get: A working Cobra setup with rootCmd, subcommands, and flag inheritance.

var rootCmd = &cobra.Command{
    Use:   "tool",
    Short: "A small CLI tool",
}
func init() {
    rootCmd.PersistentFlags().BoolP("verbose", "v", false, "verbose output")
}

12. Environment Variable Configuration

Twelve-factor apps read config from environment variables. This prompt generates the boilerplate.

Prompt:

Generate Go code for reading environment variables with defaults and parsing them into a Config struct. Support types string, int, bool, and time.Duration. Use os.Getenv with fallback values. Provide a Load() function that returns a Config and a test using t.Setenv.

What you get: A config.go with a Load() function that uses helper conversions.

type Config struct {
    Port        int           `env:"PORT" default:"8080"`
    Debug       bool          `env:"DEBUG" default:"false"`
    Timeout     time.Duration `env:"TIMEOUT" default:"30s"`
}

13. JSON Processing from stdin

Unix-style piping is a powerful pattern; this prompt builds a little filter.

Prompt:

Write a Go CLI utility that reads JSON lines from stdin, applies a transformation (e.g., convert camelCase keys to snake_case), and writes the result to stdout. Use bufio.NewScanner and encoding/json. Handle both an array of objects and NDJSON (newline-delimited JSON). Use a --pretty flag to indent the output.

What you get: A main.go that transforms JSON on the fly. For example, cat users.json | go run main.go --pretty.

echo '{"firstName":"John"}' | go run main.go
// Output: {"first_name":"John"}

14. File Watcher with fsnotify

When you need to react to file changes, fsnotify is the package to use.

Prompt:

Generate a file-watcher utility in Go using github.com/fsnotify/fsnotify. It should watch a directory and print events for create, write, remove, and rename. Include graceful error handling and allow a command-line flag -dir to specify a directory. Handle event op by name and path. Loop forever until interrupted.

What you get: A program with a select loop that prints events.

select {
case event := <-watcher.Events:
    log.Printf("%s %s", event.Op, event.Name)
case err := <-watcher.Errors:
    log.Println("error:", err)
}

15. Progress Bar for CLI

Long-running downloads and builds need visual feedback. This prompt creates a single-line progress bar.

Prompt:

Implement a progress bar in a Go CLI program. Use a loop that calls a function to update the bar. Output \r to overwrite the line. Show percentage, completed items, total items, and elapsed time. Provide an example with a sleep to simulate work. The progress bar should be a separate function updateProgress(current, total, start).

What you get: A function that formats and prints a progress bar.

func updateProgress(current, total int, start time.Time) {
fmt.Printf("\r%3d%%

|%s>%s| %d/%d %s",
        pct, strings.Repeat("#", n), strings.Repeat(" ", m), current, total, elapsed)
}

Testing and validating generated code

AI-generated Go code may contain small mistakes. Before merging, always run:

go run .       # compile and run
go vet .       # static analysis
go test ./...  # execute tests

You can also add the prompt: “Include a unit test with table-driven cases in _test.go.” This is a simple addition that significantly improves reliability.

Summary

These 15 prompts cover the most common Go development tasks. They are not magic: they are the result of knowing the ecosystem and asking for the right idioms. The Go documentation (Effective Go, the Go Blog, and package docs) is the best source of truth. When in doubt, include a link to a specific doc in your prompt—many models will use it to improve the answer. Now, go copy, paste, and generate.

← All posts

Comments