Build an Astrology App with Go & Vedika API

Build an Astrology App with Go and Vedika API
Published: March 13, 2026 | By Vedika Intelligence | Reading time: 12 minutes

Go is the language of choice for high-performance backend services. Its goroutine-based concurrency model, static binary output, and compile-time type safety make it ideal for astrology microservices that must handle thousands of birth chart requests with low latency and zero runtime surprises.

In this tutorial you will build a production-ready Go service that integrates Vedika API — the only B2B astrology API with an AI-powered natural language engine, 140+ endpoints, and Swiss Ephemeris astronomical precision. By the end you will have a working CLI tool and an HTTP REST wrapper, both using idiomatic Go patterns.

What You'll Build: A Go module with typed structs for birth chart requests and responses, an http.Client wrapper around Vedika API, concurrent multi-query execution via goroutines, a CLI tool for quick lookups, and an HTTP server that exposes astrology endpoints to other services.

Why Go for Astrology Services?

Goroutine Concurrency

Fan out birth chart, dasha, transit, and compatibility queries simultaneously. Collect all results in the time of the slowest single call.

Static Binary

Deploy a single binary with zero runtime dependencies. No Node, no Python, no JVM. Perfect for containers and bare-metal servers.

Compile-Time Safety

Typed structs catch JSON schema mismatches at build time, not in production at 3 AM when a user gets a wrong prediction.

Low Memory Footprint

Go services typically use 10-30 MB RAM versus 200-500 MB for equivalent Node.js services. Critical when running astrology workers at scale.

Prerequisites

Step 1: Initialize the Go Module

Create a new directory and initialize your module:

# Create and enter project directory mkdir vedika-go-client cd vedika-go-client # Initialize Go module go mod init github.com/yourusername/vedika-go-client

Your go.mod file will look like this. The standard library covers everything we need — no third-party HTTP or JSON libraries required:

// go.mod module github.com/yourusername/vedika-go-client go 1.21

Step 2: Define Typed Structs

Create types.go with structs that mirror Vedika API's request and response schemas. Proper typing eliminates entire classes of runtime errors:

// types.go package main // BirthDetails represents a person's birth information type BirthDetails struct { Datetime string `json:"datetime"` // ISO 8601: "1990-06-15T14:30:00+05:30" Latitude float64 `json:"latitude"` // Decimal degrees: 18.9388 Longitude float64 `json:"longitude"` // Decimal degrees: 72.8354 Timezone string `json:"timezone"` // UTC offset: "+05:30" } // AstrologyQueryRequest is sent to the AI natural language endpoint type AstrologyQueryRequest struct { Question string `json:"question"` BirthDetails BirthDetails `json:"birthDetails"` Language string `json:"language,omitempty"` System string `json:"system,omitempty"` // "vedic", "western", "kp" } // VedikaQueryResponse holds the AI answer and metadata type VedikaQueryResponse struct { Answer string `json:"answer"` Tokens int `json:"tokens"` System string `json:"system"` CachedResult bool `json:"cachedResult"` } // BirthChartRequest is sent to the V2 birth chart endpoint type BirthChartRequest struct { Datetime string `json:"datetime"` Latitude float64 `json:"latitude"` Longitude float64 `json:"longitude"` Timezone string `json:"timezone"` Ayanamsa string `json:"ayanamsa,omitempty"` // "lahiri" (default) } // PlanetPosition holds a single planet's computed data type PlanetPosition struct { Name string `json:"name"` Sign string `json:"sign"` Degree float64 `json:"degree"` House int `json:"house"` Retrograde bool `json:"retrograde"` Dignity string `json:"dignity"` } // BirthChartResponse holds the full chart computation type BirthChartResponse struct { Ascendant string `json:"ascendant"` MoonSign string `json:"moonSign"` SunSign string `json:"sunSign"` Planets []PlanetPosition `json:"planets"` ActiveYogas []string `json:"activeYogas"` CurrentDasha struct { Mahadasha string `json:"mahadasha"` Antardasha string `json:"antardasha"` EndsAt string `json:"endsAt"` } `json:"currentDasha"` } // APIError represents an error response from Vedika API type APIError struct { StatusCode int Message string } func (e *APIError) Error() string { return fmt.Sprintf("vedika api error %d: %s", e.StatusCode, e.Message) }

Step 3: Build the API Client

Create client.go — a reusable client with a configured http.Client, base URL, and API key. This pattern makes testing and mocking straightforward:

// client.go package main import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "time" ) const ( defaultBaseURL = "https://api.vedika.io" defaultTimeout = 30 * time.Second ) // VedikaClient wraps the Vedika API with typed methods type VedikaClient struct { apiKey string baseURL string httpClient *http.Client } // NewVedikaClient creates a new client with sensible defaults func NewVedikaClient(apiKey string) *VedikaClient { return &VedikaClient{ apiKey: apiKey, baseURL: defaultBaseURL, httpClient: &http.Client{ Timeout: defaultTimeout, }, } } // post sends a POST request and decodes the JSON response into dest func (c *VedikaClient) post(ctx context.Context, path string, body, dest interface{}) error { payload, err := json.Marshal(body) if err != nil { return fmt.Errorf("marshal request: %w", err) } req, err := http.NewRequestWithContext( ctx, http.MethodPost, c.baseURL+path, bytes.NewReader(payload), ) if err != nil { return fmt.Errorf("create request: %w", err) } req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+c.apiKey) resp, err := c.httpClient.Do(req) if err != nil { return fmt.Errorf("execute request: %w", err) } defer resp.Body.Close() bodyBytes, _ := io.ReadAll(resp.Body) if resp.StatusCode >= 400 { return &APIError{ StatusCode: resp.StatusCode, Message: string(bodyBytes), } } if err := json.Unmarshal(bodyBytes, dest); err != nil { return fmt.Errorf("decode response: %w", err) } return nil } // QueryAI sends a natural language question about a birth chart func (c *VedikaClient) QueryAI(ctx context.Context, req AstrologyQueryRequest) (*VedikaQueryResponse, error) { var result VedikaQueryResponse if err := c.post(ctx, "/api/v1/astrology/query", req, &result); err != nil { return nil, err } return &result, nil } // GetBirthChart fetches a computed Vedic birth chart func (c *VedikaClient) GetBirthChart(ctx context.Context, req BirthChartRequest) (*BirthChartResponse, error) { var result BirthChartResponse if err := c.post(ctx, "/v2/astrology/birth-chart", req, &result); err != nil { return nil, err } return &result, nil }

Step 4: Concurrent Queries with Goroutines

Go's goroutines let you fan out multiple Vedika API calls in parallel. Instead of waiting sequentially for birth chart, dasha periods, and transits (which could take 3× the latency), you get all three in the time of the slowest single call:

// concurrent.go package main import ( "context" "sync" ) // AstrologyProfile aggregates results from concurrent API calls type AstrologyProfile struct { BirthChart *BirthChartResponse CareerQuery *VedikaQueryResponse LoveQuery *VedikaQueryResponse Errors []error } // FetchProfile fetches birth chart + AI predictions concurrently func FetchProfile(ctx context.Context, client *VedikaClient, bd BirthDetails) AstrologyProfile { var ( wg sync.WaitGroup mu sync.Mutex profile AstrologyProfile ) addErr := func(err error) { mu.Lock() profile.Errors = append(profile.Errors, err) mu.Unlock() } // Goroutine 1: Fetch birth chart wg.Add(1) go func() { defer wg.Done() chart, err := client.GetBirthChart(ctx, BirthChartRequest{ Datetime: bd.Datetime, Latitude: bd.Latitude, Longitude: bd.Longitude, Timezone: bd.Timezone, }) if err != nil { addErr(err) return } mu.Lock() profile.BirthChart = chart mu.Unlock() }() // Goroutine 2: Career prediction via AI wg.Add(1) go func() { defer wg.Done() resp, err := client.QueryAI(ctx, AstrologyQueryRequest{ Question: "What are my career prospects for 2026?", BirthDetails: bd, }) if err != nil { addErr(err) return } mu.Lock() profile.CareerQuery = resp mu.Unlock() }() // Goroutine 3: Relationship prediction via AI wg.Add(1) go func() { defer wg.Done() resp, err := client.QueryAI(ctx, AstrologyQueryRequest{ Question: "What does my 7th house indicate about marriage timing?", BirthDetails: bd, }) if err != nil { addErr(err) return } mu.Lock() profile.LoveQuery = resp mu.Unlock() }() wg.Wait() return profile }

Step 5: Build a CLI Tool

Create main.go with a CLI interface using standard library flags. This lets astrologers or developers query Vedika API from the terminal without writing any code:

// main.go package main import ( "context" "flag" "fmt" "log" "os" "time" ) func main() { var ( apiKey = flag.String("key", "", "Vedika API key (or set VEDIKA_API_KEY env var)") datetime = flag.String("datetime", "", "Birth datetime (ISO 8601, e.g. 1990-06-15T14:30:00+05:30)") lat = flag.Float64("lat", 0, "Birth latitude (decimal degrees)") lon = flag.Float64("lon", 0, "Birth longitude (decimal degrees)") tz = flag.String("tz", "+05:30", "Timezone offset (default: +05:30 IST)") question = flag.String("q", "", "Question to ask (AI natural language mode)") concurrent = flag.Bool("concurrent", false, "Fetch full profile concurrently") ) flag.Parse() // API key: flag takes priority, then environment variable key := *apiKey if key == "" { key = os.Getenv("VEDIKA_API_KEY") } if key == "" { log.Fatal("API key required: use -key flag or VEDIKA_API_KEY env var") } if *datetime == "" || *lat == 0 || *lon == 0 { log.Fatal("Birth details required: -datetime, -lat, -lon") } client := NewVedikaClient(key) ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second) defer cancel() bd := BirthDetails{ Datetime: *datetime, Latitude: *lat, Longitude: *lon, Timezone: *tz, } if *concurrent { fmt.Println("Fetching full astrological profile (concurrent)...") profile := FetchProfile(ctx, client, bd) if profile.BirthChart != nil { fmt.Printf("\n=== Birth Chart ===\nAscendant: %s | Moon: %s | Sun: %s\n", profile.BirthChart.Ascendant, profile.BirthChart.MoonSign, profile.BirthChart.SunSign, ) fmt.Printf("Active Yogas: %v\n", profile.BirthChart.ActiveYogas) fmt.Printf("Current Dasha: %s / %s (ends %s)\n", profile.BirthChart.CurrentDasha.Mahadasha, profile.BirthChart.CurrentDasha.Antardasha, profile.BirthChart.CurrentDasha.EndsAt, ) } if profile.CareerQuery != nil { fmt.Printf("\n=== Career Prediction ===\n%s\n", profile.CareerQuery.Answer) } if profile.LoveQuery != nil { fmt.Printf("\n=== Relationship Prediction ===\n%s\n", profile.LoveQuery.Answer) } for _, err := range profile.Errors { fmt.Fprintf(os.Stderr, "warning: %v\n", err) } return } if *question != "" { resp, err := client.QueryAI(ctx, AstrologyQueryRequest{ Question: *question, BirthDetails: bd, }) if err != nil { log.Fatalf("AI query failed: %v", err) } fmt.Println(resp.Answer) return } // Default: fetch birth chart chart, err := client.GetBirthChart(ctx, BirthChartRequest{ Datetime: bd.Datetime, Latitude: bd.Latitude, Longitude: bd.Longitude, Timezone: bd.Timezone, }) if err != nil { log.Fatalf("Birth chart failed: %v", err) } fmt.Printf("Ascendant: %s\nMoon Sign: %s\nSun Sign: %s\n", chart.Ascendant, chart.MoonSign, chart.SunSign) fmt.Printf("Planets:\n") for _, p := range chart.Planets { retroStr := "" if p.Retrograde { retroStr = " (R)" } fmt.Printf(" %-10s %s%s, House %d, %.2f°, %s\n", p.Name, p.Sign, retroStr, p.House, p.Degree, p.Dignity) } }

Running the CLI

# Build the binary go build -o vedika-cli . # Ask an AI question VEDIKA_API_KEY=vk_live_xxx ./vedika-cli \ -datetime "1990-06-15T14:30:00+05:30" \ -lat 18.9388 -lon 72.8354 \ -q "What does my current Mahadasha indicate for business?" # Fetch full birth chart VEDIKA_API_KEY=vk_live_xxx ./vedika-cli \ -datetime "1990-06-15T14:30:00+05:30" \ -lat 18.9388 -lon 72.8354 # Concurrent full profile (birth chart + career + love predictions) VEDIKA_API_KEY=vk_live_xxx ./vedika-cli \ -datetime "1990-06-15T14:30:00+05:30" \ -lat 18.9388 -lon 72.8354 \ -concurrent

Step 6: Build an HTTP REST Wrapper

Expose Vedika API to your internal services through a typed Go HTTP server. This pattern is common in microservice architectures where you want a single access point with auth, logging, and retry logic:

// server.go package main import ( "encoding/json" "log" "net/http" "os" ) // writeJSON encodes v as JSON and writes it to w func writeJSON(w http.ResponseWriter, status int, v interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(v) } func startServer() { client := NewVedikaClient(os.Getenv("VEDIKA_API_KEY")) // POST /chart — returns full birth chart http.HandleFunc("/chart", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "POST only"}) return } var req BirthChartRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) return } chart, err := client.GetBirthChart(r.Context(), req) if err != nil { writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, chart) }) // POST /query — AI natural language endpoint http.HandleFunc("/query", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "POST only"}) return } var req AstrologyQueryRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) return } resp, err := client.QueryAI(r.Context(), req) if err != nil { writeJSON(w, http.StatusBadGateway, map[string]string{"error": err.Error()}) return } writeJSON(w, http.StatusOK, resp) }) // POST /profile — concurrent full profile http.HandleFunc("/profile", func(w http.ResponseWriter, r *http.Request) { var bd BirthDetails if err := json.NewDecoder(r.Body).Decode(&bd); err != nil { writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) return } profile := FetchProfile(r.Context(), client, bd) writeJSON(w, http.StatusOK, profile) }) log.Println("Vedika Go wrapper listening on :8080") log.Fatal(http.ListenAndServe(":8080", nil)) }

Testing the REST Wrapper

# Start the server VEDIKA_API_KEY=vk_live_xxx go run . # Test birth chart endpoint curl -X POST http://localhost:8080/chart \ -H "Content-Type: application/json" \ -d '{ "datetime": "1990-06-15T14:30:00+05:30", "latitude": 18.9388, "longitude": 72.8354, "timezone": "+05:30" }' # Test AI query endpoint curl -X POST http://localhost:8080/query \ -H "Content-Type: application/json" \ -d '{ "question": "What career path suits me best?", "birthDetails": { "datetime": "1990-06-15T14:30:00+05:30", "latitude": 18.9388, "longitude": 72.8354, "timezone": "+05:30" } }'

Production Best Practices

Context-Based Timeouts

Always pass a context with a timeout to prevent goroutine leaks when Vedika API is slow or unavailable:

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() resp, err := client.QueryAI(ctx, req) if errors.Is(err, context.DeadlineExceeded) { log.Println("Vedika API timeout — check network or increase timeout") }

Retry with Exponential Backoff

func withRetry(attempts int, fn func() error) error { var err error for i := 0; i < attempts; i++ { if err = fn(); err == nil { return nil } var apiErr *APIError if errors.As(err, &apiErr) && apiErr.StatusCode == 429 { // Rate limited — back off exponentially wait := time.Duration(1<Sleep(wait) continue } return err // Non-retryable error } return err }

Environment-Based Configuration

# Production: set via environment variable or GCP Secret Manager export VEDIKA_API_KEY="vk_live_your_key_here" # Never hardcode keys in source code # Never commit .env files containing API keys

Why Vedika API Beats Competitors for Go Services

140+ Endpoints

Birth charts, planetary positions, yogas, doshas, dashas, transits, panchang, numerology, Shadbala, and much more — all accessible from Go.

AI Natural Language

One endpoint handles any astrology question in plain English. No need to learn 140 calculation APIs individually.

Swiss Ephemeris Precision

Astronomical-grade planetary positions. Same engine used by professional astrology software worldwide.

30 Languages

Hindi, Tamil, Telugu, Gujarati, Bengali, Marathi, Kannada — and 23 more. Build for India's diversity from one API.

MCP Server

World's first astrology MCP server. AI agents can call Vedika natively — no custom integration needed.

Starts at $12/month

No per-endpoint pricing surprises. Wallet-based credits. Starter covers most Go microservice use cases.

Conclusion

Building a Go astrology service with Vedika API is clean and idiomatic. The key advantages:

Next steps:

  1. Get your Vedika API key at vedika.io/signup
  2. Run go mod init and paste the code above into your project
  3. Test with go run . -concurrent -datetime "1990-06-15T14:30:00+05:30" -lat 18.9388 -lon 72.8354
  4. Add your business logic around the typed responses
  5. Deploy the single binary to Cloud Run, GKE, or any Linux server

For full endpoint documentation, sandbox testing, and code samples in 12 languages, visit our developer documentation.


About Vedika Intelligence: Vedika is the only B2B astrology API with an AI-powered chatbot and 140+ calculation endpoints, serving production apps worldwide. Built on Swiss Ephemeris for astronomical precision, supporting Vedic, Western, and KP astrology across 30 languages. The world's first astrology MCP server.

Try the #1 Vedic Astrology API

140+ endpoints, 30 languages, Swiss Ephemeris precision. Free sandbox included — no credit card required.

Get Free API Key