openapi-typescript لـ TypeScript: دليل شامل مع أمثلة
في تطوير الويب الحديث، تلعب واجهات API دورًا محوريًا، وأصبح توثيقها باستخدام معيار OpenAPI (المعروف سابقًا بـ Swagger) هو المعيار الفعلي. لكن الحفاظ يدويًا على توافق أنواع TypeScript مع مواصفات OpenAPI هو عملية شاقة وعرضة للأخطاء. مكتبة openapi-typescript تحل هذه المشكلة عن طريق توليد أنواع TypeScript صارمة تلقائيًا بناءً على مخطط OpenAPI الخاص بك (الإصداران v3.0 و v3.1).
الهدف الرئيسي للمكتبة هو ضمان التعامل الآمن مع الأنواع (type-safe) عند التفاعل مع API. بدلاً من تعريف الواجهات (interfaces) يدويًا لكل نقطة نهاية (endpoint)، تقوم بتشغيل المُولّد الذي ينشئ ملفًا واحدًا (أو عدة ملفات) يحتوي على أنواع جميع الطلبات والاستجابات والمعاملات والمخططات. هذا لا يوفر الوقت فحسب، بل يضمن أيضًا أن أنواعك متزامنة دائمًا مع أحدث إصدار من API. إذا تغيرت المواصفات، يكفي إعادة توليد الأنواع، وسيشير مترجم TypeScript فورًا إلى أي تباين في الكود.
تُستخدم المكتبة بنشاط في المشاريع التي تكون فيها الموثوقية وسرعة التطوير أمرًا بالغ الأهمية: بدءًا من البنى القائمة على الخدمات المصغرة (microservices) وصولاً إلى تطبيقات الصفحة الواحدة (SPA). وهي تدعم التوليد لكل من الجانب العميل (مثل fetch أو axios) والجانب الخادم (مثل Express أو Fastify). في هذه المقالة، سنشرح بالتفصيل عملية التثبيت، والطرق الأساسية، والأمثلة العملية، والأخطاء الشائعة.
التثبيت
لتثبيت المكتبة، استخدم npm أو yarn. الأمر التالي سيقوم بتثبيت المُولّد والتبعيات الضرورية.
npm install openapi-typescript typescript @types/node --save-dev
أو عبر yarn:
yarn add -D openapi-typescript typescript @types/node
إذا كنت تخطط لاستخدام الأنواع المُولّدة في وقت التشغيل (runtime) (مثل التحقق من الصحة)، فقم بتثبيت openapi-typescript-helpers أيضًا:
npm install openapi-typescript-helpers
بداية سريعة — مثال عملي بسيط
لنفترض أن لديك ملفًا باسم spec.yaml يحتوي على مواصفات OpenAPI. سننشئ سكريبتًا بسيطًا لتوليد الأنواع.
// generate.ts
import { createClient } from 'openapi-typescript';
import * as fs from 'fs';
async function main() {
const spec = fs.readFileSync('./spec.yaml', 'utf-8');
const result = await createClient(spec, { format: 'yaml' });
fs.writeFileSync('./api-types.d.ts', result);
console.log('تم توليد الأنواع في الملف api-types.d.ts');
}
main().catch(console.error);
قم بتشغيل السكريبت:
npx ts-node generate.ts
بعد ذلك، سيظهر في الملف api-types.d.ts جميع الأنواع المطابقة لمواصفاتك. يمكنك الآن استيرادها في مشروعك:
import type { paths, components } from './api-types';
// استخدام نوع خاص بنقطة نهاية معينة
type GetUsersResponse = paths['/users']['get']['responses'][200]['content']['application/json'];
الطرق والوظائف الأساسية
1. createClient(schema: string, options?: ClientOptions): Promise<string>
الوظيفة: الطريقة الرئيسية لتوليد الأنواع. تستقبل نص المواصفات (JSON أو YAML) وتُرجع نص كود TypeScript.
import { createClient } from 'openapi-typescript';
import * as fs from 'fs';
const spec = fs.readFileSync('./spec.json', 'utf-8');
const types = await createClient(spec, { format: 'json' });
fs.writeFileSync('./types.d.ts', types);
2. createClientFromUrl(url: string, options?: ClientOptions): Promise<string>
الوظيفة: تقوم بتحميل المواصفات من عنوان URL بشكل غير متزامن وتوليد الأنواع. مفيدة لـ APIs البعيدة.
import { createClientFromUrl } from 'openapi-typescript';
const types = await createClientFromUrl('https://api.example.com/openapi.json');
console.log(types); // نص كود TypeScript المُولّد
3. createClientFromFile(filePath: string, options?: ClientOptions): Promise<string>
الوظيفة: تقرأ ملف المواصفات من مسار محلي وتقوم بتوليد الأنواع. بديل مناسب لـ createClient عند التعامل مع الملفات.
import { createClientFromFile } from 'openapi-typescript';
const types = await createClientFromFile('./spec.yaml', { format: 'yaml' });
fs.writeFileSync('./types.d.ts', types);
أمثلة عملية متقدمة
مثال 1: استخدام الأنواع المُولّدة مع مكتبة axios
لنفترض أن لدينا نقطة نهاية لجلب المستخدمين. يمكننا استخدام الأنواع المُولّدة لضمان سلامة البيانات:
import axios from 'axios';
import type { paths } from './api-types';
type GetUsersResponse = paths['/users']['get']['responses'][200]['content']['application/json'];
async function fetchUsers(): Promise<GetUsersResponse> {
const response = await axios.get<GetUsersResponse>('/users');
return response.data;
}
// الآن، TypeScript سيتحقق من صحة البيانات المسترجعة
fetchUsers().then(users => {
console.log(users[0].name); // آمن من حيث الأنواع
});
مثال 2: توليد الأنواع لخادم Express
يمكن استخدام المكتبة لتوليد أنواع للخادم أيضًا، مما يضمن تطابق الاستجابات مع المواصفات:
import express from 'express';
import type { paths } from './api-types';
const app = express();
app.get('/users', (req, res) => {
// نوع الاستجابة مستمد من المواصفات
const response: paths['/users']['get']['responses'][200]['content']['application/json'] = [
{ id: 1, name: 'أحمد' }
];
res.json(response);
});
الأخطاء الشائعة وكيفية تجنبها
- تنسيق غير صحيح للمواصفات: تأكد من أن ملف YAML أو JSON صحيح وخالٍ من الأخطاء النحوية. استخدم أدوات التحقق مثل
swagger-cli validate. - عدم تحديث الأنواع بعد تغيير API: قم دائمًا بإعادة تشغيل أمر التوليد بعد أي تعديل على ملف المواصفات. أضف هذا الأمر إلى سكريبتات البناء (build scripts) الخاصة بك.
- تعارض الإصدارات: تأكد من أن إصدار المكتبة متوافق مع إصدار OpenAPI الخاص بك (v3.0 أو v3.1). راجع وثائق المكتبة للحصول على التفاصيل.
- استيراد خاطئ للأنواع: استخدم
import typeبدلاً منimportلتجنب تضمين الأنواع في كود JavaScript النهائي (tree-shaking).
الخلاصة
مكتبة openapi-typescript هي أداة لا غنى عنها لأي مطور TypeScript يعمل مع APIs موثقة بـ OpenAPI. فهي تقلل الأخطاء، توفر الوقت، وتحسن جودة الكود بشكل كبير. من خلال أتمتة عملية توليد الأنواع، يمكنك التركيز على كتابة منطق الأعمال بدلاً من القلق بشأن توافق الأنواع. ابدأ باستخدامها اليوم في مشروعك القادم!