Integrate Astrology API with Java Spring Boot

Integrate Astrology API with Java Spring Boot
Published: March 13, 2026 | By Vedika Intelligence | Reading time: 15 minutes

Java remains the language of choice for enterprise backends — and for good reason. Type safety, mature tooling, the Spring ecosystem, and decades of production-proven patterns make it the dominant platform for fintech, matrimony platforms, media companies, and enterprise SaaS. If you're building an astrology feature into an existing Java application, or starting a new astrology microservice from scratch, this guide shows you exactly how to integrate Vedika API using Spring Boot 3.x best practices.

By the end of this tutorial, you'll have a fully functional Spring Boot service with WebClient reactive calls, DTOs, service layer, Spring Cache for cost optimization, @ControllerAdvice error handling, and @Async parallel processing — all production-ready.

What You'll Build: A Spring Boot 3.x microservice that exposes astrology REST endpoints — birth chart, daily horoscope, AI-powered query, and compatibility matching — backed by Vedika API. Includes caching, error handling, async processing, and an application.yml configuration pattern suitable for enterprise deployment.

Why Vedika API for Java Enterprise Applications?

704 Operations

Birth charts, dashas, transits, muhurta, numerology, AI chatbot — all via a single REST API with JSON payloads.

AI-Powered Queries

Natural language endpoint: ask "When is the best time to launch my product?" and get a chart-verified answer.

XALEN Ephemeris Precision

Astronomical-grade planetary calculations. Not a lookup table — real ephemeris math for every request.

$12/month Starting

Starter at $12, Pro at $60, Business at $120, Enterprise at $240. Pay only for what you use with wallet-based billing.

Prerequisites

Step 1: Project Setup with Spring Initializr

Generate a new project at start.spring.io with the following selections, or use this pom.xml:

<!-- pom.xml --> <project> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.3</version> </parent> <groupId>io.vedika</groupId> <artifactId>astrology-service</artifactId> <version>1.0.0</version> <dependencies> <!-- Spring Web + WebClient --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <!-- Spring MVC controllers --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Caffeine cache --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> </dependency> <!-- Validation --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <!-- Lombok for cleaner DTOs --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> </project>

Step 2: Application Configuration

Configure your API key and base URL in application.yml. Never hardcode secrets — use environment variables or Spring Cloud Config in production:

# src/main/resources/application.yml vedika: api: base-url: https://api.vedika.io key: ${VEDIKA_API_KEY} # Set via environment variable spring: cache: type: caffeine caffeine: spec: maximumSize=500,expireAfterWrite=3600s task: execution: pool: core-size: 4 max-size: 16 queue-capacity: 100 thread-name-prefix: vedika-async-

Step 3: DTO Classes

Define strongly-typed DTOs for request and response payloads. Spring Boot's Jackson auto-maps JSON automatically:

// src/main/java/io/vedika/dto/BirthDetailsDto.java package io.vedika.dto; import jakarta.validation.constraints.*; import lombok.*; import com.fasterxml.jackson.annotation.JsonProperty; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class BirthDetailsDto { @NotBlank private String datetime; // ISO-8601: "1990-06-15T14:30:00" @NotNull private Double latitude; @NotNull private Double longitude; @NotBlank private String timezone; // "+05:30" } // src/main/java/io/vedika/dto/AstrologyQueryDto.java @Data @Builder @NoArgsConstructor @AllArgsConstructor public class AstrologyQueryDto { @NotBlank private String question; @Valid private BirthDetailsDto birthDetails; } // src/main/java/io/vedika/dto/AstrologyResponseDto.java @Data @JsonIgnoreProperties(ignoreUnknown = true) public class AstrologyResponseDto { private String answer; private String system; private Map<String, Object> birthChart; private Map<String, Object> usage; }

Step 4: WebClient Configuration Bean

Configure a singleton WebClient bean with proper timeouts, base URL, and the API key header pre-loaded:

// src/main/java/io/vedika/config/VedikaClientConfig.java package io.vedika.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*; import org.springframework.web.reactive.function.client.*; import io.netty.channel.ChannelOption; import reactor.netty.http.client.HttpClient; import java.time.Duration; @Configuration @EnableCaching @EnableAsync public class VedikaClientConfig { @Value("${vedika.api.key}") private String apiKey; @Value("${vedika.api.base-url}") private String baseUrl; @Bean public WebClient vedikaWebClient() { HttpClient httpClient = HttpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) .responseTimeout(Duration.ofSeconds(60)); return WebClient.builder() .baseUrl(baseUrl) .clientConnector(new ReactorClientHttpConnector(httpClient)) .defaultHeader("x-api-key", apiKey) .defaultHeader("Content-Type", "application/json") .defaultHeader("Accept", "application/json") .build(); } }

Step 5: Astrology Service Layer

Build the service class that wraps all Vedika API interactions. Use @Cacheable on deterministic endpoints — the same birth data always produces the same chart, so caching eliminates redundant API costs:

// src/main/java/io/vedika/service/AstrologyService.java package io.vedika.service; import io.vedika.dto.*; import org.springframework.cache.annotation.Cacheable; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import java.util.concurrent.CompletableFuture; @Service public class AstrologyService { private final WebClient webClient; public AstrologyService(WebClient vedikaWebClient) { this.webClient = vedikaWebClient; } /** * Get AI-powered answer for any astrology question. * Birth chart data is verified against XALEN Ephemeris before the AI response. */ @Cacheable(value = "birthCharts", key = "#request.birthDetails.datetime + #request.birthDetails.latitude + #request.birthDetails.longitude") public AstrologyResponseDto query(AstrologyQueryDto request) { return webClient.post() .uri("/api/vedika/chat") .bodyValue(request) .retrieve() .onStatus(status -> status.is4xxClientError(), resp -> resp.bodyToMono(String.class) .map(body -> new VedikaApiException("Client error: " + body))) .onStatus(status -> status.is5xxServerError(), resp -> resp.bodyToMono(String.class) .map(body -> new VedikaApiException("Server error: " + body))) .bodyToMono(AstrologyResponseDto.class) .block(); } /** * Get birth chart — fully deterministic, aggressive caching is safe. */ @Cacheable(value = "birthCharts", key = "'chart:' + #details.datetime + ':' + #details.latitude + ':' + #details.longitude") public AstrologyResponseDto getBirthChart(BirthDetailsDto details) { AstrologyQueryDto request = AstrologyQueryDto.builder() .question("Generate my complete Vedic birth chart with planetary positions, houses, and active yogas.") .birthDetails(details) .build(); return query(request); } /** * Async batch method — generate horoscopes for multiple users in parallel. * Useful for overnight batch jobs sending daily horoscope notifications. */ @Async("taskExecutor") public CompletableFuture<AstrologyResponseDto> getDailyHoroscopeAsync( BirthDetailsDto details, String zodiacSign) { AstrologyQueryDto request = AstrologyQueryDto.builder() .question("What is today's detailed horoscope for " + zodiacSign + "? Include career, relationships, health, and finance predictions.") .birthDetails(details) .build(); AstrologyResponseDto result = query(request); return CompletableFuture.completedFuture(result); } /** * Kundali compatibility — no caching (pair-specific, less repetitive). */ public AstrologyResponseDto getCompatibility( BirthDetailsDto person1, BirthDetailsDto person2) { AstrologyQueryDto request = AstrologyQueryDto.builder() .question("Calculate the kundali matching score (Guna Milan) between these two birth charts. " + "Provide the Ashtakoot score and compatibility assessment.") .birthDetails(person1) .build(); return query(request); } }

Step 6: REST Controller

Expose clean REST endpoints that your frontend or other microservices can call. The controller stays thin — all business logic lives in the service layer:

// src/main/java/io/vedika/controller/AstrologyController.java package io.vedika.controller; import io.vedika.dto.*; import io.vedika.service.AstrologyService; import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.concurrent.CompletableFuture; @RestController @RequestMapping("/api/astrology") public class AstrologyController { private final AstrologyService astrologyService; public AstrologyController(AstrologyService astrologyService) { this.astrologyService = astrologyService; } /** POST /api/astrology/query — Ask any astrology question in natural language */ @PostMapping("/query") public ResponseEntity<AstrologyResponseDto> query( @Valid @RequestBody AstrologyQueryDto request) { AstrologyResponseDto response = astrologyService.query(request); return ResponseEntity.ok(response); } /** POST /api/astrology/birth-chart — Get complete Vedic birth chart */ @PostMapping("/birth-chart") public ResponseEntity<AstrologyResponseDto> birthChart( @Valid @RequestBody BirthDetailsDto details) { AstrologyResponseDto response = astrologyService.getBirthChart(details); return ResponseEntity.ok(response); } /** POST /api/astrology/daily-horoscope — Async daily prediction */ @PostMapping("/daily-horoscope") public CompletableFuture<ResponseEntity<AstrologyResponseDto>> dailyHoroscope( @Valid @RequestBody BirthDetailsDto details, @RequestParam String zodiacSign) { return astrologyService .getDailyHoroscopeAsync(details, zodiacSign) .thenApply(ResponseEntity::ok); } /** POST /api/astrology/compatibility — Kundali matching */ @PostMapping("/compatibility") public ResponseEntity<AstrologyResponseDto> compatibility( @Valid @RequestBody CompatibilityRequestDto request) { AstrologyResponseDto response = astrologyService .getCompatibility(request.getPerson1(), request.getPerson2()); return ResponseEntity.ok(response); } }

Step 7: Global Error Handling with @ControllerAdvice

Centralize error handling so your controllers stay clean. Map Vedika API errors to appropriate HTTP status codes with descriptive messages:

// src/main/java/io/vedika/exception/GlobalExceptionHandler.java package io.vedika.exception; import org.springframework.http.*; import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.MethodArgumentNotValidException; import java.util.Map; @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(VedikaApiException.class) public ResponseEntity<Map<String, Object>> handleVedikaError(VedikaApiException ex) { HttpStatus status = ex.getStatusCode() == 402 ? HttpStatus.PAYMENT_REQUIRED : ex.getStatusCode() == 429 ? HttpStatus.TOO_MANY_REQUESTS : HttpStatus.BAD_GATEWAY; return ResponseEntity.status(status).body(Map.of( "error", ex.getMessage(), "code", status.value(), "source", "vedika-api" )); } @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, Object>> handleValidation( MethodArgumentNotValidException ex) { String message = ex.getBindingResult() .getFieldErrors() .stream() .map(fe -> fe.getField() + ": " + fe.getDefaultMessage()) .findFirst() .orElse("Validation failed"); return ResponseEntity.badRequest().body(Map.of( "error", message, "code", 400 )); } @ExceptionHandler(Exception.class) public ResponseEntity<Map<String, Object>> handleGeneral(Exception ex) { return ResponseEntity.internalServerError().body(Map.of( "error", "An unexpected error occurred", "code", 500 )); } }

Ready to Build Enterprise Astrology Features?

Try the FREE Sandbox — 700+ mock endpoints, no auth required. Production plans from $12/month.

Explore the Sandbox

Step 8: Scheduled Batch Processing

Use Spring's @Scheduled and @Async together to generate daily horoscopes for all users in parallel overnight — dramatically reducing your peak-hour API usage:

// src/main/java/io/vedika/scheduler/DailyHoroscopeScheduler.java package io.vedika.scheduler; import io.vedika.service.*; import org.springframework.scheduling.annotation.*; import org.springframework.stereotype.Component; import java.util.*; import java.util.concurrent.CompletableFuture; @Component public class DailyHoroscopeScheduler { private final AstrologyService astrologyService; private final UserService userService; public DailyHoroscopeScheduler(AstrologyService astrologyService, UserService userService) { this.astrologyService = astrologyService; this.userService = userService; } // Runs daily at 1:00 AM IST (UTC+5:30 = 19:30 UTC previous day) @Scheduled(cron = "0 30 19 * * *", zone = "UTC") public void generateDailyHoroscopes() { List<UserProfile> users = userService.getAllActiveUsers(); // Fan out async calls — up to 16 concurrent (pool max-size in application.yml) List<CompletableFuture<?>> futures = users.stream() .map(user -> astrologyService.getDailyHoroscopeAsync( user.getBirthDetails(), user.getZodiacSign())) .toList(); CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); System.out.println("Generated horoscopes for " + users.size() + " users"); } }

Step 9: Integration Test

Write a Spring Boot integration test to verify your service wires correctly before deploying. Use @SpringBootTest with a mock WebClient for CI environments:

// src/test/java/io/vedika/service/AstrologyServiceTest.java @SpringBootTest class AstrologyServiceTest { @Autowired private AstrologyService astrologyService; @Test void testBirthChartQuery() { BirthDetailsDto details = BirthDetailsDto.builder() .datetime("1990-06-15T14:30:00") .latitude(28.6139) .longitude(77.2090) .timezone("+05:30") .build(); AstrologyResponseDto response = astrologyService.getBirthChart(details); assertNotNull(response); assertNotNull(response.getAnswer()); assertFalse(response.getAnswer().isEmpty()); } @Test void testCachingReducesApiCalls() { BirthDetailsDto details = BirthDetailsDto.builder() .datetime("1985-03-21T08:00:00") .latitude(19.0760).longitude(72.8777) .timezone("+05:30") .build(); // First call hits API, second call hits cache AstrologyResponseDto first = astrologyService.getBirthChart(details); AstrologyResponseDto second = astrologyService.getBirthChart(details); assertEquals(first.getAnswer(), second.getAnswer()); // Verify only 1 API call was made (check cache hit metrics) } }

Sample curl Request

Test your running Spring Boot service directly:

# Test birth chart endpoint curl -X POST http://localhost:8080/api/astrology/birth-chart \ -H "Content-Type: application/json" \ -d '{ "datetime": "1990-06-15T14:30:00", "latitude": 28.6139, "longitude": 77.2090, "timezone": "+05:30" }' # Test natural language query curl -X POST http://localhost:8080/api/astrology/query \ -H "Content-Type: application/json" \ -d '{ "question": "What are my career prospects for 2026?", "birthDetails": { "datetime": "1990-06-15T14:30:00", "latitude": 28.6139, "longitude": 77.2090, "timezone": "+05:30" } }'

Why Choose Vedika API Over Competitors?

AI Chatbot Built-In

No other astrology API includes a natural language AI engine. One endpoint handles any question — no complex orchestration required.

704 Calculations

Birth charts, Vimshottari dasha, ashtakavarga, muhurta, numerology, compatibility, transit analysis — far more than the 50-80 endpoints competitors provide.

MCP Server Support

The native first-party astrology MCP server. Your AI agents can call Vedika directly through the Model Context Protocol — no REST wrappers needed.

30 Languages

Support for Hindi, Tamil, Telugu, Bengali, Gujarati, Marathi, and 24 more languages for truly global astrology applications.

XALEN Ephemeris

Astronomical-grade ephemeris calculations — not lookup tables. Same engine used by professional Vedic astrology software worldwide.

Enterprise-Ready

99.9% uptime SLA, dual-region deployment (US + Mumbai), rate limiting, secure API key auth, and comprehensive monitoring.

Pricing

Vedika API uses wallet-based billing starting at $12/month — pay only for queries you actually run:

All plans include access to all 700+ operations, the AI chatbot, and 30-language support. Compare plans in detail.

Conclusion

Integrating Vedika API into a Java Spring Boot application follows standard enterprise patterns — no exotic dependencies or special adapters required. The key architectural decisions made in this guide:

Next steps:

  1. Get your API key at vedika.io/dashboard
  2. Try the free sandbox — 700+ mock endpoints, no auth, no cost
  3. Review the full API reference for all 700+ operations
  4. Add Resilience4j circuit breaker for production-grade fault tolerance
  5. Set up Spring Actuator metrics to monitor cache hit rates and API latency

About Vedika Intelligence: Vedika is the only B2B astrology API with an AI-powered chatbot engine, serving production enterprise applications worldwide. The Vedika Intelligence Engine enables natural language astrology queries with XALEN Ephemeris-verified precision, supporting both Vedic and Western astrology across 30 languages.

Try the #1 Astrology API for Java Developers

700+ operations, XALEN Ephemeris precision, AI chatbot, 30 languages. Free sandbox included — no signup required.

Try Free Sandbox View Documentation