Expose Spring Boot API Using OpenShift Route
Learn how to expose a Spring Boot REST API to external users using OpenShift Routes. Understand the complete request flow, Service and Route configuration, TLS, custom domains, and production deployment best practices.
Introduction
After deploying a Spring Boot application to OpenShift, one of the most common questions is:
How do users access my REST API?
By default, a Spring Boot application runs inside a Pod, and Pods are only reachable within the OpenShift cluster.
Even after creating a Service, the application is still internal to the cluster.
To make the API available to browsers, mobile apps, frontend applications, or third-party systems, OpenShift provides a Route.
A Route exposes a Service through a public URL and automatically handles routing, load balancing, and HTTPS termination.
In this article, you'll deploy a Spring Boot REST API and expose it using an OpenShift Route.
Learning Objectives
By the end of this article, you will understand:
- Why Routes are required
- Complete request flow
- Spring Boot deployment architecture
- Create Deployment
- Create Service
- Create Route
- Access REST APIs
- Enable HTTPS
- Verify the deployment
- Production best practices
End-to-End Architecture
flowchart LR
Developer[Developer]
--> Git[Git Repository]
--> Build[Build Pipeline]
--> Image[Container Image]
--> Deployment[OpenShift Deployment]
--> Pod[Spring Boot Pod]
--> Service[ClusterIP Service]
--> Route[OpenShift Route]
--> Browser[Browser / Client]
This is the standard architecture used by most enterprise Spring Boot applications.
Request Flow
sequenceDiagram
participant Browser
participant Route
participant Service
participant Pod
participant SpringBoot
participant Database
Browser->>Route: HTTPS Request
Route->>Service: Forward Request
Service->>Pod: Load Balance
Pod->>SpringBoot: Execute API
SpringBoot->>Database: Read/Write Data
Database-->>SpringBoot: Response
SpringBoot-->>Browser: JSON Response
Project Structure
springboot-openshift-demo/
├── src/
├── pom.xml
├── Dockerfile
├── deployment.yaml
├── service.yaml
├── route.yaml
└── README.md
Prerequisites
Before creating a Route, ensure you have:
- OpenShift Cluster
- OpenShift CLI (
oc) - Spring Boot Application
- Deployment
- Running Pods
- Service
Verify Pods:
oc get pods
Example:
payment-api-7c5df7d8b-2knlm Running
payment-api-7c5df7d8b-hvpt8 Running
Step 1 – Create a Spring Boot REST API
@RestController
@RequestMapping("/api")
public class PaymentController {
@GetMapping("/payments")
public String payments() {
return "Welcome to CodeWithVenu OpenShift!";
}
}
Step 2 – Create Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-api
spec:
replicas: 3
selector:
matchLabels:
app: payment-api
template:
metadata:
labels:
app: payment-api
spec:
containers:
- name: payment-api
image: quay.io/codewithvenu/payment-api:1.0
ports:
- containerPort: 8080
Deploy:
oc apply -f deployment.yaml
Step 3 – Verify Deployment
oc get deployment
Expected output:
payment-api 3/3 Running
Step 4 – Create Service
apiVersion: v1
kind: Service
metadata:
name: payment-service
spec:
selector:
app: payment-api
ports:
- port: 80
targetPort: 8080
Apply:
oc apply -f service.yaml
Service Architecture
flowchart TD
Service[Payment Service]
Service --> Pod1[Spring Boot Pod 1]
Service --> Pod2[Spring Boot Pod 2]
Service --> Pod3[Spring Boot Pod 3]
The Service automatically distributes traffic across all Pods.
Step 5 – Create Route
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: payment-route
spec:
to:
kind: Service
name: payment-service
port:
targetPort: 8080
tls:
termination: edge
Deploy:
oc apply -f route.yaml
Route Architecture
flowchart LR
User[Internet User]
--> Route[OpenShift Route]
--> Service[ClusterIP Service]
--> Pod1[Spring Boot Pod 1]
Service --> Pod2[Spring Boot Pod 2]
Service --> Pod3[Spring Boot Pod 3]
Step 6 – Verify Route
oc get routes
Example:
NAME HOST
payment-route payment.apps.cluster.example.com
Step 7 – Test the API
Open:
https://payment.apps.cluster.example.com/api/payments
Response:
{
"message": "Welcome to CodeWithVenu OpenShift!"
}
Route Load Balancing
Requests are distributed automatically.
flowchart TD
Browser
--> Route
Route
--> Service
Service
--> Pod1
Service
--> Pod2
Service
--> Pod3
If one Pod fails, traffic automatically shifts to healthy Pods.
Enable HTTPS
Configure TLS.
tls:
termination: edge
Supported options:
- edge
- passthrough
- reencrypt
Custom Domain
Production applications usually use custom domains.
Example:
https://api.codewithvenu.com
instead of
https://payment.apps.cluster.example.com
Banking Example
A banking platform exposes only the API Gateway.
flowchart TD
CUSTOMERS["Customers"]
ROUTE["Route"]
API["API Gateway"]
PAYMENT["Payment Service"]
ACCOUNT["Account Service"]
CUSTOMER["Customer Service"]
PAYPODS["Payment Pods"]
ACCPODS["Account Pods"]
CUSPODS["Customer Pods"]
CUSTOMERS --> ROUTE
ROUTE --> API
API --> PAYMENT
API --> ACCOUNT
API --> CUSTOMER
PAYMENT --> PAYPODS
ACCOUNT --> ACCPODS
CUSTOMER --> CUSPODS
Internal services remain private.
Spring Boot Microservices
flowchart LR
BROWSER["Browser"]
ROUTE["OpenShift Route"]
GATEWAY["Gateway Service"]
ORDER["Order Service"]
PAYMENT["Payment Service"]
NOTIFY["Notification Service"]
BROWSER --> ROUTE
ROUTE --> GATEWAY
GATEWAY --> ORDER
GATEWAY --> PAYMENT
GATEWAY --> NOTIFY
Only the Gateway is exposed externally.
Verify Everything
Deployments
oc get deployment
Pods
oc get pods
Services
oc get svc
Routes
oc get routes
Describe Route
oc describe route payment-route
Troubleshooting
Route Not Found
Verify:
oc get routes
Service Not Found
oc get svc
Ensure the Route references the correct Service.
No Endpoints
Check labels.
oc get pods --show-labels
Service selectors must match Pod labels.
503 Service Unavailable
Possible causes:
- Pods not running
- Readiness probe failing
- Incorrect targetPort
- Service selector mismatch
Best Practices
- Always expose a Service, never a Pod.
- Use HTTPS for all production APIs.
- Configure health probes.
- Use meaningful Route names.
- Store Route YAML in Git.
- Expose only API Gateway services.
- Use custom domains for production.
- Monitor Route metrics.
Common Mistakes
❌ Creating a Route directly to a Pod.
❌ Exposing databases externally.
❌ Forgetting TLS.
❌ Incorrect Service selector.
❌ Using HTTP in production.
❌ Exposing every microservice publicly.
Enterprise Deployment Workflow
flowchart LR
DEV["Developer"]
GIT["Git Repository"]
JENKINS["Jenkins Pipeline"]
BC["BuildConfig"]
IS["ImageStream"]
DEPLOY["Deployment"]
SVC["Service"]
ROUTE["Route"]
USERS["Internet Users"]
DEV --> GIT
GIT --> JENKINS
JENKINS --> BC
BC --> IS
IS --> DEPLOY
DEPLOY --> SVC
SVC --> ROUTE
ROUTE --> USERS
This architecture is commonly used in banking, insurance, healthcare, retail, and SaaS platforms.
Summary
OpenShift Routes provide a simple and secure way to expose Spring Boot REST APIs to external users.
Key takeaways:
- Pods are internal and should never be accessed directly.
- Services provide stable internal networking.
- Routes expose Services externally using HTTP/HTTPS.
- Routes support automatic load balancing and TLS termination.
- Most production applications expose only an API Gateway through a Route while keeping backend services private.
- Combining Deployment, Service, and Route creates a scalable and production-ready architecture.
Interview Questions
- Why do we need a Route in OpenShift?
- What is the difference between a Pod, Service, and Route?
- Can a Route point directly to a Pod?
- What TLS termination options are available?
- How does a Route perform load balancing?
- Why should only API Gateway services be exposed?
- How do you create a Route using the CLI?
- How do you verify a Route?
- What causes a
503 Service Unavailableerror? - What are the best practices for exposing Spring Boot APIs in production?