مسارات API
أمثلة
معلومة مفيدة: إذا كنت تستخدم App Router، يمكنك استخدام مكونات الخادم (Server Components) أو معالجات المسار (Route Handlers) بدلاً من مسارات API.
توفر مسارات API حلاً لبناء واجهة برمجة تطبيقات عامة (public API) باستخدام Next.js.
أي ملف داخل مجلد pages/api
يتم تعيينه إلى /api/*
وسيتم التعامل معه كنقطة نهاية API بدلاً من صفحة
. هذه الملفات تعمل فقط على جانب الخادم ولا تزيد من حجم حزمة جانب العميل.
على سبيل المثال، مسار API التالي يعيد استجابة JSON برمز حالة 200
:
import type { NextApiRequest, NextApiResponse } from 'next'
type ResponseData = {
message: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
export default function handler(req, res) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
معلومة مفيدة:
- مسارات API لا تحدد رؤوس CORS، مما يعني أنها تعمل فقط من نفس المصدر (same-origin) افتراضيًا. يمكنك تخصيص هذا السلوك عن طريق تغليف معالج الطلب بـمساعدات طلب CORS.
- لا يمكن استخدام مسارات API مع التصدير الثابت (static exports). ومع ذلك، يمكن لـمعالجات المسار (Route Handlers) في App Router ذلك.
- ستتأثر مسارات API بـإعداد
pageExtensions
فيnext.config.js
.
المعاملات
export default function handler(req: NextApiRequest, res: NextApiResponse) {
// ...
}
req
: نسخة من http.IncomingMessage، بالإضافة إلى بعض الوسائط المدمجة مسبقًاres
: نسخة من http.ServerResponse، بالإضافة إلى بعض وظائف المساعدة
طرق HTTP
للتعامل مع طرق HTTP المختلفة في مسار API، يمكنك استخدام req.method
في معالج الطلب الخاص بك، كما يلي:
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
// معالجة طلب POST
} else {
// التعامل مع أي طريقة HTTP أخرى
}
}
export default function handler(req, res) {
if (req.method === 'POST') {
// معالجة طلب POST
} else {
// التعامل مع أي طريقة HTTP أخرى
}
}
مساعدات الطلب
توفر مسارات API مساعدات طلب مدمجة تقوم بتحليل الطلب الوارد (req
):
req.cookies
- كائن يحتوي على الكوكيز المرسلة مع الطلب. القيمة الافتراضية{}
req.query
- كائن يحتوي على سلسلة الاستعلام (query string). القيمة الافتراضية{}
req.body
- كائن يحتوي على الجسم الذي تم تحليله حسبcontent-type
، أوnull
إذا لم يتم إرسال جسم
التكوين المخصص
يمكن لكل مسار API تصدير كائن config
لتغيير التكوين الافتراضي، وهو كما يلي:
export const config = {
api: {
bodyParser: {
sizeLimit: '1mb',
},
},
// يحدد المدة القصوى المسموح بها لتنفيذ هذه الوظيفة (بالثواني)
maxDuration: 5,
}
bodyParser
مفعل تلقائيًا. إذا كنت تريد استهلاك الجسم كـ Stream
أو مع raw-body
، يمكنك تعيين هذا إلى false
.
إحدى حالات الاستخدام لتعطيل bodyParser
التلقائي هي السماح لك بالتحقق من الجسم الخام لطلب webhook، على سبيل المثال من GitHub.
export const config = {
api: {
bodyParser: false,
},
}
bodyParser.sizeLimit
هو الحد الأقصى للحجم المسموح به للجسم الذي تم تحليله، بأي تنسيق مدعوم من قبل bytes، كما يلي:
export const config = {
api: {
bodyParser: {
sizeLimit: '500kb',
},
},
}
externalResolver
هو علم صريح يخبر الخادم أن هذا المسار يتم معالجته بواسطة محلل خارجي مثل express أو connect. تفعيل هذا الخيار يعطل التحذيرات للطلبات غير المحلولة.
export const config = {
api: {
externalResolver: true,
},
}
responseLimit
مفعل تلقائيًا، ويظهر تحذيرًا عندما يتجاوز حجم استجابة مسارات API 4MB.
إذا كنت لا تستخدم Next.js في بيئة بدون خادم (serverless)، وتفهم الآثار المترتبة على الأداء لعدم استخدام CDN أو مضيف وسائط مخصص، يمكنك تعيين هذا الحد إلى false
.
export const config = {
api: {
responseLimit: false,
},
}
يمكن أن يأخذ responseLimit
أيضًا عدد البايتات أو أي تنسيق سلسلة مدعوم من bytes
، على سبيل المثال 1000
، '500kb'
أو '3mb'
.
ستكون هذه القيمة هي الحد الأقصى لحجم الاستجابة قبل عرض تحذير. القيمة الافتراضية هي 4MB. (انظر أعلاه)
export const config = {
api: {
responseLimit: '8mb',
},
}
مساعدات الاستجابة
كائن استجابة الخادم (Server Response)، (غالبًا ما يختصر بـ res
) يتضمن مجموعة من طرق المساعدة المشابهة لـ Express.js لتحسين تجربة المطور وزيادة سرعة إنشاء نقاط نهاية API جديدة.
تشمل وظائف المساعدة:
res.status(code)
- دالة لتعيين رمز الحالة. يجب أن يكونcode
رمز حالة HTTP صالحًاres.json(body)
- إرسال استجابة JSON. يجب أن يكونbody
كائنًا قابلًا للتسلسلres.send(body)
- إرسال استجابة HTTP. يمكن أن يكونbody
سلسلة
،كائن
أوBuffer
res.redirect([status,] path)
- إعادة التوجيه إلى مسار أو عنوان URL محدد. يجب أن يكونstatus
رمز حالة HTTP صالحًا. إذا لم يتم تحديده، فإنstatus
يكون افتراضيًا "307" "إعادة توجيه مؤقتة".res.revalidate(urlPath)
- إعادة التحقق من صفحة عند الطلب باستخدامgetStaticProps
. يجب أن يكونurlPath
سلسلة
.
تعيين رمز حالة الاستجابة
عند إرسال استجابة إلى العميل، يمكنك تعيين رمز حالة الاستجابة.
يضبط المثال التالي رمز حالة الاستجابة على 200
(OK
) ويعيد خاصية message
بقيمة Hello from Next.js!
كاستجابة JSON:
import type { NextApiRequest, NextApiResponse } from 'next'
type ResponseData = {
message: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
export default function handler(req, res) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
إرسال استجابة JSON
عند إرسال استجابة إلى العميل يمكنك إرسال استجابة JSON، ويجب أن يكون هذا كائنًا قابلًا للتسلسل. في تطبيق حقيقي، قد ترغب في إعلام العميل بحالة الطلب بناءً على نتيجة نقطة النهاية المطلوبة.
يرسل المثال التالي استجابة JSON برمز الحالة 200
(OK
) ونتيجة العملية غير المتزامنة. يتم تضمينها في كتلة try catch للتعامل مع أي أخطاء قد تحدث، مع رمز الحالة المناسب ورسالة الخطأ التي يتم التقاطها وإرسالها مرة أخرى إلى العميل:
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const result = await someAsyncOperation()
res.status(200).json({ result })
} catch (err) {
res.status(500).json({ error: 'failed to load data' })
}
}
export default async function handler(req, res) {
try {
const result = await someAsyncOperation()
res.status(200).json({ result })
} catch (err) {
res.status(500).json({ error: 'failed to load data' })
}
}
إرسال استجابة HTTP
يعمل إرسال استجابة HTTP بنفس الطريقة عند إرسال استجابة JSON. الفرق الوحيد هو أن جسم الاستجابة يمكن أن يكون سلسلة
، كائن
أو Buffer
.
يرسل المثال التالي استجابة HTTP برمز الحالة 200
(OK
) ونتيجة العملية غير المتزامنة.
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const result = await someAsyncOperation()
res.status(200).send({ result })
} catch (err) {
res.status(500).send({ error: 'failed to fetch data' })
}
}
export default async function handler(req, res) {
try {
const result = await someAsyncOperation()
res.status(200).send({ result })
} catch (err) {
res.status(500).send({ error: 'failed to fetch data' })
}
}
إعادة التوجيه إلى مسار أو عنوان URL محدد
على سبيل المثال نموذج، قد ترغب في إعادة توجيه عميلك إلى مسار أو عنوان URL محدد بمجرد تقديمهم للنموذج.
يعيد المثال التالي توجيه العميل إلى المسار /
إذا تم تقديم النموذج بنجاح:
import type { NextApiRequest, NextApiResponse } from 'next'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const { name, message } = req.body
try {
await handleFormInputAsync({ name, message })
res.redirect(307, '/')
} catch (err) {
res.status(500).send({ error: 'Failed to fetch data' })
}
}
export default async function handler(req, res) {
const { name, message } = req.body
try {
await handleFormInputAsync({ name, message })
res.redirect(307, '/')
} catch (err) {
res.status(500).send({ error: 'failed to fetch data' })
}
}
إضافة أنواع TypeScript
يمكنك جعل مسارات API أكثر أمانًا من الناحية النوعية عن طريق استيراد أنواع NextApiRequest
و NextApiResponse
من next
، بالإضافة إلى ذلك، يمكنك أيضًا كتابة بيانات الاستجابة الخاصة بك:
import type { NextApiRequest, NextApiResponse } from 'next'
type ResponseData = {
message: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
معلومة مفيدة: جسم
NextApiRequest
هوany
لأن العميل قد يتضمن أي حمولة. يجب عليك التحقق من نوع/شكل الجسم في وقت التشغيل قبل استخدامه.
مسارات API الديناميكية
تدعم مسارات API المسارات الديناميكية، وتتبع نفس قواعد تسمية الملفات المستخدمة لـ pages/
.
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const { pid } = req.query
res.end(`Post: ${pid}`)
}
export default function handler(req, res) {
const { pid } = req.query
res.end(`Post: ${pid}`)
}
الآن، سيستجيب الطلب إلى /api/post/abc
بالنص: Post: abc
.
مسارات API الشاملة
يمكن توسيع مسارات API لالتقاط جميع المسارات عن طريق إضافة ثلاث نقاط (...
) داخل الأقواس. على سبيل المثال:
pages/api/post/[...slug].js
تطابق/api/post/a
، ولكن أيضًا/api/post/a/b
،/api/post/a/b/c
وهكذا.
معلومة مفيدة: يمكنك استخدام أسماء أخرى غير
slug
، مثل:[...param]
سيتم إرسال المعاملات المطابقة كمعامل استعلام (slug
في المثال) إلى الصفحة، وسيكون دائمًا مصفوفة، لذا فإن المسار /api/post/a
سيكون له كائن query
التالي:
{ "slug": ["a"] }
وفي حالة /api/post/a/b
، وأي مسار مطابق آخر، ستتم إضافة معاملات جديدة إلى المصفوفة، كما يلي:
{ "slug": ["a", "b"] }
على سبيل المثال:
import type { NextApiRequest, NextApiResponse } from 'next'
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const { slug } = req.query
res.end(`Post: ${slug.join(', ')}`)
}
export default function handler(req, res) {
const { slug } = req.query
res.end(`Post: ${slug.join(', ')}`)
}
الآن، سيستجيب الطلب إلى /api/post/a/b/c
بالنص: Post: a, b, c
.
مسارات API الشاملة الاختيارية
يمكن جعل المسارات الشاملة اختيارية عن طريق تضمين المعامل في أقواس مزدوجة ([[...slug]]
).
على سبيل المثال، pages/api/post/[[...slug]].js
ستطابق /api/post
، /api/post/a
، /api/post/a/b
، وهكذا.
الفرق الرئيسي بين المسارات الشاملة والاختيارية هو أن المسارات الاختيارية تطابق أيضًا المسار بدون المعامل (/api/post
في المثال أعلاه).
كائنات query
هي كما يلي:
{ } // GET `/api/post` (كائن فارغ)
{ "slug": ["a"] } // `GET /api/post/a` (مصفوفة بعنصر واحد)
{ "slug": ["a", "b"] } // `GET /api/post/a/b` (مصفوفة متعددة العناصر)
محاذير
- تأخذ مسارات API المحددة مسبقًا الأسبقية على مسارات API الديناميكية، ومسارات API الديناميكية تأخذ الأسبقية على مسارات API الشاملة. انظر إلى الأمثلة التالية:
pages/api/post/create.js
- ستطابق/api/post/create
pages/api/post/[pid].js
- ستطابق/api/post/1
،/api/post/abc
، إلخ. ولكن ليس/api/post/create
pages/api/post/[...slug].js
- ستطابق/api/post/1/2
،/api/post/a/b/c
، إلخ. ولكن ليس/api/post/create
،/api/post/abc
مسارات API على الحافة (Edge)
إذا كنت ترغب في استخدام مسارات API مع Edge Runtime، نوصي بتبني App Router تدريجيًا واستخدام معالجات المسار (Route Handlers) بدلاً من ذلك.
توقيع دالة معالجات المسار متساوي الشكل (isomorphic)، مما يعني أنه يمكنك استخدام نفس الوظيفة لكل من Edge و Node.js runtimes.