مستندات API اشعار فارسی
مرجع کامل برای API داده، موتور تیغ، فورک و توسعه، و پرامپتهای آماده برای دستیارهای کدنویسی.
یا فشار دهید / در هر صفحهای
معرفی کلی
API رایگان و متنباز برای دسترسی به مجموعهای از اشعار و سخنان فارسی. تعداد دقیق اسناد، شاعران و دستهبندیها در بخش متریک زنده از دادهٔ واقعی مخزن خوانده میشود.
متریک زنده موتور
شروع سریع
اولین درخواست در کمتر از ۳۰ ثانیه. هیچ مرحله نصبی لازم نیست — فقط یک درخواست HTTP ارسال کنید.
# دریافت یک شعر تصادفی
curl "https://pq.arsamadineh.ir/api/quotes?random=true&limit=1"
# دریافت ۵ شعر از حافظ
curl "https://pq.arsamadineh.ir/api/quotes/hafez?limit=5"
# فال حافظ (یک غزل تصادفی)
curl "https://pq.arsamadineh.ir/api/quotes/hafez?random=true&limit=1"
# جستجوی کلمه «عشق»
curl "https://pq.arsamadineh.ir/api/quotes/search?q=%D8%B9%D8%B4%D9%82&limit=5"پنج اندپوینت برتر برای شروع
GET /api/quotes?random=true&limit=1GET /api/quotes/hafez?random=true&limit=1GET /api/quotes/search?q=عشقGET /api/poets?stats=trueGET /api/engine/stats
احراز هویت
احراز هویت لازم نیست
تمام اندپوینتها کاملاً عمومی هستند. هیچ کلید API، توکن، یا ثبتنامی نیاز نیست. فقط کافی است درخواست HTTP ارسال کنید. هدر Accept: application/json اختیاری است.
نرخ درخواست منصفانه
موتور تیغ بهطور پیشفرض ۱۲۰ درخواست در دقیقه برای هر IP مجاز میکند. اگر به بیشتر نیاز دارید، صفحه محدودساز نرخ را ببینید.
CORS باز
تمام اندپوینتها برای استفاده از مرورگر و فرانتاند پاسخگو هستند. میتوانید مستقیماً از دامنه خودتان fetch کنید.
مرجع اندپوینتها
تمام روشها GET هستند. پاسخها همگی JSON با ساختار یکپارچه{ success, data, count, meta }.
مسیرها
پارامترها
| نام | نوع | پیشفرض | توضیح |
|---|---|---|---|
limit | number | 10 | تعداد اشعار بازگشتی (حداکثر 100) |
random | boolean | false | انتخاب تصادفی اشعار |
poet | string | — | فیلتر بر اساس نام شاعر (مثلاً: مولانا) |
category | string | — | فیلتر بر اساس دستهبندی (مثلاً: عشق) |
نمونه درخواست
نمونه پاسخ
{
"success": true,
"data": [
{
"id": 1,
"text_persian": "عاشقان مردهاند در عشق زنده\nتا ابد در دل جانان پاینده",
"text_english": "Lovers are dead in love, yet alive...",
"poet": "مولانا جلالالدین رومی",
"poet_english": "Rumi",
"source": "دیوان شمس",
"category": "عشق",
"tags": ["عشق", "زندگی", "جاودانگی"]
}
],
"count": 1,
"meta": { "limit": 1, "random": true }
}مسیرها
پارامترها
| نام | نوع | پیشفرض | توضیح |
|---|---|---|---|
id | number | — | دریافت غزل با شماره موجود در مجموعه |
q | string | — | جستجو در بین مصرعهای دیوان |
limit | number | 10 | تعداد غزلها (حداکثر 100) |
random | boolean | false | دریافت تصادفی (فال حافظ) |
نمونه درخواست
نمونه پاسخ
{
"success": true,
"data": [
{
"id": 1,
"verses": [
["الا یا ایها الساقی ادر کاسا و ناولها", "که عشق آسان نمود اول ولی افتاد مشکلها"],
["به بوی نافه کاخر صبا زان طره بگشاید", "ز تاب جعد مشکینش چه خون افتاد در دلها"]
],
"poet": "حافظ شیرازی",
"source": "دیوان حافظ"
}
],
"count": 1,
"total": "نمونه؛ مقدار واقعی از API خوانده میشود"
}verses یک آرایه از زوجهای [مصرع اول، مصرع دوم] است. ساختار بیتی برای نمایش آسان در رابط کاربری.مسیرها
پارامترها
| نام | نوع | پیشفرض | توضیح |
|---|---|---|---|
poet | string | — | نام شاعر (مثلاً: نیما یوشیج، سهراب سپهری) |
title | string | — | جستجو در عنوان شعر |
limit | number | 10 | تعداد اشعار (حداکثر 100) |
random | boolean | false | انتخاب تصادفی |
نمونه درخواست
نمونه پاسخ
{
"success": true,
"data": [
{
"id": 2,
"title": "قایق",
"poem": "من چهرهام گرفته / من قایقم نشسته به خشکی...",
"poet": "نیما یوشیج",
"book": "مجموعه اشعار"
}
],
"count": 1,
"total": "نمونه؛ مقدار واقعی از API خوانده میشود"
}مسیرها
پارامترها
| نام | نوع | پیشفرض | توضیح |
|---|---|---|---|
author | string | — | نام گوینده (مثلاً: انیشتین) |
limit | number | 10 | تعداد نقلقولها (حداکثر 100) |
random | boolean | false | انتخاب تصادفی |
نمونه درخواست
نمونه پاسخ
{
"success": true,
"data": [
{
"id": 2,
"body": "راه حل موفقیت این است که اشتیاق شما به پیروزی بیشتر از ترس شما از شکست باشد.",
"author": "آلبرت انیشتین"
}
],
"count": 1,
"total": "نمونه؛ مقدار واقعی از API خوانده میشود"
}مسیرها
پارامترها
| نام | نوع | پیشفرض | توضیح |
|---|---|---|---|
qلازم | string | — | کلمه یا عبارت جستجو (حداقل ۲ کاراکتر) |
limit | number | 10 | تعداد نتایج (حداکثر ۵۰) |
lang | string | both | زبان: persian | english | both |
نمونه درخواست
مسیرها
پارامترها
| نام | نوع | پیشفرض | توضیح |
|---|---|---|---|
theme | string | default | default | elegant | minimal | classic | modern |
size | string | medium | small | medium | large |
poet | string | — | فیلتر شاعر خاص |
category | string | — | فیلتر دستهبندی خاص |
auto_refresh | boolean | false | تازهسازی خودکار هر ۳۰ ثانیه |
نمونه درخواست
<iframe
src="https://pq.arsamadineh.ir/api/embed?theme=classic&poet=rumi"
width="100%"
height="300"
frameborder="0"
></iframe>موتور تیغ
یک موتور API نوشتهشده در TypeScript خالص؛ ماژولهای موتور به وابستگی خارجی نیاز ندارند. مناسب برای هر پروژهای که به مسیریابی سریع، کش هوشمند، و متریک زنده نیاز دارد.
مسیریاب Trie
TighRouter از ساختار Trie برای matching استفاده میکند. به جای جستجوی خطی O(n) در لیست مسیرها، مسیر ورودی به segment تقسیم میشود و در هر گره درخت Trie تنها یک شاخه پیمایش میشود.
پارامتر داینامیک
/api/quotes/[poet]
/api/quotes/hafez
→ { poet: "hafez" }Wildcard
/api/static/*
/api/static/css/style.css
→ { wildcard: "css/style.css" }ترکیبی
/api/[version]/users/[id]
/api/v2/users/42
→ { version: "v2", id: "42" }کش LRU + TTL
TighCache با دو مکانیزم Eviction:
- LRU (Least Recently Used): وقتی اندازه به سقف میرسد، کماستفادهترین کلید حذف میشود.
- TTL (Time To Live): هر کلید پس از انقضا بهطور خودکار از کش خارج میشود.
- invalidatePattern: حذف گروهی کلیدها بر اساس الگوی regex.
// استفاده در یک route
engine.get("/api/quotes/popular", async () => {
const top = await db.quotes
.orderBy("likes", "desc")
.limit(20)
return {
status: 200,
headers: { "Content-Type": "application/json" },
body: top,
}
}, {
cache: {
ttl: 5 * 60_000, // ۵ دقیقه
key: (req) => `popular:${req.ip}`,
},
})محدودساز نرخ
TighRateLimiter سه استراتژی برای کنترل نرخ درخواست دارد:
Token Bucket
پیشفرض. درخواستها با سرعت ثابت جایگزین میشوند.
ترافیک متغیر و burst-پذیر
Sliding Window
شمارش دقیق درخواستها در پنجره زمانی شناور.
ترافیک یکنواخت
Fixed Window
شمارش ساده در هر پنجره زمانی ثابت.
ترافیک قابل پیشبینی
// هدرهای پاسخ
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1751640000
Retry-After: 30 // فقط در حالت 429مدار شکن
TighCircuitBreaker از الگوی سهحالته پیروی میکند تا از فراخوانی بیش از حد یک endpoint ناپایدار جلوگیری کند.
CLOSED
حالت عادی. درخواستها عبور میکنند. خطاها شمارش میشوند.
OPEN
پس از رسیدن به آستانه خطا، درخواستها بلاک میشوند (۵۰۳). پس از recoveryTimeout به half-open میرود.
HALF-OPEN
تعداد محدودی درخواست آزمایشی ارسال میشود. موفقیت → closed، شکست → open.
پایپلاین Middleware
TighMiddleware هر درخواست را از طریق زنجیرهای از middlewareها عبور میدهد. دو middleware پیشفرض فعال هستند و فشردهسازی بهصورت اختیاری در دسترس است:
corsMiddlewareتزریق هدرهای CORS و پاسخ ۲۰۴ به OPTIONS
timingMiddlewareاندازهگیری پاسخ + تزریق X-Request-Id
compressMiddlewareفشردهسازی gzip اختیاری در پاسخهای بزرگ
// افزودن middleware سفارشی
engine.use(async (req, next) => {
const start = Date.now()
const res = await next()
console.log(`${req.method} ${req.path} → ${res.status} (${Date.now() - start}ms)`)
return res
})متریکها
TighMetrics بهطور خودکار برای هر درخواست latency، method، path و status code را ثبت میکند. percentileها بهصورت بلادرنگ محاسبه میشوند.
اداپتور Next.js
createNextHandler(engine) یک NextRequest میگیرد و آن را به TighRequest تبدیل میکند، در موتور اجرا میکند، و پاسخ را بهصورت Response استاندارد Web برمیگرداند.
import { createNextHandler } from "@/lib/engine"
import { engine } from "@/lib/engine/instance"
export const dynamic = "force-dynamic"
export const GET = createNextHandler(engine)
// به همین سادگی تمام handlerهای شما از موتور عبور میکنند
// و از کش، rate limit، circuit breaker، و متریک بهره میبرند.اندپوینتهای موتور
دو اندپوینت برای مشاهده وضعیت داخلی موتور — بدون احراز هویت:
متریک زنده
GETlatency p50-p99، hit rate کش، وضعیت مدار شکن، و uptime.
/api/engine/statsبنچمارک
GETاندازهگیری ns/op برای روتر، کش، و متریک با تعداد تکرار قابل تنظیم (پیشفرض ۱۰۰۰).
/api/engine/benchmark?iterations=5000فورک کردن و توسعه موتور
موتور تیغ طوری طراحی شده که بهراحتی در پروژه شما قابل استفاده و گسترش باشد. این راهنما شما را از صفر تا استقرار یک نمونه سفارشی همراهی میکند.
فورک کردن مخزن
روی صفحه گیتهاب، دکمه Fork را بزنید. مخزن به حساب شما کپی میشود.
git clone https://github.com/YOUR-USER/Persian-Quote-API.git
cd Persian-Quote-API
bun installنکته: پس از نصب، پروژه آماده اجرا است. دستور bun run dev سرور توسعه را روی پورت ۳۰۰۰ بالا میآورد.
آشنایی با ساختار موتور
تمام منطق موتور در lib/engine/ است. مهمترین فایل برای ویرایش instance.ts است که پیکربندی سراسری موتور را نگه میدارد.
// lib/engine/instance.ts
import { Tigh } from "./engine"
export const engine = new Tigh({
enableCache: true, // کش LRU داخلی
enableRateLimit: true, // محدودسازی نرخ
enableCircuitBreaker: true, // مدار شکن خودترمیم
cache: {
maxSize: 5000, // حداکثر کلید
defaultTTL: 30_000, // ۳۰ ثانیه
},
rateLimit: {
windowMs: 60_000, // ۶۰ ثانیه
maxRequests: 120, // ۱۲۰ درخواست
strategy: "token-bucket",
},
})نکته: تغییر این مقادیر بلافاصله روی رفتار تمام اندپوینتهای موتور اعمال میشود.
افزودن اندپوینت سفارشی
هر فایل در app/api/*/route.ts میتواند از موتور استفاده کند یا مستقل باشد. الگوی کنونی: route ها مستقیماً NextResponse برمیگردانند — برای استفاده از موتور، ساختار را به handler-based تغییر دهید.
// app/api/hello/route.ts
import { createNextHandler } from "@/lib/engine"
import { engine } from "@/lib/engine/instance"
engine.get("/api/hello", async (req) => {
return {
status: 200,
headers: { "Content-Type": "application/json" },
body: { greeting: "سلام", lang: req.headers["accept-language"] },
}
}, {
cache: { ttl: 60_000 },
})
export const GET = createNextHandler(engine)نکته: نکته: route.register در زمان import اجرا میشود، پس فایل را در hot reload لازم نیست دوباره import کنید.
سفارشیسازی ماژولها
تمام ماژولها قابل جایگزینی هستند: TighRouter، TighCache، TighRateLimiter، TighCircuitBreaker، TighMiddleware.
// نمونه: جایگزینی کش با نسخه ردیس-مانند
import { Tigh } from "./engine"
import { MyRedisCache } from "./my-redis-cache"
const engine = new Tigh({
cache: { maxSize: 100_000, defaultTTL: 300_000 }
})
engine.cache = new MyRedisCache({ url: process.env.REDIS_URL! })نکته: کافی است اینترفیس عمومی هر ماژول را پیاده کنید و در سازنده Tigh جایگزین کنید.
نوشتن تست با Bun Test
چون موتور صفر وابستگی دارد، تستنویسی بسیار ساده است.
// tests/cache.test.ts
import { test, expect } from "bun:test"
import { TighCache } from "../lib/engine/cache"
test("TighCache respects TTL", () => {
const c = new TighCache({ maxSize: 10, defaultTTL: 50 })
c.set("k", "v")
expect(c.get("k")).toBe("v")
Bun.sleep(60)
expect(c.get("k")).toBeNull()
})
test("TighCache evicts LRU", () => {
const c = new TighCache({ maxSize: 2 })
c.set("a", 1); c.set("b", 2); c.get("a"); c.set("c", 3)
expect(c.has("a")).toBe(false)
})نکته: bun test تمام تستها را اجرا میکند. CI از bun test bun.lock استفاده میکند.
استقرار
پروژه استاندارد Next.js است — Vercel بهطور خودکار آن را تشخیص میدهد.
# روی Vercel
vercel deploy
# یا با GitHub Actions
git push origin main # در Vercel فعال باشد، خودکار deploy میشودنکته: پس از deploy، به /sakhtar بروید و متریک زنده موتور را در production ببینید.
پس از فورک
اگر بهبودی در موتور اعمال کردید که به نفع همه است، یک Pull Request به مخزن اصلی بفرستید. راهنمای مشارکت در AGENTS.md توضیح داده شده است — بهویژه قاعده ثبت در changelog و لحن رسمی-دوستانه.
پرامپتهای آماده برای دستیارها
اگر با Cursor، Claude Code یا Codex کار میکنید، کافی است یکی از پرامپتهای زیر را کپی کنید و در دستیار خود paste کنید. پاسخ را به فارسی یا انگلیسی تنظیم کردهایم.
توضیح کامل معماری موتور
از دستیار بخواهید ساختار lib/engine را به فارسی توضیح دهد و رابطه بین ماژولها را بنویسد.
You are inside /home/arsam/Documents/work/Website/Webdev/Persian-Quote-API. Read every file under lib/engine/*.ts. Produce a written map (under 400 words) of every module: name, exports, role, and how it wires to engine.ts. Reply in Persian with code snippet citations.
ساخت اندپوینت جدید با موتور
یک اندپوینت GET که با موتور تیغ اجرا میشود، کش دارد، و از circuit breaker پیروی میکند.
Create app/api/quotes/by-tag/[tag]/route.ts that uses Tigh from lib/engine. The handler must: import sampleQuotes from lib/data/poetry-quotes.json, filter where tags contains the [tag] param, return at most 50 results, attach cache { ttl: 60_000, key }, and surface non-200 status via the engine's circuit breaker. Show the full file and explain each engine call.تنظیم TTL هر مسیر
بررسی الگوی ترافیک هر اندپوینت و پیشنهاد TTL اختصاصی — با قطعه کد.
Open lib/engine/instance.ts and lib/engine/cache.ts. Scan app/api/**/route.ts and propose: a per-route defaultTTL (short 10s for /search, medium 60s for /quotes/*, long 24h for /hafez, /shereno). Produce a diff for instance.ts plus a snippet showing engine.route({ cache: { ttl, key } }) for one route. Quantify expected hit-rate improvement.اشکالزدایی Latency
تحلیل دادههای زنده و ارائه دو پیشنهاد برای رساندن P99 به زیر ۵۰ms.
Hit GET /api/engine/stats and parse latency.p50/p90/p95/p99 plus cache.hitRate. Identify the top 3 slowest paths from topPaths. Suggest two concrete optimizations (cache key rewrite, eager prewarm, or middleware reorder) that should bring p99 below 50ms. Show diffs and explain trade-offs.
استقرار روی Vercel
راهنمای کامل env vars، build command، و تنظیمات لبه.
Walk me through a full Vercel deployment of /home/arsam/Documents/work/Website/Webdev/Persian-Quote-API. Provide: the exact env vars (none required, but list any optional for future use), build/dev commands, a minimal vercel.json that pins Node.js 20 and maximizes the cron quota, and a check that the JSON imports in lib/data/*.json remain valid on the Edge runtime.
افزودن تستهای موتور
ساخت تست واحد برای هر ماژول با Bun Test.
Create tests/ folder with bun:test unit tests for every module in lib/engine: TighRouter (param + wildcard match), TighCache (LRU eviction, TTL expiration), TighRateLimiter (each strategy), TighCircuitBreaker (state transitions), TighMetrics (percentile accuracy). Group tests by module. No external libraries; pure assertions.
خلاصه PR برای بازبینی
از تغییرات فعلی یک توصیف کوتاه و حرفهای برای ارسال به GitHub PR بساز.
Look at the currently changed files (git status / git diff --staged). Write a Persian PR description under 250 words: a one-line summary, a section of files changed, and a checklist of what to verify before merging. Keep language formal and direct — no marketing adjectives.
Refactor یک اندپوینت موجود
تبدیل یکی از route.tsهای موجود به استفاده کامل از موتور (بهجای NextResponse مستقیم).
Pick app/api/quotes/route.ts. Refactor it to delegate to engine via createNextHandler(engine) from lib/engine/adapter-next.ts. Register the route inside instance.ts via engine.get("/api/quotes", ...), wire cache { ttl, key } and rateLimit config. Provide a step-by-step diff and explain how NextRequest becomes the engine Request shape.نحوه استفاده
- روی یکی از کارتها دکمه «کپی» را بزنید.
- در پنل دستیار، متن کپیشده را paste کنید.
- پاسخ را بخوانید، تغییرات را مرور کنید، و در صورت نیاز PR ثبت کنید.
در مستندات بیشتر درباره هر پرامپت، روی عنوان کارت کلیک کنید تا به بخش مربوط به آن هدایت شوید.
نمونههای کاربردی
چهار سناریوی واقعی برای استفاده از API — از سادهترین تا یکپارچهسازی کامل در رابط کاربری.
نمایش شعر روز در سایت
هر روز یک شعر جدید به بازدیدکنندگان نشان دهید.
const today = new Date().toISOString().slice(0, 10)
const res = await fetch(
`https://pq.arsamadineh.ir/api/quotes?random=true&limit=1&cacheBust=${today}`
)
const { data } = await res.json()
// data[0].text_persianویجت فال حافظ
یک iframe ساده برای نمایش فال حافظ در سایت شخص ثالث.
<iframe
src="https://pq.arsamadineh.ir/api/embed?theme=classic&poet=hafez&auto_refresh=true"
width="400"
height="280"
style="border: 0; border-radius: 12px;"
loading="lazy"
></iframe>تست بار (Load Test)
اندازهگیری latency واقعی از سمت کاربر.
import asyncio, aiohttp, time
async def hit(session, url):
async with session.get(url) as r:
return r.status, await r.json()
async def main():
url = "https://pq.arsamadineh.ir/api/quotes?random=true"
async with aiohttp.ClientSession() as s:
start = time.time()
results = await asyncio.gather(*[hit(s, url) for _ in range(100)])
print(f"100 reqs in {time.time() - start:.2f}s")
asyncio.run(main())اپ موبایل (React Native)
یک اپ ساده برای مرور اشعار، با کش محلی برای آفلاین.
import { useEffect, useState } from "react"
import AsyncStorage from "@react-native-async-storage/async-storage"
export function QuoteScreen() {
const [quote, setQuote] = useState(null)
useEffect(() => {
AsyncStorage.getItem("quote").then(setQuote)
}, [])
const refresh = async () => {
const r = await fetch("/api/quotes?random=true&limit=1")
const j = await r.json()
setQuote(j.data[0])
AsyncStorage.setItem("quote", JSON.stringify(j.data[0]))
}
return /* ... */
}استقرار و خودمیزبانی
سه روش برای راهاندازی یک نمونه شخصی — از سادهترین (Vercel) تا کنترل کامل (Docker).
- مخزن را به حساب گیتهاب خود fork کنید.
- به
vercel.comبروید و «New Project» را بزنید. - مخزن fork شده را انتخاب کنید. Vercel بهطور خودکار Next.js را تشخیص میدهد.
- روی «Deploy» کلیک کنید. در کمتر از یک دقیقه نمونه شما فعال میشود.
- برای custom domain، از تنظیمات پروژه دامنه را اضافه کنید.
هیچ متغیر محیطی لازم نیست — تمام دادهها فایلهای JSON محلی هستند.
پشتیبانگیری از دادهها
فایلهای JSON در lib/data/ منبع حقیقتی هستند. برای افزودن شعر جدید، یا فایل JSON را ویرایش کنید، یا از فرم /contribute استفاده کنید تا یک PR خودکار ساخته شود.
عیبیابی
رایجترین مشکلات و راهحلهای آنها.
CORS بلاک میکند
کش stale شده
دریافت ۴۲۹ (Too Many Requests)
مدار شکن باز است (۵۰۳)
P99 بالا (بیش از ۲۰۰ms)
مدیریت خطاها
کدهای HTTP استاندارد و ساختار پاسخهای خطا.
نمونه پاسخ خطا
{
"error": "No quotes found for this poet",
"poet": "شاعر نامعلوم",
"suggestion": "Available poets: مولانا, حافظ, سعدی, فردوسی"
}آمادهاید موتور را امتحان کنید؟
به صفحه متریک زنده بروید و عملکرد موتور را در زمان واقعی ببینید. یا فورک کنید و برای پروژه خودتان سفارشیسازی کنید.