تحقّق من البيانات عند حدود واجهة برمجة التطبيقات (API) ومركِز معالجة الأخطاء كلها في برمجية وسيطة واحدة ذات أربعة وسائط.
افتح هذا الدرس في Kodokonكل بيانات واردة عدائية حتى يثبت العكس: جسم JSON، ومعاملات URL، والترويسات (headers). ينتمي التحقق إلى حدود التطبيق - قبل المتحكم - حتى تعمل الطبقات الداخلية على بيانات مضمونة. ثم ميّز بين عائلتين من الأخطاء: الأخطاء التشغيلية (مُدخَل غير صالح، أو مورد مفقود، أو تعارض)، وهي متوقعة وتُترجَم إلى 4xx، وأخطاء البرمجة (العلل bugs)، التي يجب أن تُنتِج خطأ 500 مبهمًا في جانب العميل وتتبُّعًا كاملًا للمكدس في جانب الخادم.
export class HttpError extends Error {
constructor(status, message, details = undefined) {
super(message);
this.status = status;
this.details = details;
}
}تعترض برمجية وسيطة للتحقق الطلبَ قبل المتحكم. تُظهِر النسخة اليدوية أدناه المبدأ؛ وفي بيئة الإنتاج، يوفّر مخطط تصريحي (أصبح zod هو المعيار) إضافةً إلى ذلك استنتاج الأنواع ورسائل منظّمة. والمقايضة: تبعية واحدة وتكلفة طفيفة أثناء التشغيل، مقابل قواعد مركزية قابلة للتركيب يستحيل نسيانها.
import { HttpError } from './http-error.js';
export function validateUser(req, res, next) {
const { email, name } = req.body ?? {};
const errors = [];
if (typeof email !== 'string' || !email.includes('@')) {
errors.push('email: invalid format');
}
if (typeof name !== 'string' || name.trim().length < 2) {
errors.push('name: 2 characters minimum');
}
if (errors.length > 0) {
return next(new HttpError(400, 'Invalid body', errors));
}
next();
}يتعرّف Express على برمجية وسيطة للأخطاء من خلال توقيعها ذي الأربعة وسائط (err, req, res, next). وإذ تُسجَّل أخيرًا، بعد كل المسارات باستخدام app.use(errorHandler)، تصبح مخرج الأخطاء الوحيد لواجهة برمجة التطبيقات (API): تنسيق استجابة متجانس، وتسجيل في مكان واحد، ودون تسريب أيّ معلومات داخلية. أما المتحكمات، من جهتها، فتكتفي باستدعاء next(err).
export function errorHandler(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
const status = err.status ?? 500;
const body = { error: err.message };
if (err.details) {
body.details = err.details;
}
if (status >= 500) {
console.error(err);
body.error = 'Internal server error';
}
res.status(status).json(body);
}