Security & Validation

Rate Limiting

Rate-limiting allows you to set a maximum rate of requests for your API gateway. This is useful to enforce rate limits agreed with your clients and protect your downstream services.

The Zuplo Rate-Limit allows you to limit based on different attributes of the incoming request. For example, you might set a rate limit of 10 requests per second per user, or 20 requests per second for a given IP address.

The Zuplo rate-limiter also allows you to set a custom bucket name by which to effect a rate-limit using a function.

When a client reaches a rate limit - they will receive a 429 response code.

Configuration#

{
  "name": "my-rate-limit-inbound-policy",
  "policyType": "rate-limit-inbound",
  "handler": {
    "export": "RateLimitInboundPolicy",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "headerMode": "user",
      "identifier": [
        {
          "export": "$import(./modules/my-module)",
          "module": "default"
        }
      ],
      "mode": "strict",
      "rateLimitBy": "user",
      "requestsAllowed": 1000,
      "throwOnFailure": false,
      "timeWindowMinutes": 60
    }
  }
}

Options#

  • name the name of your policy instance. This is used as a reference in your routes.
  • policyType the identifier of the policy. This is used by the Zuplo UI. Value should be rate-limit-inbound.
  • handler/export The name of the exported type. Value should be RateLimitInboundPolicy.
  • handler/module the module containing the policy. Value should be $import(@zuplo/runtime).
  • handler/options The options for this policy:
    • rateLimitBy

      The identifying element of the request that enforces distinct rate limits. For example, you can limit by user, ip, function or all - function allows you to specify a simple function to create a string identifier to create a rate-limit group

    • requestsAllowed

      The max number of requests allowed in the given time window

    • timeWindowMinutes

      The time window in which the requests are rate-limited. The count restarts after each window expires

    • identifier

      The function that returns dynamic configuration data. Used only with rateLimitBy=function

      • export

        used only with rateLimitBy=function. Specifies the export to load your custom bucket function, e.g. default, rateLimitIdentifier.

      • module

        Specifies the module to load your custom bucket function, in the format $import(./modules/my-module)

    • headerMode

      Adds the retry-after header, defaults to true

    • throwOnFailure

      If true, the policy will throw an error in the event there is a problem connecting to the rate limit service

    • mode

      The mode of the policy. If set to async, the policy will check if the request is over the rate limit without blocking. This can result in some requests allowed over the rate limit.

Tip

Note you can have multiple instances of rate-limiting policies to use in combination. You should apply the longest duration timeWindow first, in order to the shortest duration time window.

Using a custom function

You can create a rate-limit bucket based on any property of a request using a custom function that returns a CustomRateLimitDetails object (which provides the identifier used by the limiting system).

The CustomRateLimitDetails object can be used to override the timeWindowMinutes & requestsAllowed options.

This example would create a unique rate-limiting function based on the customerId parameter in routes (note it’s important that a policy like this is applied to a route that has a /:customerId parameter).

//module - ./modules/rate-limiter.ts
 
import { CustomRateLimitDetails, ZuploRequest } from "@zuplo/runtime";
 
export function rateLimitKey(
  request: ZuploRequest,
  context: ZuploContext,
  policyName: string
): CustomRateLimitDetails {
  context.log.info(
    `processing customerId '${request.params.customerId}' for rate-limit policy '${policyName}'`
  );
  if (request.params.customerId === "43567890") {
    // Override timeWindowMinutes & requestsAllowed
    return {
      key: request.params.customerId,
      requestsAllowed: 100,
      timeWindowMinutes: 1,
    };
  }
}
// config - ./config/policies.json
"export": "RateLimitInboundPolicy",
"module": "$import(@zuplo/runtime)",
"options": {
  "rateLimitBy": "function",
  "requestsAllowed": 2,
  "timeWindowMinutes": 1,
  "identifier": {
    "module": "$import(./modules/rate-limiter)",
    "export": "rateLimitKey"
  }
}

Was this article helpful?

Do you have any questions?Contact us
Check out ourproduct changelog