API cache
API caching writes the responses of query APIs to Redis and returns results directly while the cache is valid, reducing pressure on databases and downstream services. Cache rules are created per environment and then bound to specific APIs.
Entry
Security Management → Flow control rules → API cache.
List fields
| Column | Description |
|---|---|
| Rule ID | Cache rule ID |
| Rule name | A recognizable name |
| Cache duration/s | Cache validity period, in seconds |
| Cache Key rule | URL, URL+Query, URL+Body, URL+custom parameters |
| Max result size/kb | Maximum size of a single response that may be written to the cache |
| Bound APIs | Number of APIs bound to the rule |
| Modified time | Most recent update time |
The list supports filtering by rule name and environment. Before deleting a rule, unbind its APIs; a rule that is still bound to APIs cannot be deleted.
Create a cache rule
- Click "New";
- Select the environment (cannot be changed after creation);
- Enter a rule name;
- Enter the cache duration in seconds;
- Enter the maximum cache result in KB. Responses larger than this size are not written to the cache;
- Select a cache key rule;
- After saving, click "Bind" to bind APIs.
Cache key rules
| Value | Rule | Key composition | Use case |
|---|---|---|---|
| 0 | URL | Method + path | All callers share the same result |
| 1 | URL+Query | Method + path + all query parameters (sorted) | GET queries where query parameters determine the result |
| 2 | URL+Body | Method + path + request body MD5 | POST queries where the body determines the result |
| 3 | URL+custom parameters | Method + path + specified query parameters (sorted) | Cache distinguished only by key parameters |
When "custom parameters" is selected, enter the query parameter names used in the key, separated by commas. If the request is missing all of the specified parameters, the request is not cached and is forwarded directly.
When generating the cache key, the gateway prefixes the rule key with the caller scope: authenticated requests are isolated by app ID, and unauthenticated APIs use anon. Therefore, different apps never hit each other's cache even when request parameters are identical, preventing cross-app data leakage.
Conditions for caching
Caching does not apply to every API; all of the following conditions must be met:
- The API is bound to a cache rule;
- The response content type of the API is JSON;
- The SQL type of the API is SELECT (a query-type SQL API);
- The response size does not exceed the "maximum result size";
- The request is not blocked by rate limiting, circuit breaking, or IP rules.
When the conditions are not met, the request is forwarded normally; it simply does not read from or write to the cache. MCP calls and admin backend routes skip the cache.
Execution flow
- On a cache hit, HTTP 200 is returned with the response header
Api-Cache: true; - Cache writes are asynchronous fire-and-forget; a write failure does not affect the current response;
- Cache values store only the response body, not response headers; on a hit, the content type is returned as JSON.
Capacity and safety limits
| Limit | Default | Description |
|---|---|---|
| Maximum request body size included in the key | 100 KB | Larger requests skip the cache and are forwarded directly, so large bodies do not consume memory; adjustable via apigo.cache.max-body-size-bytes |
| Maximum cached response size | Rule configuration, 1024 KB when unset | Responses above the limit are not cached |
| Gateway aggregation hard cap | 256 MB | Even if a rule is configured higher, this hard cap is never exceeded |
| Default cache duration | 300 seconds | Used when the rule leaves it empty |
| Caller isolation | By appId / anon | Different apps do not share caches |
Design rationale
- Environment isolation: rules and bindings both carry the environment, so development, test, and production caches do not affect each other;
- Cache queries only: the write logic requires the SQL type to be SELECT, preventing write operation results from being cached and returned repeatedly within the validity period;
- Bounded size: while aggregating a response, the gateway counts as it forwards and stops counting immediately once the limit is exceeded, only logging a record, so large responses cannot exhaust gateway memory;
- Failure degradation: when Redis is unavailable or a write fails, requests are forwarded normally and the main path is not blocked;
- No proactive cleanup of old values: after a rule is modified or deleted, existing cache entries are not invalidated immediately and must wait for the TTL to expire; to apply changes immediately, delete the corresponding cache keys in Redis.
FAQ
| Symptom | What to check |
|---|---|
The response has no Api-Cache: true | Whether the rule is bound to the API, the response is JSON, and the SQL is SELECT |
| Old results are still returned after data changes | The cache has not expired; shorten the TTL or clear the cache |
| Different apps read the same result | Check the API authentication method; unauthenticated APIs share the anon scope |
| Large responses are never cached | Check the "maximum result size" against the actual response size |
| POST APIs are not cached | Use the URL+Body or URL+Query rule and confirm the request body does not exceed 100 KB |