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

  1. Why do we need a Route in OpenShift?
  2. What is the difference between a Pod, Service, and Route?
  3. Can a Route point directly to a Pod?
  4. What TLS termination options are available?
  5. How does a Route perform load balancing?
  6. Why should only API Gateway services be exposed?
  7. How do you create a Route using the CLI?
  8. How do you verify a Route?
  9. What causes a 503 Service Unavailable error?
  10. What are the best practices for exposing Spring Boot APIs in production?