مسارات 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 only) افتراضيًا. يمكنك تخصيص هذا السلوك عن طريق تغليف معالج الطلب بـمساعدات طلب CORS.
- لا يمكن استخدام مسارات API مع التصدير الثابت (static exports). ومع ذلك، يمكن لـمعالجات المسار (Route Handlers) في App Router ذلك.
- ستتأثر مسارات API بـإعدادات
pageExtensions
فيnext.config.js
.
المعاملات
export default function handler(req: NextApiRequest, res: NextApiResponse) {
// ...
}
req
: نسخة من http.IncomingMessageres
: نسخة من 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
.
إحدى حالات الاستخدام لتعطيل bodyParsing
التلقائي هي السماح لك بالتحقق من الجسم الخام لطلب 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 الشاملة. انظر إلى الأمثلة التالية:
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) بدلاً من مسارات API.
توقيع دالة معالجات المسار متساوي الشكل (isomorphic)، مما يعني أنه يمكنك استخدام نفس الوظيفة لكل من Edge و Node.js runtimes.