API Proxy

Introduction

The API Proxy is an essential element of the YaaS architecture and serves the following purposes:

  • Enforces security
  • Enables central logging and tracing
  • Ensures platform resiliency by implementing the rate-limiting and circuit-breaker mechanisms

The API Proxy is a custom service that acts as an edge server and protects YaaS resources. When you register a service in the Builder, a Generated Proxy URL is created. It masks the service's actual Source URL:

A service in the Builder

All communication between clients and services is routed through this unique proxy url:

graph LR A[Client]--Request--> B{API Proxy} B--Data--> C(Service) C--Exchange->- B B--Response--> A

The API Proxy actively analyzes the YaaS traffic for the response codes, and triggers the relevant mechanism when suspicious activity is identified.

Based on the values of Hybris-specific headers, the API Proxy gathers information about tenants and services interactions. This is processed later for the billing purposes and package rate plans management.

Request Headers

Hybris-specific headers are added with calls to the service proxy:

  • hybris-client: This is your client Identifier.
  • hybris-client-id: This is the Client ID of your client in the Builder.
  • hybris-client-owner: This is the Identifier of the client's parent tenant.
  • hybris-external-path: This is the value of the API proxy YaaS URL that is sent from the client and received at the proxy endpoint.
  • hybris-external-url: This includes the Generated Proxy URL from the Builder.
  • hybris-hop: This is a number that is incremented by one every time a new service is called, in order to process a single request that is identified by hybris-request-id. It has diagnostic purposes, and the service includes it as part of any log message. Your service should propagate it unaltered whenever it makes a subsequent request to another YaaS service.
  • hybris-request-id: This is the request identifier. This is generated if not passed. Your service should propagate it unaltered whenever it makes a subsequent request to another YaaS service.
  • hybris-scopes: This lists the scopes that are requested and granted to the client in the call for an access token. For more information, see Scopes.
  • hybris-service-owner: This is the Identifier of the target service owner.
  • hybris-session-id: This is the session identifier. This is generated if not passed.
  • hybris-target-url: This consists of the Generated Proxy URL from the Builder and a specified endpoint.
  • hybris-tenant: This is the tenant Identifier only for requests in the context of a tenant.
  • hybris-org: This is the organization Identifier in requests sent in the context of an organization.
  • hybris-user: This reflects the authorized user.

For more information, see the Hybris Headers document.


Please note that only Hybris-specific headers are listed in the examples on this page.

Example 1

In this example, a test project is created in the Builder. The project contains a client whose credentials are used to obtain an access token. A custom echo service reads the headers, and no Authorization rule is applied. The following is a list of the headers in the request:

"hybris-client": "tutorial.tutorialapp",
"hybris-client-id": "KTYUcWs1uUSNAxwnhatEjmrn8IpsRGFA",
"hybris-client-owner": "tutorial",
"hybris-external-path": "/hybris/CUSTOM_ECHO_SERVICE/v1",
"hybris-external-url": "https://api.yaas.io/hybris/CUSTOM_ECHO_SERVICE/v1",
"hybris-hop": "1",
"hybris-request-id": "25845194-9989-4dcf-8cca-f74aca068322",
"hybris-scopes": "hybris.tenant=tutorial",
"hybris-service-owner": "toad",
"hybris-session-id": "1be8ba76-ba91-4503-ab60-6e09db32edce",
"hybris-target-url": "https://api.yaas.io/hybris/CUSTOM_ECHO_SERVICE/v1/headers",
"hybris-tenant": "tutorial"

Example 2

The following is a list of the headers when the access token used in the call is issued without any tenant context:

"hybris-external-path": "/hybris/CUSTOM-ECHO-SERVICE/v1",
"hybris-external-url": "https://api.yaas.io/hybris/CUSTOM_ECHO_SERVICE/v1",
"hybris-hop": "1",
"hybris-request-id": "0d51d120-8fe8-4810-a0af-035eeba49ccc",
"hybris-service-owner": "toad",
"hybris-session-id": "136b3716-698b-4388-b8bd-b855b23856eb",
"hybris-target-url": "https://api.yaas.io/hybris/CUSTOM_ECHO_SERVICE/v1/header",
"hybris-user": "user@hybris.com"

Example 3

The following headers are sent with the request when the hybris.org=$organizationID scope was passed while acquiring the access token with the Resource Owner Password Credentials Grant:

"hybris-external-path": "/hybris/CUSTOM_ECHO_SERVICE/v1",
"hybris-external-url": "https://api.yaas.io/hybris/CUSTOM_ECHO_SERVICE/v1",
"hybris-hop": "1",
"hybris-org": "59cc4b46f5ce83bf493f7h29",
"hybris-request-id": "eb2f7303-5d3b-44b3-b8e5-79135eaed718",
"hybris-scopes": "hybris.org=59cc4b46f5ce83bf493f7h29",
"hybris-service-owner": "toad",
"hybris-session-id": "d40bea46-1e68-4b93-8af6-81935d69824e",
"hybris-target-url": "https://api.yaas.io/hybris/CUSTOM_ECHO_SERVICE/v1/headers",
"hybris-user": "user@hybris.com"

Some Hybris-specific headers, such as hybris-user and hybris-org, are added under specific circumstances. When following the Implicit Grant and Resource Owner Password Credentials Grant authorization flows, scopes are passed in the request for an access token, and in the applied authorization rules.

Example 4

The following headers are sent with the request when the Skip Authorization for all paths and methods is applied in the Builder:

"authorization": "Bearer 001-e3c1d3c6-24d5-4071-b8cf-9cb280b1d36e",
"hybris-external-path": "/hybris/CUSTOM_ECHO_SERVICE/v1",
"hybris-external-url": "https://api.yaas.io/hybris/CUSTOM_ECHO_SERVICE/v1",
"hybris-hop": "1",
"hybris-request-id": "a4b0382b-0f92-4070-a56b-aaaee9fd568d",
"hybris-service-owner": "toad",
"hybris-target-url": "https://api.yaas.io/hybris/CUSTOM_ECHO_SERVICE/v1/headers"

The API Proxy does not process the Hybris-specific headers when the Skip Authorization is set on the specified parameters in the Authorization Rules of the service.

Headers Evaluation

The following parameters are evaluated when granting access to YaaS resources:

  • hybris-client and the automatically-created value of hybris-client-id – These are the Identifiers of a client. In requests within a $someproject context such as, hybris.tenant=$someproject, this project must be the owner of the client, or be subscribed to any package that contains this client.
  • hybris-scopes – This is the list of the scopes granted to the client. The effective scopes are intersections of the following:
    • Client Credentials Grant flow – The requested scopes and the subscriptions-related scopes granted to the client by the tenant.
    • Implicit Grant and the Resource Owner Password Credentials Grant – The requested scopes, the subscriptions-related scopes granted to the client by the tenant, and the scopes defined by roles assigned to the user.

    If the evaluated scopes do not match the required scopes of the resource, the service returns an error code of 403. For more information about authorization, see the Security documentation.

  • hybris-tenant – This is the tenant (project). Use hybris.no_tenant to obtain an access token outside the context of any tenant. With the Implicit Grant and Resource Owner Password Credentials Grant, the hybris-user parameter also determines the user's permissions.
  • hybris-user – This is the authenticated user's email. The user must be a member of the tenant (project) to perform operations within the context of this tenant.

For more information about the use of the respective values, see the relevant API documentation.

URL Rewrite

Introduction

The API proxy provides the URL Rewrite mechanism that is essential to services that use self-containing links. When a service generates paged responses with link headers, they encode access to the previous and the next response pages. In YaaS, no external client is able to access the service directly, using its internal address. The only way to access the service is to use the public API Proxy URL in the Builder, called a Generated Proxy URL. However, the service only knows its "internal" URL, which is the URL it is deployed to (or the deployment IP address only).

Use case

How can a service make use of the generated self-containing link, if it doesn't know its Generated Proxy URL, or public API Proxy URL?

Solution

The API Proxy offers the URL Rewrite mechanism to make it easier for service providers to handle such use cases. If you want to generate links that refer to the service itself, use the private deployment URL, regardless of its public API Proxy URL. When the API Proxy processes the response from the service, it transparently rewrites the necessary URL parts, and changes the service private deployment URL to its Generated Proxy URL. The proxy only rewrites URLs that match the Source URL of the service, as configured in the Builder. During the rewrite, additional URL components beyond the Source URL, such as additional path segments, query, and fragment components (if any) are preserved. The URL Rewrite mechanism scans the entire response body for the following content types:

  • application/JSON
  • text/plain
  • text/HTML

    The mechanism also scans for the following two headers:

  • link
  • location

The following diagram illustrates the process flow:

graph LR A[Service]-- Incoming
Target Service
Response --> B{API Proxy} B-- Checks body
and headers
for URL --> D[Source URL
equals
Generated
Proxy URL] D--Yes--> E[URL is
rewritten] D--No-->F[URL is not
rewritten]

Example

In the following example, the result of the API Proxy rewrite processing is shown:

Service definition:

When a GET request is sent to https://api.yaas.io/hybris/torch/v1/fire/path?flame=a&burn=b, assume the service responds with a body containing the following JSON payload:

{
 "seeAlso":"http://torch-v1.hunt.io/new/path?myName=Classified",
 "additionalInfo": "https://www.rfc-editor.org/rfc/rfc20.txt"
}

The API Proxy processes the response and substitutes the matching URL with the following:

{
 "seeAlso":"https://api.yaas.io/hybris/torch/v1/new/path?myName=Classified",
 "additionalInfo": "https://www.rfc-editor.org/rfc/rfc20.txt"
}

Result

The source URL, http://torch-v1.hunt.io is replaced with the Generated Proxy URL, https://api.yaas.io/hybris/torch/v1.

In this example, notice the following:

  • The protocols of the source and proxy URLs are different.
  • The additional path and query components are preserved: "/new/path?myName=Classified".
  • The second "additionalInfo" link is NOT rewritten since it doesn't match the service's Source URL.
The API Proxy rewrite process changes the service response. This can influence your service, for example, when the communication uses digital signatures.

Rate Limiting

Every reliable software ecosystem must be able to handle the incoming traffic that is greater than its processing abilities. Generally, when flooded with requests, the proxy performance may degrade. If it cannot immediately deal with the incoming requests, then they are placed in a queue. This increases the latency for requests until the service is completely overloaded. The clients start to receive the error codes of 502 or 503, and the system requires a restart because it is impossible to send a successful API call.

Our mission is to maintain YaaS as a safe and stable environment. This is why we introduced the rate limiting mechanism to prevent the API Proxy from being affected by malicious or accidental requests that may harm the system.

There are two independent rate-limiting values:

  • per tenant - This value involves all requests per a specific hybris-tenant, across all tenants. When the limit is exceeded, the client receives an error code of 429 and an insufficient_resources error message. This means the client is sending excessive requests, and the number of requests needs to be managed.
  • global - This value takes into account all incoming requests. When the limit is exceeded, the client receives the error code of 503 and a service_temporarily_unavailable error message. This means that excessive or unnecessary calls are being made to the API Proxy.

When the API Proxy is under heavy load, it rejects some of the incoming requests with these errors. Still, the system processes as many calls as it is capable of, with minimum latency.

The rate-limiting values are not configurable for the users. However, the API Proxy mechanism is fully scalable and can adjust to the increased traffic that is not identified as malicious or harmful.

Make your service development more efficient and reduce the number of calls to the API Proxy with the following actions:

  • Create a test client and monitor the number of requests
  • Implement error handling
  • Cache results from previous calls
  • Plan and batch the requests.

Circuit Breaker

The architecture of a microservice relies on the successful communication between various software instances. It is important to manage the failing HTTP calls because they use up the resources and may lead to a system failure.

The API Proxy serves as the guardian of the YaaS ecosystem, and it actively monitors the requests. Each call to a target service that passes through the API Proxy increases one of the two values:

  • success count – HTTP codes of 2xx-4xx
  • failure count – HTTP codes 5xx or timed-out by the API Proxy.

When a client calls a service that is failing or returning slow responses, the ratio of the failure to success count increases. If it reaches the threshold of 50%, the API Proxy triggers the following pattern called the circuit breaker:

sequenceDiagram Client->>API Proxy: GET /hybris/service/v1/a API Proxy->>API Proxy: Circuit breaker check: closed API Proxy->>Target Service: GET /a Target Service->>API Proxy: HTTP code 500 API Proxy->>Client: HTTP code 500 Client->>API Proxy: GET /hybris/service/v1/a API Proxy->>API Proxy: Circuit breaker check: open API Proxy->>Client: HTTP code 503

During the normal operation, the circuit breaker is closed. When it is open, each call to the failing target service is blocked and results with a response code of 503 from the API Proxy:

{
   "status": 503,
   "message": "The circuit breaker for the requested service is currently open. Please try again later.",
   "type": "circuit_breaker_open",
   "moreInfo": "https://api.yaas.io/patterns/errortypes.html"
}


The API Proxy collects the statistics in one-minute timeframes that are split into intervals. To activate the circuit breaker, there must be at least 15 requests to a service within this timeframe. This reflects the total number of requests, regardless the response status codes.

The circuit breaker remains open for a few minutes. This depends on how the failure count is distributed within the time intervals. When the error/success ratio drops below 50%, the API Proxy tries to close the circuit breaker. It switches to a half-opened state and executes a test call to your service. A success response closes the circuit breaker:

graph LR A[Closed]-- Success
or failure under
50% threshold --> A A-- Failure
Threshold reached --> B{Open} B-- Failure --> B B-- Reset Attempt --> C(Half-open) C-- Failure --> B C-- Success --> A

For more information about the background of the circuit breaker mechanism, see external documentation, such as Martin Fowler's website.

If your service requires user interaction, it should return the error codes of 40x for invalid input.

  • Send feedback

    If you find any information that is unclear or incorrect, please let us know so that we can improve the Dev Portal content.

  • Get Help

    Use our private help channel. Receive updates over email and contact our specialists directly.

  • hybris Experts

    If you need more information about this topic, visit hybris Experts to post your own question and interact with our community and experts.