DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • From Microservices to Agent Services: The Next Architectural Shift
  • Building an AI-Powered Incident Triage Agent with .NET Aspire
  • Securing AI Agents at the API Layer: 5 Controls That Actually Matter
  • Retrieval Augmented Generation With Spring AI 2.0, Claude, and PGvector

Trending

  • No Observability Tool Is the “Best”
  • Orchestrating Small Language Models Without Losing Events or Context
  • Designing Enterprise-Grade Autonomous Agents With Microsoft Copilot Studio
  • How to Protect Your AI Agents from Prompt Injection Attacks: An Active Defense Approach
  1. DZone
  2. Data Engineering
  3. AI/ML
  4. AI-Powered API Development With Spring AI

AI-Powered API Development With Spring AI

Learn how to build intelligent, production-ready REST APIs using Spring AI, enabling your Spring Boot applications to integrate LLMs.

By 
Muhammed Harris Kodavath user avatar
Muhammed Harris Kodavath
·
Aug. 14, 26 · Analysis
Likes (0)
Comment
Save
Tweet
Share
72 Views

Join the DZone community and get the full member experience.

Join For Free

Artificial intelligence has rapidly become a core capability in modern software development. For Java developers, integrating these capabilities into existing enterprise applications no longer requires learning entirely new frameworks or interacting directly with complex AI APIs. Spring AI bridges this gap by providing a familiar Spring programming model for working with large language models (LLMs) from providers such as OpenAI, Google Gemini, and others.

In this article, we will build a simple AI-powered REST API using Spring Boot and Spring AI while exploring practices that help move beyond proof-of-concept implementations toward production-ready enterprise applications.

A Typical Enterprise Architecture

Rather than allowing clients to communicate directly with an AI provider, enterprise applications usually introduce a service layer responsible for security, validation, business logic, and monitoring.

Plain Text
 
               Client Application
                        │
                        ▼
             Spring Boot REST API
                        │
           Validation & Business Logic
                        │
                        ▼
               Spring AI ChatClient
                        │
                        ▼
             Large Language Model
           (OpenAI / Gemini / Azure)


This architecture keeps AI interactions behind your own APIs, allowing you to enforce authentication, authorization, logging, rate limiting, and governance without exposing provider-specific details to consumers.

Creating the Spring Boot Project

Getting started with Spring AI is straightforward.

The application requires Spring Web, Validation, and the Spring AI starter.

XML
 
<properties>
    <java.version>21</java.version>
    <spring-ai.version>1.0.0</spring-ai.version>
</properties>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>${spring-ai.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>

</dependencies>


Configuring the AI Model

One security practice I strongly recommend is avoiding hard-coded API keys or model names inside the application.

Instead, configure them using environment variables or an enterprise secrets manager.

YAML
 
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: ${OPENAI_MODEL}
          temperature: 0.2


The lower temperature value encourages more deterministic responses, which is generally preferable for technical or business APIs where consistency matters.

Designing the API Contract

Rather than exposing raw AI requests directly, I prefer defining explicit request and response models. This keeps the REST API independent of the underlying AI provider and makes future changes much easier.

Java
 
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public record AIQuestionRequest(

        @NotBlank
        @Size(max = 2000)
        String question,

        String audience

) {}


Response model:

Java
 
public record AIAnswerResponse(
        String answer
) {}


Configuring the ChatClient

Spring AI's ChatClient is responsible for interacting with the configured language model.

Rather than repeating the same instructions in every request, we can configure a default system prompt once.

Java
 
@Configuration
public class AIConfiguration {

    @Bean
    ChatClient chatClient(ChatClient.Builder builder) {

        return builder
                .defaultSystem("""
                    You are an experienced Java architect.

                    Provide concise,
                    accurate,
                    production-ready answers.

                    Never invent APIs.

                    If uncertain,
                    clearly state your assumptions.
                    """)
                .build();

    }

}


The system prompt establishes the overall behavior of the assistant. It ensures that every request follows the same guidelines, resulting in more predictable responses.

Implementing the AI Service

One architectural decision I recommend is keeping AI interactions inside a dedicated service layer rather than calling the language model directly from a controller.

This separation makes the code easier to test, improves maintainability, and keeps business logic independent of the web layer.

Java
 
@Service
public class TechnicalAssistantService {

    private final ChatClient chatClient;

    public TechnicalAssistantService(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    public AIAnswerResponse answer(AIQuestionRequest request) {

        String audience =
                request.audience() == null
                ? "Java Developer"
                : request.audience();

        String response =
                chatClient.prompt()

                        .user(user -> user

                                .text("""
                                    Explain the following question.

                                    Audience: {audience}

                                    Question:
                                    {question}

                                    Keep the answer under
                                    300 words.
                                    """)

                                .param("audience", audience)
                                .param("question", request.question()))

                        .call()

                        .content();

        return new AIAnswerResponse(response);

    }

}


Creating the REST Controller

With the service layer complete, exposing the AI functionality through a REST endpoint becomes straightforward.

Java
 
@RestController
@RequestMapping("/api/ai")
public class AIController {

    private final TechnicalAssistantService assistantService;

    public AIController(TechnicalAssistantService assistantService) {
        this.assistantService = assistantService;
    }

    @PostMapping("/ask")
    public ResponseEntity<AIAnswerResponse> ask(
            @Valid @RequestBody AIQuestionRequest request) {

        return ResponseEntity.ok(
                assistantService.answer(request));

    }

}


The endpoint accepts a JSON request, validates the input, invokes the service layer, and returns a structured response.

Returning Structured AI Responses

Many AI examples simply return text.

While that's useful for chat applications, enterprise APIs usually need predictable JSON responses.

For example, suppose we want AI to review Java code.

Instead of receiving one long paragraph, we can ask the model to return structured data.

Java
 
public record CodeReviewResponse(

        String summary,

        List<String> strengths,

        List<String>issues,

        List<String>recommendations,

        String riskLevel

){}


Now Spring AI can map the model response directly into a Java object.

Java
 
public CodeReviewResponse review(String sourceCode){

    return chatClient.prompt()

            .system("""
                You are a Senior Java Architect.

                Review the code for
                correctness,
                performance,
                security and
                maintainability.
                """)

            .user(sourceCode)

            .call()

            .entity(CodeReviewResponse.class);

}


This approach is much cleaner than parsing raw JSON or trying to interpret free-form responses manually.

It also keeps the rest of the application strongly typed.

Streaming AI Responses

Some AI responses can take several seconds to complete.

Rather than waiting until the entire response has been generated, Spring AI allows responses to be streamed back to the client.

Java
 
@RestController
@RequestMapping("/api/ai")
public class StreamingController {

    private final ChatClient chatClient;

    public StreamingController(ChatClient chatClient) {
        this.chatClient = chatClient;
    }

    @GetMapping(
            value="/stream",
            produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> stream(
            @RequestParam String question){

        return chatClient.prompt()

                .user(question)

                .stream()

                .content();

    }

}


Streaming significantly improves the user experience because clients can begin displaying the answer immediately instead of waiting for the complete response.

This is especially useful for chat applications and AI assistants.

Cache Responses When Appropriate

AI requests introduce additional latency and cost because every request communicates with an external model.

If the same prompt is frequently submitted, consider caching the response.

Spring Cache makes this simple.

Java
 
@Service
public class TechnicalAssistantService {

    @Cacheable("aiResponses")
    public AIAnswerResponse answer(AIQuestionRequest request) {

        // AI Call

    }

}


Caching works particularly well for frequently asked questions, product descriptions, technical explanations, and internal knowledge articles.

Dynamic or user-specific responses generally should not be cached unless the cache key includes the relevant context.

Final Thoughts

What stands out to me is that Spring AI allows AI capabilities to become a natural extension of an existing Spring Boot application rather than requiring an entirely new architecture. Whether the goal is building an internal knowledge assistant, generating summaries, reviewing code, or automating repetitive tasks, the development experience remains consistent with the rest of the Spring ecosystem.

That said, building a production-ready AI application involves much more than calling an LLM. Prompt design, security, validation, observability, performance, and cost management all play a critical role in delivering reliable solutions.

AI API

Opinions expressed by DZone contributors are their own.

Related

  • From Microservices to Agent Services: The Next Architectural Shift
  • Building an AI-Powered Incident Triage Agent with .NET Aspire
  • Securing AI Agents at the API Layer: 5 Controls That Actually Matter
  • Retrieval Augmented Generation With Spring AI 2.0, Claude, and PGvector

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook