Skip to content

feat(platform-api): support API-level upstreamDefinitions pool#2155

Draft
mehara-rothila wants to merge 1 commit into
wso2:feature/operation-level-epfrom
mehara-rothila:feat/platform-api-upstream-definitions
Draft

feat(platform-api): support API-level upstreamDefinitions pool#2155
mehara-rothila wants to merge 1 commit into
wso2:feature/operation-level-epfrom
mehara-rothila:feat/platform-api-upstream-definitions

Conversation

@mehara-rothila

Copy link
Copy Markdown
Contributor

Purpose

The gateway (data plane) fully supports upstreamDefinitions: a pool of reusable, named backend definitions that an API's upstream.ref resolves against by name. The control plane (platform-api) never declared or emitted this pool, so on the control-plane path it is currently broken:

  • API-level upstream.ref is half-wired. The ref field is accepted, but the pool it must resolve against is never emitted in the deployment YAML, so the gateway rejects it ("no upstreamDefinitions provided").
  • The dynamic-endpoint policy is inert. Its required targetUpstream parameter must name an entry in upstreamDefinitions; with no pool emitted, the policy has nothing to resolve against.
  • Weighted load balancing, per-upstream basePath, and per-upstream timeout (all carried by the pool) cannot be expressed at all through the control plane.

This PR begins closing that control-plane gap by declaring the API-level upstreamDefinitions pool in the platform-api OpenAPI schema.

Goals

Make the control plane able to express the same upstreamDefinitions pool the gateway already consumes, so a single API definition can declare named backends and reference them by name, and ref-based routing plus the dynamic-endpoint policy work through the product, not only by deploying directly to the gateway.

This PR is the first step: the OpenAPI schema declaration. The follow-up steps (code generation, internal model, converters, deployment-YAML emission, validation) wire it through end to end on this same branch.

Approach

Scope of this PR (step 1 of the feature): OpenAPI schema only. It adds the upstreamDefinitions array on the REST API plus the ReusableUpstream and UpstreamTimeout component schemas. No operation-level (per-operation) upstream override is included; that is intentionally deferred.

Design decisions:

  • Shape mirrors the gateway exactly. ReusableUpstream mirrors the gateway's authoritative UpstreamDefinition (name, optional basePath, optional timeout, and upstreams[] with url + optional weight), so the deployment YAML platform-api will emit is parseable by the gateway unchanged. UpstreamTimeout is a direct copy of the gateway's.
  • Naming avoids a collision. platform-api already uses the name UpstreamDefinition for the per-endpoint upstream wrapper (url | ref + auth). The reusable pool entry is therefore named ReusableUpstream so the existing type is untouched and existing endpoints/models are not broken.
  • Single addition via allOf. upstreamDefinitions is added once to the RESTAPI schema; because CreateRESTAPIRequest and UpdateRESTAPIRequest inherit from RESTAPI via allOf, the field is registered for create, update, and read.
  • weight: minimum: 0 to match the gateway (0 means "never route here"), rather than imposing an artificial floor in the control plane.

Remaining work (follow-up commits on this branch):

  1. Regenerate generated.go (make generate).
  2. Add internal model + DTO types (ReusableUpstream, UpstreamTimeout, and UpstreamDefinitions on the config structs).
  3. Wire the converters (OpenAPI ↔ model ↔ deployment-YAML DTO).
  4. Emit the pool in BuildAPIDeploymentYAML (the line that makes ref and dynamic-endpoint functional end to end).
  5. Validation (name uniqueness, weight bounds, ref resolvability).

User stories

As an API developer, I want to declare a set of named, reusable upstream definitions on my API and reference them by name from the API's upstream.ref, so that backend URLs live in one place and ref-based and dynamic-endpoint routing work through the control plane, not just by deploying directly to the gateway.

Documentation

N/A for this schema-only step. User-facing documentation (under the Platform Gateway docs) will accompany the functional wiring.

Automation tests

  • Unit tests

    None in this schema-only step: no Go code paths are added yet (generated.go is regenerated in the follow-up). Unit tests accompany the model, converter, and emission wiring.

  • Integration tests

    N/A for this step.

Security checks

Samples

Once fully wired, an API will be able to declare a pool and reference it:

upstreamDefinitions:
  - name: prod-pool
    basePath: /api/v2
    timeout:
      connect: 5s
    upstreams:
      - url: http://prod-backend-1:5000
        weight: 80
      - url: http://prod-backend-2:5000
        weight: 20
upstream:
  main:
    ref: prod-pool

Test environment

  • Go (version per platform-api/src/go.mod)
  • go build ./cmd/main.go and make test pass (no new code paths in this schema-only step)

…API schema

Declare the API-level upstreamDefinitions pool (ReusableUpstream + UpstreamTimeout) so an upstream.ref can resolve against a named definition, mirroring the gateway's upstreamDefinitions shape. Schema only; model, converters, deployment-YAML emission, and validation follow.
@mehara-rothila mehara-rothila changed the title feat(platform-api): add upstreamDefinitions pool to the REST API Open… feat(platform-api): support API-level upstreamDefinitions pool Jun 11, 2026
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary

This PR adds OpenAPI schema declarations for API-level upstream definitions to the platform-api, enabling support for reusable named upstream configurations at the API level.

Changes

File: platform-api/src/resources/openapi.yaml

RESTAPI Schema Enhancement

Added a new optional upstreamDefinitions field to the RESTAPI schema component. This array field allows APIs to define a list of reusable named upstream definitions that can be referenced by name in endpoint-level upstream.ref values.

New Schema Components

ReusableUpstream - Defines a reusable named upstream definition with the following properties:

  • name (required): Unique identifier following alphanumeric, hyphen, and underscore pattern
  • basePath (optional): Base path prefix prepended to requests routed to this upstream
  • timeout (optional): Reference to UpstreamTimeout configuration
  • upstreams (required): Array of backend targets, each with:
    • url (required): Backend URL (host and port only)
    • weight (optional): Integer weight for load balancing (0–100 range)

UpstreamTimeout - Provides upstream timeout configuration:

  • connect (optional): Connection timeout duration in standard format (e.g., "5s", "500ms")

Impact

The schema additions enable API-level upstream pooling with support for:

  • Named upstream references for reusability across endpoints
  • Weighted load balancing across multiple backend targets
  • Optional base path prefixes for upstream requests
  • Connection timeout configuration

This is a schema-only change; follow-up work will include internal model generation, converter implementation, deployment YAML emission, and validation logic.

Walkthrough

This OpenAPI specification update extends the REST API schema to support reusable upstream definitions. The change introduces two new schema components—ReusableUpstream and UpstreamTimeout—and adds an optional upstreamDefinitions field to the RESTAPI schema. The new ReusableUpstream component defines a named upstream entry with optional base path, timeout configuration, and weighted backend URL targets. The UpstreamTimeout component provides timeout configuration fields including connect-timeout with duration constraints. Together, these changes enable richer, named upstream routing configuration at the API level.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding API-level upstreamDefinitions pool support to the platform-api schema.
Description check ✅ Passed The description is comprehensive and follows the template structure, covering purpose, goals, approach, user stories, documentation, tests, security, samples, and test environment.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mehara-rothila

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@platform-api/src/resources/openapi.yaml`:
- Around line 8455-8464: UpstreamTimeout.connect's OpenAPI regex only allows a
single unit but the runtime uses time.ParseDuration (see
spec.upstreamDefinitions[%d].timeout.connect), so update the OpenAPI schema for
UpstreamTimeout.connect to either (A) broaden the pattern to match Go
time.ParseDuration format (allow multiple sequential value+unit segments,
decimals, and units like ns|us|µs|ms|s|m|h, optional leading minus) or (B)
explicitly document/validate that only single-unit durations are accepted;
locate the UpstreamTimeout.connect property in the OpenAPI file and change the
pattern or description accordingly.
- Around line 8427-8447: Update the ReusableUpstream schema so its basePath
property is constrained to a path-only form and each upstream.url is constrained
to host[:port]-only (no path/query/fragment) to match gateway validation:
tighten basePath (property name basePath) to require a leading "/" and a path
pattern (e.g., path segment characters only) and change
upstreams.items.properties.url to validate host[:port] (e.g., restrict
format/pattern to host with optional port) instead of generic uri; keep timeout
($ref: '`#/components/schemas/UpstreamTimeout`') unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c978ac83-b305-4917-85d3-8826d792c30e

📥 Commits

Reviewing files that changed from the base of the PR and between 66e4674 and e6e8d18.

📒 Files selected for processing (1)
  • platform-api/src/resources/openapi.yaml

Comment thread platform-api/src/resources/openapi.yaml
Comment thread platform-api/src/resources/openapi.yaml
@renuka-fernando renuka-fernando changed the base branch from main to feature/operation-level-ep June 12, 2026 11:52
@renuka-fernando renuka-fernando self-assigned this Jun 12, 2026
@@ -10228,6 +8409,60 @@ components:
description: Authentication value (API key, Bearer token, or Base64 encoded credentials for basic auth)
example: my-api-key-value

ReusableUpstream:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ReusableUpstream:
UpstreamDefinition:

What about UpstreamDefinition here?
cc: @tharindu1st

@mehara-rothila mehara-rothila Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tharindu1st @renuka-fernando this is a 3-way name swap, not a simple rename.

Today in openapi.yaml:

Schema Role Line
Upstream the {main, sandbox} wrapper L8363
UpstreamDefinition the url/ref endpoint L8374
ReusableUpstream the pool entry L8412

(Upstream is shared by API / LLMProvider / MCPServer / WebSub, so it has to stay.)

Two things point the same way:

  • The gateway-controller names the pool entry UpstreamDefinition (management-openapi.yaml#L4210).
  • Our internal model already uses UpstreamEndpoint (endpoint) + UpstreamDefinition (pool) , see platform-api/src/internal/model/upstream.go.

We can't fully match the gateway since it has no wrapper (it inlines {main, sandbox}).

Proposal: keep the Upstream wrapper, then rename:

  • endpoint UpstreamDefinitionUpstreamEndpoint
  • pool entry ReusableUpstreamUpstreamDefinition

This aligns the schema with both the gateway's pool name and our internal model. Good to proceed?

maxLength: 100
pattern: '^[a-zA-Z0-9\-_]+$'
example: my-upstream-1
basePath:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pattern for basePath?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The gateway-controller validates upstream basePath in code (#2106), not via an OpenAPI pattern. Happy to add a matching pattern here for client-side validation , or keep it server-side to match the gateway. Which do you prefer?

@@ -8006,6 +6326,11 @@ components:
example: "2023-10-12T10:30:00Z"
upstream:
$ref: "#/components/schemas/Upstream"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

upstream should have to support ref as well right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes , main/sandbox resolve to UpstreamDefinition (line 8374), which is oneOf: [url] | [ref], so main: { ref: my-upstream-1 } already works. Same shape as the gateway's Upstream in #2012.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants