go-api-boot

Production-Ready Go API Framework

Featured in Awesome GoProduction ReadyZero Config

Batteries‑included Go framework for building production‑grade gRPC + HTTP APIs – with generics, MongoDB ODM, cloud utilities, zero‑config HTTPS, Temporal workers, and a one‑line bootstrap CLI.

Overview

go‑api‑boot eliminates the repetitive plumbing required to ship modern API services in Go. With a single CLI command you get:

  • A fully wired gRPC server that also serves gRPC‑Web and REST gateways – no Envoy sidecars or extra proxies.
  • Temporal workflow support for long-running background jobs.
  • Generic ODM for MongoDB with multi‑tenant support.
  • Opinionated middlewares (JWT auth, logging, panic recovery) that you can opt out of per‑method.
  • A relocatable cloud toolkit (Azure / GCP) for signed URLs, blob storage, secret resolution, etc.
  • Zero-configuration HTTPS – serve valid TLS certificates on day 0.
  • Built-In Dependency injection wiring customized for gRpc services, temporal workers, config, mongo client, and cloud abstractions.

The result: you write business logic, not boilerplate.

Key Features

🚀 gRPC & gRPC‑Web

First‑class gRPC & gRPC‑Web – serve browsers natively without Envoy.

🗄️ Generic ODM for MongoDB

Type‑safe generic multi-tenant Object Model with async helpers.

🔍 Vector & Text Search

Built‑in support for Atlas Vector Search and Atlas Search.

🔐 JWT Auth & Middleware

Observability, logging, panic recovery pre‑wired.

☁️ Cloud Providers

Interchangeable Azure / GCP helpers for storage & secrets.

🔒 Zero‑Config SSL

Automatic Let's Encrypt certificates with exponential back‑off.

⏰ Temporal Workflow Support

Run long-lived, fault-tolerant background jobs with native Temporal integration.

🔧 Bootstrap CLI

Scaffold full service, models, repos, services, Dockerfile, build scripts.

Quick Start

Bootstrap a New Service

# Install the CLI once
$ go install github.com/SaiNageswarS/go-api-boot/cmd/go-api-boot@latest

# Scaffold a new service in ./quizService
$ go-api-boot bootstrap github.com/yourname/quizService proto

Generated layout:

quizService/
├── cmd/...           # main.go and build scripts
├── db/              # repositories
├── generated/       # proto stubs (via build script)
├── services/        # business logic
├── Dockerfile       # multistage build
└── config.ini       # config

Running Locally

# Generate proto code & build binary
$ ./build.sh

# Export secrets (or use .env / Azure Key Vault)
$ export MONGO_URI=mongodb://localhost:27017
$ export ACCESS_SECRET=supersecret
$ export DOMAIN=api.example.com       # required for SSL
# (optional) use cloud cache for certs
$ export SSL_BUCKET=my-cert-bucket    # bucket / container name

# Start the server – gRPC :50051, HTTP :8081 (HTTPS if --ssl)
$ ./build/quizService

Core Modules

Server

// main.go
package main

func main() {
    // Load secrets and config
    dotenv.LoadEnv()

    // load config file
    var ccfg *config.AppConfig 
    config.LoadConfig("config.ini", ccfg) // loads [dev] or [prod] section based on env var - `ENV=dev` or `ENV=prod`

    mongo, _ := odm.GetClient()
    // Pick a cloud provider – all implement cloud.Cloud
    cloudFns := cloud.ProvideAzure(ccfg) // or cloud.ProvideGCP(cfg)
    // load secrets from Keyvault/SecretManader
    cloudFns.LoadSecretsIntoEnv(context.Background())

    boot, _ := server.New().
        GRPCPort(":50051").        // or ":0" for dynamic
        HTTPPort(":8080").
        EnableSSL(server.CloudCacheProvider(cfg, cloudFns)).
        // Dependency injection
        Provide(cfg).
        Provide(mongo).
        ProvideAs(cloudFns, (*cloud.Cloud)(nil)).
        // Register gRPC service impls
        RegisterService(server.Adapt(pb.RegisterLoginServer), ProvideLoginService).
        Build()

    ctx, cancel := context.WithCancel(context.Background())
    // catch SIGINT ‑> cancel
    _ = boot.Serve(ctx)
}

gRPC, gRPC‑Web, and optional REST gateway on the same port. Middleware registry (unary + stream) to plug in OpenTelemetry, Prometheus, etc.

ODM (MongoDB)

Generic CRUD

// Model
type Profile struct {
    ID    string `bson:"_id"`
    Name  string `bson:"name"`
}
func (p Profile) Id() string { return p.ID }
func (p Profile) CollectionName() string { return "profile" }

// Query
client, err := odm.GetClient(ccfg)
profile, err := async.Await(odm.CollectionOf[Profile](client, tenant).FindOneById(context.Background(), id))

Additionally use helpers like HashedKey to generate _id, NewModelFrom[T any](proto interface) to copy values from proto to the model.

Creating & Ensuring Indexes

// In your setup code
if err := odm.EnsureIndexes[Profile](ctx, mongoClient, tenant); err != nil {
  log.Fatalf("failed to ensure indexes: %v", err)
}

This idempotent helper safely creates all indexes advertised by your models:

  • Implement Indexed for classic indexes.
  • Implement SearchIndexed for text search (TermSearchIndexSpec).
  • Implement VectorIndexed for vector search (VectorIndexSpec).

Vector Search

type Article struct {
    ID        string      `bson:"_id"`
    Title     string      `bson:"title"`
    Content   string      `bson:"content"`
    Embedding bson.Vector `bson:"embedding"` // 768-dim vector
}

func (a Article) Id() string { return a.ID }
func (a Article) CollectionName() string { return "articles" }

// Specify vector index on field "embedding"
func (m Article) VectorIndexSpecs() []odm.VectorIndexSpec {
  return []odm.VectorIndexSpec{{
    Name: "contentVecIdx", Path: "embedding", Type: "vector", NumDimensions: 768,
    Similarity: "cosine",
  }}
}
embedding := getEmbedding(...) // []float32
params := odm.VectorSearchParams{
  IndexName:     "contentVecIdx",
  Path:          "embedding",
  K:             5,
  NumCandidates: 20,
}
results, _ := async.Await(repo.VectorSearch(ctx, embedding, params))
for _, hit := range results {
  fmt.Println(hit.Doc, hit.Score)
}

Text Search

type Article struct {
    ID        string      `bson:"_id"`
    Title     string      `bson:"title"`
    Content   string      `bson:"content"`
    Embedding bson.Vector `bson:"embedding"` // 768-dim vector
}

func (a Article) Id() string { return a.ID }
func (a Article) CollectionName() string { return "articles" }

// Specify term index on field "content" and "title".
func (m Article) TermSearchIndexSpecs() []odm.TermSearchIndexSpec {
  return []odm.TermSearchIndexSpec{{
    Name: "contentTextIdx", Paths: []string {"content", "title"},
  }}
}
params := odm.TermSearchParams{
  IndexName: "contentTextIdx",
  Path:      []string {"content", "title"},
  Limit:     10,
}
results, _ := async.Await(repo.TermSearch(ctx, "golang guides", params))
for _, hit := range results {
  fmt.Println(hit.Doc, hit.Score)
}

Auth & JWT

func (s *LoginService) AuthFuncOverride(ctx context.Context, method string) (context.Context, error) {
    return ctx, nil // public endpoint
}

HS256 by default – override via env vars or secrets manager. Skip auth per‑method.

Cloud Abstractions

var cloudFns cloud.Cloud = cloud.ProvideAzure(ccfg)
filePath, err := cloudFns.DownloadFile(context, bucket, key)

Switch provider with one line – signatures stay identical. Cloud access Secrets such as ClientId, TenantId, ClientSecret for Azure or ServiceAccount.json for GCP are loaded from environment variables.

Zero‑Config SSL/TLS

boot, _ := server.New().
    GRPCPort(":50051").HTTPPort(":8080").
    EnableSSL(server.DirCache("certs"))  // local cache
    Build()

There are two ways to persist the Let's Encrypt certificates:

  • Local autocert.DirCache("certs") – good for single-node dev / on-prem.
  • Distributed cache with SslCloudCache – perfect for Docker / Kubernetes where the container filesystem is ephemeral.

ACME challenge handled internally, exponential back‑off for cloud IP propagation. Just expose port 80 and 443 in your container spec.

Temporal Workers

import (
    "github.com/SaiNageswarS/go-api-boot/server"
    "go.temporal.io/sdk/client"
    "go.temporal.io/sdk/worker"
)

boot, _ := server.New().
    GRPCPort(":50051").
    HTTPPort(":8080").
    WithTemporal("MY_TASK_QUEUE", &client.Options{
        HostPort: "temporal:7233", // or "localhost:7233" if running locally
    }).
    // ProvideIndexerActivities is a function whose dependencies will be injected
    RegisterTemporalActivity(ProvideIndexerActivities).  
    RegisterTemporalWorkflow(IndexPdfFileWorkflow).
    Build()

boot.Serve(context.Background())

go-api-boot provides first-class support for running Temporal workers alongside your gRPC/HTTP services using the same dependency injection system.

CLI Reference

CommandDescription
bootstrap <modulePath> <protoDir>Scaffold a new project
repository <ModelName>Generate model + repository in `db/`
service <ServiceName>Generate skeleton gRPC service

Run with -h for full flags.

Examples

🏥 Medicine RAG

A retrieval-augmented generation full-stack application for doctors

View on GitHub →

🤖 Agent Boot

AI agent framework

View on GitHub →

🔐 Kotlang/authGo

Real‑world auth service

View on GitHub →

Contributing

PRs and issues are welcome!

  1. Fork ➡️ hack ➡️ PR.
  2. Run make test lint – zero lint errors.
  3. Add unit / integration tests for new features.

License

Apache‑2.0 – see LICENSE for details.