Repository navigation
Open
Description
Service
API Gateway (REST APIs, v1)
AWS API Action
GetUsage (aws apigateway get-usage) and execute-api calls made with an API key of a usage plan that has a quota or throttle
Expected behavior
API Gateway counts every call a key makes on a stage of its usage plan, reports the count in GetUsage, and refuses a call over the plan's quota or throttle. Measured on AWS (eu-west-1, REST API with MOCK integrations):
| Case | AWS answer |
|---|---|
Plan quota 2 per DAY, three calls with its key |
200, 200, then 429 |
| Call over the quota | 429, x-amzn-ErrorType: LimitExceededException, {"message":"Limit Exceeded"} |
| Call over the throttle (burst 1, rate 0, two calls) | 200, then 429, x-amzn-ErrorType: TooManyRequestsException, {"message":"Too Many Requests"} |
GetUsage after two admitted calls |
[2, 0] for today: [used, remaining], remaining being the limit minus the use from the start of the quota period through that day |
A refused (429) call |
not counted |
A key of the plan on a method with apiKeyRequired=false |
counted and refused the same way |
| A plan without a quota | [0, 0] for every day, even after calls |
A request that fails request validation (400) |
counted: metering runs before validation |
Actual behavior
ApiGatewayService.getUsage answers [0, 0] for every key and day, and nothing on the execute path counts calls per key, so a plan's quota and throttle are never enforced: every call with the key answers 200.
The docs state the gap: Floci "does not enforce throttles or quotas" (docs/services/api-gateway.md).
Reproduction
export AWS_ENDPOINT_URL=http://localhost:4566
API=$(aws apigateway create-rest-api --name metered --query id --output text)
ROOT=$(aws apigateway get-resources --rest-api-id "$API" --query 'items[0].id' --output text)
aws apigateway put-method --rest-api-id "$API" --resource-id "$ROOT" --http-method GET \
--authorization-type NONE --api-key-required
aws apigateway put-integration --rest-api-id "$API" --resource-id "$ROOT" --http-method GET \
--type MOCK --request-templates '{"application/json":"{\"statusCode\":200}"}'
aws apigateway put-method-response --rest-api-id "$API" --resource-id "$ROOT" --http-method GET --status-code 200
aws apigateway put-integration-response --rest-api-id "$API" --resource-id "$ROOT" --http-method GET --status-code 200
aws apigateway create-deployment --rest-api-id "$API" --stage-name prod
PLAN=$(aws apigateway create-usage-plan --name q --api-stages apiId="$API",stage=prod \
--quota limit=2,period=DAY --query id --output text)
KEY=$(aws apigateway create-api-key --name k --enabled --query id --output text)
VALUE=$(aws apigateway get-api-key --api-key "$KEY" --include-value --query value --output text)
aws apigateway create-usage-plan-key --usage-plan-id "$PLAN" --key-id "$KEY" --key-type API_KEY
for i in 1 2 3; do
curl -s -o /dev/null -w '%{http_code}\n' -H "x-api-key: $VALUE" \
"http://localhost:4566/restapis/$API/prod/_user_request_/"
done
# AWS: 200 200 429 Floci: 200 200 200
aws apigateway get-usage --usage-plan-id "$PLAN" --start-date "$(date -u +%F)" --end-date "$(date -u +%F)"
# AWS: today [2, 0] Floci: today [0, 0]Environment
- Floci version / image tag:
mainat cf96dad - Java SDK version (if applicable): n/a
- How you're running Floci (Docker / native /
mvn quarkus:dev): Docker
Metadata
Metadata
Assignees
Labels
No labels
Activity
AndreKurait commentedon Nov 6, 2026
Still present on main cf96dad: usage reporting returns [0, 0] without metering. Existing #7665 addresses this scope; keep the issue open until it lands. Previously qualified a3f1cb7 with 38 tests plus a separate 32-call concurrency control: quota 5 admitted exactly 5 and rejected 27. This is retained local evidence, not a new AWS comparison; weekly/monthly offset anchors remain unverified. No duplicate fix is needed.
fix(apigateway): count usage plan calls per key and enforce quota and…