Skip to content

Commit

Permalink
Add/update rate limiting examples with Vercel KV (vercel#745)
Browse files Browse the repository at this point in the history
  • Loading branch information
leerob authored Jul 19, 2023
1 parent 3ba01f8 commit 7295c56
Show file tree
Hide file tree
Showing 46 changed files with 912 additions and 808 deletions.
6 changes: 4 additions & 2 deletions edge-functions/api-rate-limit/.env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
UPSTASH_REST_API_DOMAIN =
UPSTASH_REST_API_TOKEN =
KV_URL="redis://..."
KV_REST_API_URL="https://..."
KV_REST_API_TOKEN="AXx3ASQ..."
KV_REST_API_READ_ONLY_TOKEN="Anx3ASQ..."
27 changes: 12 additions & 15 deletions edge-functions/api-rate-limit/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
---
name: API Rate Limiting with Upstash
slug: api-rate-limit-upstash
description: Template featuring API Rate limiting at the edge with Redis using Upstash.
description: Rate limit your Next.js application with Vercel KV and Upstash.
framework: Next.js
useCase: Edge Functions
css: Tailwind
deployUrl: https://vercel.com/new/clone?repository-url=https://github.com/vercel/examples/tree/main/edge-functions/api-rate-limit&env=UPSTASH_REST_API_DOMAIN,UPSTASH_REST_API_TOKEN&project-name=api-rate-limit-upstash&repository-name=api-rate-limit-upstash
deployUrl: https://vercel.com/new/clone?repository-url=https://github.com/vercel/examples/tree/main/edge-functions/api-rate-limit?project-name=api-rate-limit&repository-name=api-rate-limit&stores=%5B%7B"type"%3A"kv"%7D%5D
demoUrl: https://edge-functions-api-rate-limit.vercel.app
relatedTemplates:
- api-rate-limit-and-tokens
- vercel-middleware-kv-redis
---

# API Rate Limiting with Upstash
# API Rate Limiting with Vercel KV and Upstash

This example features API Rate limiting at the edge with Redis using [Upstash](https://upstash.com/).

The pattern for rate limiting is inspired by the [GitHub API](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting).
This example features API Rate limiting at the edge with [Vercel KV](https://vercel.com/docs/storage/vercel-kv).

## Demo

Expand All @@ -29,7 +28,7 @@ You can choose from one of the following two methods to use this repository:

Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme):

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/examples/tree/main/edge-functions/api-rate-limit&env=UPSTASH_REST_API_DOMAIN,UPSTASH_REST_API_TOKEN&project-name=api-rate-limit-upstash&repository-name=api-rate-limit-upstash)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/examples/tree/main/edge-functions/api-rate-limit?project-name=api-rate-limit&repository-name=api-rate-limit&stores=%5B%7B"type"%3A"kv"%7D%5D)

### Clone and Deploy

Expand All @@ -39,17 +38,15 @@ Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packag
pnpm create next-app --example https://github.com/vercel/examples/tree/main/edge-functions/api-rate-limit api-rate-limit
```

You'll need to have an account with [Upstash](https://upstash.com/). Once that's done, copy the `.env.example` file in this directory to `.env.local` (which will be ignored by Git):

```bash
cp .env.example .env.local
```
Next, create a [Vercel KV](https://vercel.com/docs/storage/vercel-kv) database on your account and connect it to your project.

Then open `.env.local` and set the environment variables to match the REST API of your database. It should look like this:
Copy the example `.env.local` file shown in the dashboard with the credentials needed to connect to your Redis database. It should look similar to this:

```bash
UPSTASH_REST_API_DOMAIN = "us1-shiny-firefly-12345.upstash.io"
UPSTASH_REST_API_TOKEN = "your-api-token"
KV_URL="redis://..."
KV_REST_API_URL="https://..."
KV_REST_API_TOKEN="AXx3ASQ..."
KV_REST_API_READ_ONLY_TOKEN="Anx3ASQ..."
```

Next, run Next.js in development mode:
Expand Down
2 changes: 0 additions & 2 deletions edge-functions/api-rate-limit/components/headers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const Headers: FC<{ path: string; children: string }> = ({
latency: null,
status: null,
headers: {
'X-upstash-latency': '',
'X-RateLimit-Limit': '',
'X-RateLimit-Remaining': '',
'X-RateLimit-Reset': '',
Expand All @@ -29,7 +28,6 @@ const Headers: FC<{ path: string; children: string }> = ({
latency: `~${Math.round(Date.now() - start)}ms`,
status: `${res.status}`,
headers: {
'X-upstash-latency': `${res.headers.get('X-upstash-latency')}ms`,
'X-RateLimit-Limit': res.headers.get('X-RateLimit-Limit'),
'X-RateLimit-Remaining': res.headers.get('x-RateLimit-Remaining'),
'X-RateLimit-Reset': res.headers.get('x-RateLimit-Reset'),
Expand Down
33 changes: 0 additions & 33 deletions edge-functions/api-rate-limit/lib/ip-rate-limit.ts

This file was deleted.

132 changes: 0 additions & 132 deletions edge-functions/api-rate-limit/lib/rate-limit.ts

This file was deleted.

62 changes: 0 additions & 62 deletions edge-functions/api-rate-limit/lib/upstash.ts

This file was deleted.

2 changes: 2 additions & 0 deletions edge-functions/api-rate-limit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
"lint": "next lint"
},
"dependencies": {
"@upstash/ratelimit": "^0.4.3",
"@vercel/examples-ui": "^1.0.5",
"@vercel/kv": "^0.2.2",
"next": "canary",
"react": "latest",
"react-dom": "latest"
Expand Down
5 changes: 3 additions & 2 deletions edge-functions/api-rate-limit/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ export default function MyApp({ Component, pageProps }: AppProps) {

return (
<Layout
title="API Rate Limiting with Upstash"
title="API Rate Limiting with Vercel KV"
path="edge-functions/api-rate-limit"
deployButton={{
env: ['UPSTASH_REST_API_DOMAIN', 'UPSTASH_REST_API_TOKEN'],
customDeployUrl:
'https://vercel.com/new/clone?repository-url=https://github.com/vercel/examples/tree/main/edge-functions/api-rate-limit?project-name=api-rate-limit&repository-name=api-rate-limit&stores=%5B%7B"type"%3A"kv"%7D%5D',
}}
>
<Component {...pageProps} />
Expand Down
25 changes: 17 additions & 8 deletions edge-functions/api-rate-limit/pages/api/ping.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import type { NextRequest } from 'next/server'
import { ipRateLimit } from '@lib/ip-rate-limit'
import { Ratelimit } from '@upstash/ratelimit'
import { kv } from '@vercel/kv'

const ratelimit = new Ratelimit({
redis: kv,
// 5 requests from the same IP in 10 seconds
limiter: Ratelimit.slidingWindow(5, '10 s'),
})

export const config = {
runtime: 'edge',
}

export default async function handler(req: NextRequest) {
const res = await ipRateLimit(req)
// If the status is not 200 then it has been rate limited.
if (res.status !== 200) return res

res.headers.set('content-type', 'application/json')
export default async function handler(request: NextRequest) {
// You could alternatively limit based on user ID or similar
const ip = request.ip ?? '127.0.0.1'
const { limit, reset, remaining } = await ratelimit.limit(ip)

return new Response(JSON.stringify({ success: true }), {
status: 200,
headers: res.headers,
headers: {
'X-RateLimit-Limit': limit.toString(),
'X-RateLimit-Remaining': remaining.toString(),
'X-RateLimit-Reset': reset.toString(),
},
})
}
8 changes: 4 additions & 4 deletions edge-functions/api-rate-limit/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ export default function Index() {
return (
<Page>
<Text variant="h2" className="mb-6">
API Rate Limiting with Upstash
API Rate Limiting with Vercel KV
</Text>
<Text className="mb-4">
By using Redis with Upstash we can keep a counter of requests by IP at
the edge.
By using Redis with Vercel KV, we can keep a counter of requests by IP
address.
</Text>
<Text className="mb-4">
For the demo below you can send a maximum of{' '}
For the demo below, you can send a maximum of{' '}
<b>5 requests every 10 seconds</b>.
</Text>
<Headers path="/api/ping">Make a request</Headers>
Expand Down
Loading

0 comments on commit 7295c56

Please sign in to comment.