AWS Builder Center

Building a Generative AI API with Spring Boot and Amazon Bedrock

Learn how to integrate Amazon Bedrock into a Spring Boot application and expose a simple REST API for generative AI, while keeping the application structure clean and production-friendly.

Software Devloper

Building a Generative AI API with Spring Boot and Amazon Bedrock

Generative AI does not always require building an application from scratch.
For Java developers, a practical approach is to keep the familiar Spring Boot architecture and introduce AI as another backend capability.
In this article, we will build a simple REST API using Spring Boot that sends a user prompt to Amazon Bedrock and returns the generated response.
The goal is not to build a complete chatbot. Instead, we will create a clean foundation that can later be extended with authentication, conversation history, streaming responses, logging, rate limiting, guardrails, and other production capabilities.

Architecture

The basic request flow is:
Client → Spring Boot REST API → AI Service → AWS SDK → Amazon Bedrock Runtime → Foundation Model
The Spring Boot application is responsible for the API and business logic, while Amazon Bedrock provides the model inference capability.
[INSERT YOUR ARCHITECTURE IMAGE HERE]

1. Create the Spring Boot project

Start with a standard Spring Boot application using Java 17 or newer.
The main dependencies required for this example are:
  • Spring Web
  • Spring Validation
  • AWS SDK for Java 2.x
  • Amazon Bedrock Runtime
For Maven, add the Bedrock Runtime dependency:
1
2
3
4
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bedrockruntime</artifactId>
</dependency>
Using the AWS SDK BOM is recommended so that AWS SDK module versions remain aligned.

2. Configure AWS credentials

Never hard-code AWS access keys inside Java source code or application configuration.
For local development, the AWS SDK for Java can use the default credentials provider chain.
For example:
1
2
3
4
BedrockRuntimeClient client = BedrockRuntimeClient.builder()
.credentialsProvider(DefaultCredentialsProvider.create())
.region(Region.US_EAST_1)
.build();
In AWS environments, prefer IAM roles instead of long-lived access keys.
This keeps credentials outside the application code and makes the application easier to deploy securely.

3. Create the Bedrock service

The Bedrock integration should be isolated inside a dedicated service rather than placing AWS-specific code directly inside the controller.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Service
public class AiService {

private final BedrockRuntimeClient bedrockClient;

public AiService() {
this.bedrockClient = BedrockRuntimeClient.builder()
.credentialsProvider(DefaultCredentialsProvider.create())
.region(Region.US_EAST_1)
.build();
}

public String generate(String prompt) {

String modelId = "YOUR_MODEL_ID";

Message message = Message.builder()
.content(ContentBlock.fromText(prompt))
.role(ConversationRole.USER)
.build();

ConverseResponse response = bedrockClient.converse(
request -> request
.modelId(modelId)
.messages(message)
.inferenceConfig(config -> config
.maxTokens(500)
.temperature(0.5F))
);

return response.output()
.message()
.content()
.get(0)
.text();
}
}
The exact model ID should be selected based on the model currently available in the AWS Region being used.
Model availability and capabilities can vary by Region and model, so the current Amazon Bedrock model catalog should always be checked before deployment.

4. Expose a REST API

Now we can expose a simple REST endpoint from Spring Boot.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RestController
@RequestMapping("/api/ai")
public class AiController {

private final AiService aiService;

public AiController(AiService aiService) {
this.aiService = aiService;
}

@PostMapping("/generate")
public ResponseEntity<String> generate(@RequestBody String prompt) {

return ResponseEntity.ok(
aiService.generate(prompt)
);
}
}
A request can look like this:
1
2
3
4
POST /api/ai/generate
Content-Type: text/plain

Explain Redis caching in simple terms.
The application receives the request, passes the prompt to the AI service, and returns the generated response.

5. Why use the Converse API?

One useful feature of Amazon Bedrock is the Converse API.
Instead of designing the application around one model's request and response format, the application can use a common conversational interface for supported models.
Conceptually, the application looks like this:
Spring Boot
↓
AI Service
↓
Amazon Bedrock Converse API
↓
Foundation Model
This makes the AI layer easier to evolve as application requirements change.
The application can continue using the same service abstraction while the underlying supported model changes.

6. Add request validation

A production API should not accept empty or unlimited prompts.
Instead of accepting a raw string, create a request DTO.
1
2
3
4
5
6
public record GenerateRequest(
@NotBlank
@Size(max = 4000)

String prompt
) {
}
Then validate the request in the controller:
1
2
3
4
5
6
7
8
@PostMapping("/generate")
public ResponseEntity<String> generate(
@Valid @RequestBody GenerateRequest request)
{

return ResponseEntity.ok(
aiService.generate(request.prompt())
);
}
This keeps input validation close to the API boundary and prevents invalid requests from reaching the Bedrock service.

7. Improve the project structure

As the application grows, it is better to keep AWS-specific logic isolated.
A simple structure could look like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
src/main/java
└── com.example.ai
├── controller
│ └── AiController.java
│
├── service
│ └── AiService.java
│
├── config
│ └── BedrockConfig.java
│
├── dto
│ ├── GenerateRequest.java
│ └── GenerateResponse.java
│
└── exception
└── AiException.java
This structure keeps responsibilities separated and makes the integration easier to maintain.

8. Production considerations

A basic Bedrock integration is straightforward.
A production-ready AI service requires additional considerations.

Authentication

The REST API should be protected using the application's existing authentication mechanism, such as Spring Security with JWT or OAuth2.

Rate limiting

AI requests can become expensive as traffic increases.
Rate limiting should be applied before requests reach Amazon Bedrock.

Timeouts and retries

Bedrock is an external service, so the application should handle transient failures and configure sensible timeout and retry behaviour.

Logging and observability

Useful metrics include:
  • Request count
  • Response time
  • Error rate
  • Model used
  • Token usage where available
  • Estimated application cost
Avoid logging sensitive prompts or personal information unless there is a clear requirement and the appropriate controls are in place.

Cost control

AI usage should be monitored from the beginning.
Set appropriate AWS budgets, monitor Bedrock usage, and establish application-level limits where necessary.

Guardrails

For applications where generated content needs additional safety controls, Amazon Bedrock Guardrails can be used to evaluate model inputs and outputs.
This can help apply policies around content filtering, denied topics, sensitive information, and other application-specific controls.

9. What can we build next?

Once the basic integration is working, the same architecture can be extended into more useful applications.
For example:
Spring Boot
├── AI Chat
├── Document Summarization
├── Customer Support Assistant
├── RAG / Knowledge Base
├── AI-powered Search
└── Tool Calling
The important point is that AI can be introduced as another backend capability instead of rewriting the entire application architecture.

10. Key takeaways

The basic architecture is simple:
Client
↓
Spring Boot REST API
↓
AI Service
↓
AWS SDK for Java
↓
Amazon Bedrock Runtime
↓
Foundation Model
For Java developers, this provides a familiar way to start building generative AI applications while continuing to use technologies such as Spring Boot, REST APIs, dependency injection, validation, security, and standard backend design patterns.
The important engineering challenge is not simply sending a prompt to a model.
The real challenge is integrating AI into the application in a way that is secure, maintainable, observable, and cost-aware.

Conclusion

Amazon Bedrock makes it possible to add generative AI capabilities to applications without building and operating foundation models ourselves.
By keeping the Bedrock integration behind a dedicated Spring Boot service, we can start with a small implementation and evolve it over time.
Authentication, validation, rate limiting, observability, guardrails, RAG, streaming, and asynchronous processing can all be added as the application grows.
For Java developers, this creates a practical path from traditional backend development to production-oriented generative AI applications on AWS.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article