Apigee
    June 9, 2026

    Apigee — Building API Proxies

    Create an Apigee API proxy from scratch: proxy vs target endpoints, flows and conditional routing, route rules, the bundle structure, and how to test it.

    Share

    The API proxy is the unit you build and deploy. This page walks through its anatomy and how to create one.

    Anatomy of a proxy bundle

    A proxy is a folder of XML (the "bundle") you can edit in the UI or in source control:

    apiproxy/
      myapi.xml                 # proxy manifest
      proxies/default.xml       # ProxyEndpoint: base path, flows, route rules
      targets/default.xml       # TargetEndpoint: backend URL, flows
      policies/*.xml            # reusable policy definitions
      resources/                # JS/Java/XSL/OAS resources
    • ProxyEndpoint — defines the base path clients hit (e.g. /orders/v1), the request/response flows, and route rules (which target to use).
    • TargetEndpoint — defines the backend (<HTTPTargetConnection><URL>), with its own flows.

    A minimal ProxyEndpoint

    <ProxyEndpoint name="default">
      <HTTPProxyConnection>
        <BasePath>/orders/v1</BasePath>
      </HTTPProxyConnection>
    
      <PreFlow name="PreFlow">
        <Request>
          <Step><Name>VerifyAPIKey</Name></Step>
          <Step><Name>QuotaPerApp</Name></Step>
        </Request>
      </PreFlow>
    
      <Flows>
        <Flow name="GetOrder">
          <Condition>(proxy.pathsuffix MatchesPath "/{id}") and (request.verb = "GET")</Condition>
          <Request/>
          <Response/>
        </Flow>
      </Flows>
    
      <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
      </RouteRule>
    </ProxyEndpoint>

    Route rules & conditional routing

    Route rules pick the target; conditions let you branch:

    <RouteRule name="noRoute">
      <Condition>request.verb = "OPTIONS"</Condition>
      <!-- no target: respond from the proxy (e.g. CORS preflight) -->
    </RouteRule>
    <RouteRule name="default">
      <TargetEndpoint>default</TargetEndpoint>
    </RouteRule>

    Order matters — the first matching rule wins; keep the unconditional default last.

    Target with a backend

    <TargetEndpoint name="default">
      <HTTPTargetConnection>
        <URL>https://orders-backend.internal/api</URL>
      </HTTPTargetConnection>
    </TargetEndpoint>

    Use target servers + environment config (not hardcoded URLs) so the same proxy points to different backends per environment.

    Create it (UI or CLI)

    • UI: Apigee console → Develop → API Proxies → Create. Start from an OpenAPI spec to scaffold flows automatically.
    • CLI: keep the bundle in git and deploy with apigeecli apis create bundle (covered in the CI/CD page).

    Test it

    Call the deployed proxy's hostname + base path. Use the built-in Debug/Trace tool to watch each policy step execute on a live request — invaluable for understanding flow order and debugging conditions.

    Best practices & anti-patterns

    • Scaffold from an OpenAPI spec — consistent flows, less hand-XML.
    • Externalise backend URLs via target servers + key-value maps per environment.
    • ✅ Keep the proxy thin; put resource-specific logic in conditional flows.
    • ❌ Hardcoding environment-specific URLs/secrets in the bundle.
    • ❌ One giant PreFlow doing everything — organise by conditional flows per resource.

    Next: secure and control traffic → Policies & Security →

    Ask about this article

    Get answers grounded in this post. AI-generated — based on this article, and may be imperfect.

    Scaled AI Weekly

    Enjoyed this? Get more like it every Monday.

    Real architecture decisions, LLMOps patterns that survive production, and engineering leadership advice — from 12+ years of building at enterprise scale. Free. No spam. Unsubscribe anytime.

    Join engineers building production AI systems