이 게시물에서는 Upstash를 사용하여 Next.js로 만든 SaaS 애플리케이션에 대한 할당량 시스템을 만드는 방법을 보여 드리겠습니다. 그리고 프리즈마 . Next.js API 경로를 사용하여 간단한 API를 생성하겠습니다.
많은 SaaS 애플리케이션에서 할당량 시스템을 접했을 수 있습니다. 주어진 시간에 사용자가 할 수 있는 작업 수를 제한하는 시스템입니다.
이 예에서 사용자는 매월 1,000개의 API 요청만 보낼 수 있습니다. '무료' 계획. 사용자가 1,000개 이상의 API 요청을 보내려고 하면 애플리케이션은 사용자가 더 이상 요청을 보내지 못하도록 차단합니다.
이러한 API 요청은 스프레드시트의 콘텐츠를 검색하고 이를 JSON으로 변환하는 데 사용됩니다. 이것이 바로 fastsheet의 기능입니다. 모든 Google Sheets 스프레드시트를 JSON API로 변환합니다.

데이터베이스 스키마 정의
앞서 말했듯이 우리는 Prisma를 ORM으로 사용하여 데이터베이스와 상호 작용할 것입니다. 다음은 User의 예입니다. 할당량 시스템과 Spreadsheet을 구현하는 모델 스프레드시트를 저장하는 모델 :
model User {
id Int @id @default(autoincrement())
planId String @default("FREE")
email String @unique
quota Int @default(0)
spreadsheets Spreadsheet[]
}
model Spreadsheet {
id Int @id @default(autoincrement())
userId Int
user User @relation(fields: [userId], references: [id])
content String
}
planId필드는 사용자가 구독하고 있는 요금제입니다.quota필드는 이번 달에 사용자가 수행한 API 요청 수입니다.Spreadsheet모델은User에 연결된 스프레드시트를 나타냅니다. .User여러 개의Spreadsheet를 가질 수 있습니다. 링크되어 있습니다.
작업을 단순하게 유지하기 위해 "FREE"만 처리하겠습니다. 매달 1,000개의 API 요청을 허용하는 계획 .
사용자 할당량 늘리기
우리는 사용자가 API를 요청할 때마다 사용자의 할당량을 늘리고 싶습니다.
언뜻 보면 이 작업이 쉽고 간단해 보입니다. 사용자가 API를 요청할 때마다 사용자 할당량을 1씩 늘릴 수 있습니다. Next.js API 경로에서:
// pages/api/spreadsheets/[id]/index.ts
import type { NextApiRequest, NextApiResponse } from "next";
const MAX_FREE_TIER_QUOTA = 1000;
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
// Get the ID of the spreadsheet from the URL.
const { id } = req.params;
// Get the spreadsheet and its associated user from the database.
const spreadsheet = await prisma.spreadsheet.findUnique({
where: { id: Number(id) },
include: { user: true },
});
// Verify that the spreadsheet exists.
if (!spreadsheet) {
return res.status(404).json({ error: "Spreadsheet not found" });
}
// Verify that the user is not over the quota.
if (spreadsheet.user.quota >= MAX_FREE_TIER_QUOTA) {
return res.status(429).json({ error: "Quota exceeded" });
}
// Increase the user's quota by 1.
await prisma.user.update({
where: { id: spreadsheet.user.id },
data: { quota: { increment: 1 } },
});
// Return the spreadsheet's content.
return res.json({ content: spreadsheet.content });
} 그러나 이 접근 방식에는 문제가 있습니다. 속도가 예상만큼 빠르지 않다는 것입니다.
실제로 우리는 모든 API 요청에 대한 사용자 할당량을 늘리기 위해 데이터베이스 트랜잭션을 생성하고 있습니다. .
사용자의 할당량을 얻기 위해 데이터베이스에 액세스하고 할당량을 1씩 늘리는 트랜잭션을 생성합니다. 을 선택한 다음 스프레드시트 콘텐츠를 보냅니다.
이는 여러 가지 이유로 최적이 아닙니다:
- 데이터베이스가 느려질 수 있으며 이로 인해 응답 시간이 느려질 수 있습니다.
- 데이터베이스가 서버에서 멀리 떨어져 있을 수 있으며 이로 인해 응답 시간이 다시 느려질 수 있습니다.
- 이 코드는 Edge 호환으로 만들기가 더 어렵습니다. , 전 세계에 여러 개의 데이터베이스 복제본을 생성해야 합니다. (쉬운 작업이 아닙니다!) .
Upstash를 사용하여 사용자 할당량 늘리기
이 문제를 해결하기 위해 Upstash Redis®를 사용하여 사용자 할당량을 늘릴 것입니다. Upstash Redis®는 빠르고 안정적인 Redis® 데이터베이스로, 서버리스 환경을 위해 클라우드에 호스팅되어 엣지에 바로 사용할 수 있습니다. (사용자 가까이에서 코드 실행) .
INCR를 사용하겠습니다. 사용자 할당량을 1씩 늘리는 Redis® 명령. 이 명령은 원자적이므로 한 번만 실행되고 빠르게 실행됩니다.
다음은 이전과 동일한 코드이지만 Upstash Redis®를 사용하여 사용자 할당량을 관리합니다.
// pages/api/spreadsheets/[id]/index.ts
import type { NextApiRequest, NextApiResponse } from "next";
import { Redis } from "@upstash/redis";
const MAX_FREE_TIER_QUOTA = 1000;
// Generate an Upstash Redis instance using environment variables.
// Make sure those are defined in your .env file.
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL!,
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
// Get the ID of the spreadsheet from the URL.
const { id } = req.params;
// Get the spreadsheet and its associated user from the database.
const spreadsheet = await prisma.spreadsheet.findUnique({
where: { id: Number(id) },
include: { user: true },
});
// Verify that the spreadsheet exists.
if (!spreadsheet) {
return res.status(404).json({ error: "Spreadsheet not found" });
}
// Redis quota key, unique for each user by its ID.
const quotaKey = `user:${spreadsheet.user.id}:quota`;
// Retrieve the user's quota from Redis.
const quota = await redis.incr(quotaKey);
// If the key did not exist before, the returned value will be 1
// and we set the expiration to 1 day.
if (quota === 1) {
await redis.expire(quotaKey, 60 * 60 * 24);
}
// Verify that the user is not over the quota.
if (quota > MAX_FREE_TIER_QUOTA) {
return res.status(429).json({ error: "Quota exceeded" });
}
// Return the spreadsheet's content.
return res.json({ content: spreadsheet.content });
} Upstash Redis®를 사용하면 Upstash Redis® Edge의 기능을 활용할 수 있으므로 코드를 쉽게 확장할 수 있습니다. 사용자와 가까운 곳에서 코드를 실행하세요.
결론
Upstash Redis®를 사용하면 서버리스 환경을 위한 캐싱 시스템을 매우 쉽게 구현할 수 있습니다.
우리는 이를 할당량 시스템을 구현하는 데 사용했지만 원래 아이디어는 더 많은 데이터베이스 쿼리를 캐싱하거나 API 요청 결과를 캐싱하는 등 훨씬 더 많은 사용 사례에 적용될 수 있습니다.
캐싱의 최종 목표는 API를 더 빠르게 만들고 더 적은 리소스를 소비할 가능성을 높이는 것입니다(예:Planetscale 데이터베이스 읽기/쓰기 쿼리) .
향후 기사에서는 Upstash QStash를 사용하여 Redis®에서 사용자 할당량을 검색하고 이를 데이터베이스에 저장하여 사용자 할당량이 항상 최신 상태이고 손실되지 않도록 하는 방법을 살펴보겠습니다.
실시간으로 보기
이러한 종류의 최적화를 실시간으로 보려면 fastsheet를 확인하세요. , 몇 번의 클릭만으로 Google 스프레드시트를 API로 전환하는 API 서비스입니다. 넉넉한 무료 등급으로 무료로 사용할 수 있습니다.