# Step 5 - Dynamic Rate Limiting

Fortune favors the bold. In this bonus getting started guide we'll show you how
to add dynamic rate limiting to your API, all from your local project.

To follow this tutorial you'll need to have completed
[Step 1](./step-1-setup-basic-gateway-local.mdx) for a Zuplo project,
[Step 2](./step-2-add-rate-limiting-local.mdx) to add rate limiting to a route,
and [Step 3](./step-3-add-api-key-auth-local.mdx) to add API key authentication
to that same route.

:::info{title="What's Dynamic Rate Limiting?"}

Traditionally, rate limits are static and the same for everyone. This approach
doesn't let you tailor your rate limiting to your API user - you might want to
offer higher rate limits for customers that pay more. Dynamic rate limiting
allows you to determine an appropriate rate limit at request time.

:::

Let's get started.

<Stepper>

1. Add Consumer Metadata

   Let's make our rate-limiting policy more dynamic, based on properties of the
   customer. In the Zuplo Portal,
   [create a new consumer](./step-3-add-api-key-auth-local.mdx) (Services → API
   Key Service → Configure → Create Consumer), and in the Metadata field set the
   following:

   ```json
   {
     "customerType": "free"
   }
   ```

   Update the metadata of your other API Key consumer (3-dot menu → Edit) from
   Step 3 to:

   ```json
   {
     "customerType": "premium"
   }
   ```

   Now that there are users with different `customerType`, this information can
   be used to rate limit them differently.

1. Add a Custom Code Module

   In your editor, create a new file at `modules/rate-limit.ts` in your project.

   :::info{title="What's a Module?"}

   Modules are TypeScript functions that you can execute within Zuplo. They're
   typically used to add custom code within the request/response pipeline (for
   example custom policies or request handlers). You can even perform network
   requests and use libraries within these modules.

   :::

   Add the following code to your module:

   ```ts
   import { ZuploContext, ZuploRequest } from "@zuplo/runtime";

   export function rateLimit(request: ZuploRequest, context: ZuploContext) {
     const user = request.user;

     // premium customers get 1000 requests per minute
     if (user.data.customerType === "premium") {
       return {
         key: user.sub,
         requestsAllowed: 1000,
         timeWindowMinutes: 1,
       };
     }

     // free customers get 5 requests per minute
     if (user.data.customerType === "free") {
       return {
         key: user.sub,
         requestsAllowed: 5,
         timeWindowMinutes: 1,
       };
     }

     // everybody else gets 30 requests per minute
     return {
       key: user.sub,
       requestsAllowed: 30,
       timeWindowMinutes: 1,
     };
   }
   ```

1. Update your Policy

   Now we'll reconfigure the rate-limiting policy to wire up our custom
   function. Open the local **Route Designer** at http://localhost:9100, find
   the policy, and click **Edit** — or edit `config/policies.json` directly in
   your editor.

   Update the configuration to:

   ```json
   {
     "export": "RateLimitInboundPolicy",
     "module": "$import(@zuplo/runtime)",
     "options": {
       "rateLimitBy": "function",
       "requestsAllowed": 2,
       "timeWindowMinutes": 1,
       "identifier": {
         "export": "rateLimit",
         "module": "$import(./modules/rate-limit)"
       }
     }
   }
   ```

   By changing the `rateLimitBy` to `function` you are indicating the rate limit
   will be determined by a module at runtime. The `identifier` property
   indicates the module and function to run. Make sure to save once you've made
   your changes.

   :::tip

   Dynamic rate limiting reads from `request.user`, so the API key
   authentication policy from [Step 3](./step-3-add-api-key-auth-local.mdx) must
   run **before** the rate-limiting policy.

   :::

1. Test your Policy

   With your gateway running (`npm run dev`), try your dynamic rate limiting.
   Grab the key for each consumer back in the Services tab where you created
   them, then make calls with each key until you hit its limit.

   ```bash
   # free consumer — limited to 5 requests per minute
   curl http://localhost:9000/todos \
     --header 'Authorization: Bearer <FREE_CONSUMER_KEY>'

   # premium consumer — allowed 1000 requests per minute
   curl http://localhost:9000/todos \
     --header 'Authorization: Bearer <PREMIUM_CONSUMER_KEY>'
   ```

   Observe the difference in rate limits between the two consumers.

</Stepper>

## Wrapping up

Congratulations - you've just successfully built an API that's:

- Protected by API key Authentication
- Dynamically Rate Limited
- Deployed to the Edge for superior performance
- and fully documented via your Developer Portal

This is an API experience most companies dream of, and you've just built it in
less than an hour.

### Next Steps

- Continue exploring our docs to learn about customizing your
  [Developer Portal](../dev-portal/introduction.mdx), or explore our various
  [Integrations](https://zuplo.com/integrations)
- [Grab time](https://zuplo.com/meeting) with the Zuplo team to have your
  questions answered
- Start generating revenue from your new API with our
  [Monetization tutorial](./monetization/index.mdx)
