حالة 5 + 1 حيث تلعب مواصفات REST API دورًا كبيرًا


ستركز هذه المقالة على كتابة ودعم مواصفات مفيدة وذات صلة لمشروع REST API ، والذي سيوفر الكثير من التعليمات البرمجية الإضافية ، بالإضافة إلى تحسين سلامة وموثوقية وشفافية المشروع ككل بشكل جدي.


ما هي RESTful API؟



هذه خرافة


على محمل الجد ، إذا كنت تعتقد أن مشروعك يحتوي على RESTful API ، فمن شبه المؤكد أنك مخطئ. تتمثل فكرة RESTful في إنشاء واجهة برمجة تطبيقات تتوافق من جميع النواحي مع القواعد والقيود المعمارية التي وصفها أسلوب REST ، ولكن في الظروف الحقيقية يكاد يكون هذا مستحيلًا .


من ناحية ، تحتوي REST على الكثير من التعريفات الغامضة والغامضة. على سبيل المثال ، لا يتم استخدام بعض المصطلحات من قواميس طرق HTTP ورموز الحالة للغرض المقصود في الممارسة العملية ، بينما لا يتم استخدام العديد منها على الإطلاق.


من ناحية أخرى ، تضع REST قيودًا كثيرة جدًا. على سبيل المثال ، الاستخدام الذري للموارد في العالم الحقيقي ليس عقلانيًا لواجهات برمجة التطبيقات التي تستخدمها تطبيقات الجوال. الرفض الكامل لتخزين الحالة بين الطلبات هو في الأساس حظر على آلية جلسات المستخدم المستخدمة في العديد من واجهات برمجة التطبيقات.


لكن انتظر ، ليس كل شيء سيئ للغاية!


لماذا نحتاج إلى مواصفات REST API؟


على الرغم من هذه العيوب ، مع نهج معقول ، لا تزال REST أساسًا ممتازًا لتصميم واجهات برمجة تطبيقات رائعة حقًا. يجب أن يكون لواجهة برمجة التطبيقات هذه التوحيد الداخلي وهيكل واضح وتوثيق ملائم وتغطية اختبار وحدة جيدة. يمكن تحقيق كل هذا من خلال تطوير مواصفات الجودة لواجهة برمجة التطبيقات الخاصة بك.


في أغلب الأحيان ، ترتبط مواصفات REST API بوثائقها. على عكس الخيار الأول (وهو وصف رسمي لواجهة برمجة التطبيقات الخاصة بك) ، فإن القصد من الوثائق أن يقرأها الأشخاص: على سبيل المثال ، مطورو تطبيق جوال أو تطبيق ويب يستخدم API الخاص بك.


ومع ذلك ، بالإضافة إلى إنشاء الوثائق فعليًا ، لا يزال بإمكان وصف واجهة برمجة التطبيقات المناسب تحقيق الكثير من الفوائد. في المقالة ، أريد مشاركة أمثلة عن كيفية استخدام الاستخدام المختص للمواصفات:


  • جعل اختبار الوحدة أبسط وأكثر موثوقية ؛
  • تكوين المعالجة المسبقة والتحقق من صحة بيانات الإدخال ؛
  • أتمتة التسلسل وضمان سلامة الاستجابات ؛
  • وحتى الاستفادة من الكتابة الثابتة.

Openapi



التنسيق المقبول عمومًا لوصف REST API اليوم هو OpenAPI ، والذي يُعرف أيضًا باسم Swagger . هذه المواصفات عبارة عن ملف واحد بتنسيق JSON أو YAML ، ويتكون من ثلاثة أقسام:


  • رأس يحتوي على اسم ووصف وإصدار واجهة برمجة التطبيقات ، بالإضافة إلى معلومات إضافية ؛
  • وصف لجميع الموارد ، بما في ذلك معرفاتها ، وطرق HTTP ، وجميع معلمات الإدخال ، بالإضافة إلى رموز وتنسيقات نص الاستجابة ، مع روابط للتعريفات ؛
  • جميع تعريفات الكائنات بتنسيق JSON Schema والتي يمكن استخدامها في كل من معلمات الإدخال والاستجابات.

لدى OpenAPI عيب خطير - تعقيد الهيكل ، وغالبًا ما يكون التكرار . بالنسبة للمشروع الصغير ، يمكن أن تنمو محتويات ملف JSON للمواصفات بسرعة إلى عدة آلاف من الخطوط. لا يمكن الاحتفاظ بهذا الملف يدويًا في هذا النموذج. يعد هذا تهديدًا خطيرًا لفكرة الحفاظ على المواصفات الحالية مع تطور API.


هناك العديد من برامج التحرير المرئية التي تسمح لك بوصف واجهة برمجة التطبيقات وتكوين مواصفات OpenAPI الناتجة. في المقابل ، تعتمد الخدمات الإضافية والحلول السحابية عليها ، على سبيل المثال ، Swagger و Apiary و Stoplight و Restlet وغيرها.


ومع ذلك ، بالنسبة لي ، لم تكن هذه الخدمات مريحة للغاية نظرًا لصعوبة تعديل المواصفات بسرعة ودمجها مع عملية كتابة التعليمات البرمجية. ناقص آخر هو الاعتماد على مجموعة وظائف كل خدمة معينة. على سبيل المثال ، يكاد يكون من المستحيل تنفيذ اختبار وحدة كاملة عن طريق الخدمة السحابية فقط. إن إنشاء الشفرة وحتى إنشاء "المقابس" لنقاط النهاية ، على الرغم من أنه يبدو ممكنًا جدًا ، من الناحية العملية لا فائدة منه.


Tinyspec


في هذه المقالة ، سأستخدم أمثلة استنادًا إلى تنسيق وصف REST API الأصلي - tinyspec . التنسيق عبارة عن ملفات صغيرة تصف نقاط النهاية ونماذج البيانات المستخدمة في المشروع ببناء بديهي. يتم تخزين الملفات بجوار الكود ، مما يسمح لك بمراجعتها وتحريرها في عملية كتابتها. في الوقت نفسه ، يتم تجميع tinyspec تلقائيًا في OpenAPI متكامل ، والذي يمكن استخدامه على الفور في المشروع. حان الوقت لأخبرك كيف بالضبط.


في هذه المقالة ، سأعطي أمثلة من Node.js (koa ، express) و Ruby on Rails ، على الرغم من أن هذه الممارسات تنطبق على معظم التقنيات ، بما في ذلك Python و PHP و Java.


عندما تكون المواصفات مفيدة للغاية


1. اختبارات الوحدة لنقاط النهاية


يعد التطوير القائم على السلوك (BDD) مثاليًا لتطوير واجهة برمجة تطبيقات REST. الطريقة الأكثر ملاءمة لكتابة اختبارات الوحدة ليست للفصول والنماذج ووحدات التحكم الفردية ، ولكن لنقاط نهاية محددة. في كل اختبار ، تقوم بمحاكاة طلب HTTP حقيقي والتحقق من استجابة الخادم. في Node.js ، لمحاكاة طلبات الاختبار ، هناك supertest و chai-http ، في Ruby on Rails - محمولة جواً .


افترض أن لدينا مخطط GET /users ونقطة نهاية GET /users التي تُرجع جميع المستخدمين. إليك صيغة tinyspec التي تصف هذا:


  1. ملف User.models.tinyspec :

 User {name, isAdmin: b, age?: i} 

  1. ملف المستخدمين. endpoints.tinyspec :

 GET /users => {users: User[]} 

هذه هي الطريقة التي سيبدو بها اختبارنا:


Node.js


 describe('/users', () => { it('List all users', async () => { const { status, body: { users } } = request.get('/users'); expect(status).to.equal(200); expect(users[0].name).to.be('string'); expect(users[0].isAdmin).to.be('boolean'); expect(users[0].age).to.be.oneOf(['boolean', null]); }); }); 

روبي أون ريلز


 describe 'GET /users' do it 'List all users' do get '/users' expect_status(200) expect_json_types('users.*', { name: :string, isAdmin: :boolean, age: :integer_or_null, }) end end 

عندما يكون لدينا مواصفات تصف تنسيقات استجابة الخادم ، يمكننا تبسيط الاختبار والتحقق ببساطة من الاستجابة مقابل هذه المواصفات . للقيام بذلك ، سوف نستفيد من حقيقة أن نماذج tinyspec الخاصة بنا تتحول إلى تعريفات OpenAPI ، والتي تتوافق بدورها مع تنسيق JSON Schema.


يمكن اختبار أي كائن حرفي في JS (أو Hash in Ruby ، ​​وهو dict في Python ، ومجموعة مصاحبة في PHP ، وحتى Map في Java) للتوافق مع مخطط JSON. وهناك أيضًا مكونات إضافية مقابلة لأطر الاختبار ، على سبيل المثال jest-ajv (npm) و chai-ajv-json-schema (npm) و json_matchers (rubygem) لـ RSpec.


قبل استخدام المخططات ، يجب توصيلها بالمشروع. أولاً ، سننشئ ملف مواصفات openapi.json بناءً على tinyspec (يمكن تنفيذ هذا الإجراء تلقائيًا قبل كل تشغيل تجريبي):


 tinyspec -j -o openapi.json 

Node.js


الآن يمكننا استخدام JSON المستلم في المشروع وأخذ مفتاح definitions منه ، والذي يحتوي على جميع مخططات JSON. يمكن أن تحتوي المخططات على إسنادات ترافقية ( $ref ) ، وبالتالي ، إذا كان لدينا مخططات متداخلة (على سبيل المثال ، Blog {posts: Post[]} ) ، فإننا نحتاج إلى "توسيعها" لاستخدامها في عمليات التحقق. للقيام بذلك ، سوف نستخدم json-schema-deref-sync (npm).


 import deref from 'json-schema-deref-sync'; const spec = require('./openapi.json'); const schemas = deref(spec).definitions; describe('/users', () => { it('List all users', async () => { const { status, body: { users } } = request.get('/users'); expect(status).to.equal(200); // Chai expect(users[0]).to.be.validWithSchema(schemas.User); // Jest expect(users[0]).toMatchSchema(schemas.User); }); }); 

روبي أون ريلز


يمكن أن يتعامل json_matchers مع روابط $ref ، ولكنه يتطلب ملفات منفصلة مع مخططات في نظام الملفات بطريقة معينة ، لذلك عليك أولاً "تقسيم" swagger.json إلى العديد من الملفات الصغيرة (المزيد عن هذا هنا ):


 # ./spec/support/json_schemas.rb require 'json' require 'json_matchers/rspec' JsonMatchers.schema_root = 'spec/schemas' # Fix for json_matchers single-file restriction file = File.read 'spec/schemas/openapi.json' swagger = JSON.parse(file, symbolize_names: true) swagger[:definitions].keys.each do |key| File.open("spec/schemas/#{key}.json", 'w') do |f| f.write(JSON.pretty_generate({ '$ref': "swagger.json#/definitions/#{key}" })) end end 

بعد ذلك ، يمكننا كتابة اختبارنا على النحو التالي:


 describe 'GET /users' do it 'List all users' do get '/users' expect_status(200) expect(result[:users][0]).to match_json_schema('User') end end 

ملاحظة: كتابة الاختبارات بهذه الطريقة مريحة للغاية. خاصة إذا كان IDE الخاص بك يدعم تشغيل الاختبارات وتصحيح الأخطاء (مثل WebStorm و RubyMine و Visual Studio). وبالتالي ، لا يمكنك استخدام أي برنامج آخر على الإطلاق ، ويتم تقليل دورة تطوير API بالكامل إلى 3 خطوات متتالية:


  1. تصميم المواصفات (على سبيل المثال في tinyspec) ؛
  2. كتابة مجموعة كاملة من الاختبارات لنقاط النهاية المضافة / المتغيرة ؛
  3. تطوير كود يفي بجميع الاختبارات.

2. التحقق من صحة المدخلات


يصف OpenAPI تنسيق الاستجابات ليس فقط ، ولكن أيضًا إدخال البيانات. هذا يسمح لنا بالتحقق من صحة البيانات الواردة من المستخدم أثناء الطلب.


لنفترض أن لدينا المواصفات التالية التي تصف تحديث بيانات المستخدم ، وكذلك جميع الحقول التي يمكن تغييرها:


 # user.models.tinyspec UserUpdate !{name?, age?: i} # users.endpoints.tinyspec PATCH /users/:id {user: UserUpdate} => {success: b} 

في وقت سابق نظرنا في الإضافات للتحقق من صحتها داخل الاختبارات ، ولكن بالنسبة للحالات الأكثر عمومية هناك وحدات التحقق من ajv (npm) و json-schema (rubygem) ، فلنستخدمها ونكتب وحدة تحكم مع التحقق.


Node.js (Koa)


هذا مثال لـ Koa ، خليفة Express ، ولكن بالنسبة لـ Express ، سيبدو الرمز مشابهًا.


 import Router from 'koa-router'; import Ajv from 'ajv'; import { schemas } from './schemas'; const router = new Router(); // Standard resource update action in Koa. router.patch('/:id', async (ctx) => { const updateData = ctx.body.user; // Validation using JSON schema from API specification. await validate(schemas.UserUpdate, updateData); const user = await User.findById(ctx.params.id); await user.update(updateData); ctx.body = { success: true }; }); async function validate(schema, data) { const ajv = new Ajv(); if (!ajv.validate(schema, data)) { const err = new Error(); err.errors = ajv.errors; throw err; } } 

في هذا المثال ، إذا لم تتوافق بيانات الإدخال مع المواصفات ، 500 Internal Server Error استجابة 500 Internal Server Error للعميل. لمنع حدوث ذلك ، يمكننا اعتراض خطأ المدقق وتشكيل ردنا الخاص ، والذي سيحتوي على معلومات أكثر تفصيلاً حول حقول محددة لم تجتاز الاختبار ، وكذلك الامتثال للمواصفات .


قم بإضافة وصف لنموذج FieldsValidationError في ملف FieldsValidationError :


 Error {error: b, message} InvalidField {name, message} FieldsValidationError < Error {fields: InvalidField[]} 

والآن نشير إليها كإحدى الإجابات المحتملة لنقطة النهاية لدينا:


 PATCH /users/:id {user: UserUpdate} => 200 {success: b} => 422 FieldsValidationError 

سيسمح لك هذا النهج بكتابة اختبارات الوحدة التي تتحقق من صحة تشكيل الأخطاء مع البيانات غير الصحيحة الواردة من العميل.


3. تسلسل النماذج


تستخدم جميع أطر الخادم الحديثة تقريبًا ORM بطريقة أو بأخرى. وهذا يعني أن معظم الموارد المستخدمة في واجهة برمجة التطبيقات داخل النظام يتم تقديمها في شكل نماذج وحالاتها ومجموعاتها.


تسمى عملية إنشاء تمثيل JSON لهذه الكيانات لإرسالها في استجابة API التسلسل . هناك عدد من المكونات الإضافية لأطر العمل المختلفة التي تؤدي وظائف التسلسل ، على سبيل المثال: Sequelize-to-json (npm) و act_as_api (rubygem) و jsonapi-rails (rubygem). في الواقع ، تسمح هذه المكونات الإضافية لنموذج معين بتحديد قائمة الحقول التي يجب تضمينها في كائن JSON ، بالإضافة إلى قواعد إضافية ، على سبيل المثال ، لإعادة تسميتها أو حساب القيم ديناميكيًا.


تبدأ الصعوبات عندما نحتاج إلى العديد من تمثيلات JSON المختلفة لنفس النموذج أو عندما يحتوي كائن على كيانات متداخلة - ارتباطات. هناك حاجة إلى الميراث وإعادة استخدام وربط المتسللين .


تحل الوحدات المختلفة هذه المشكلات بطرق مختلفة ، ولكن دعنا نفكر ، هل يمكن للمواصفات أن تساعدنا مرة أخرى؟ في الواقع ، في الواقع ، جميع المعلومات حول متطلبات تمثيلات JSON ، وكل المجموعات الممكنة من الحقول ، بما في ذلك الكيانات المتداخلة ، موجودة بالفعل فيها. حتى نتمكن من كتابة متسلسل تلقائي.


أوجه انتباهكم إلى وحدة صغيرة لتسلسل تسلسل (npm) ، والتي تتيح لك القيام بذلك لنماذج Sequelize. يأخذ نسخة من النموذج أو الصفيف ، بالإضافة إلى الدائرة المطلوبة ، ويقوم بشكل متكرر ببناء كائن متسلسل ، مع مراعاة جميع الحقول المطلوبة واستخدام الدوائر المتداخلة للكيانات المرتبطة.


لذا ، لنفترض أن لدينا حاجة للعودة من واجهة برمجة التطبيقات لجميع المستخدمين الذين لديهم مشاركات مدونة ، بما في ذلك التعليقات على تلك المشاركات. نصف هذا باستخدام المواصفات التالية:


 # models.tinyspec Comment {authorId: i, message} Post {topic, message, comments?: Comment[]} User {name, isAdmin: b, age?: i} UserWithPosts < User {posts: Post[]} # blogUsers.endpoints.tinyspec GET /blog/users => {users: UserWithPosts[]} 

الآن يمكننا إنشاء الاستعلام باستخدام Sequelize وإرجاع كائن تسلسلي يطابق تمامًا المواصفات الموضحة أعلاه:


 import Router from 'koa-router'; import serialize from 'sequelize-serialize'; import { schemas } from './schemas'; const router = new Router(); router.get('/blog/users', async (ctx) => { const users = await User.findAll({ include: [{ association: User.posts, required: true, include: [Post.comments] }] }); ctx.body = serialize(users, schemas.UserWithPosts); }); 

يكاد يكون السحر ، أليس كذلك؟


4. الكتابة الساكنة


إذا كنت رائعًا لدرجة أنك تستخدم TypeScript أو Flow ، فربما تكون قد تساءلت بالفعل ، "ماذا عن الأنواع الثابتة العزيزة الخاصة بي؟!" . باستخدام sw2dts أو وحدات swagger-to-flowtype ، يمكنك إنشاء جميع التعريفات اللازمة بناءً على مخططات JSON واستخدامها للكتابة الثابتة للاختبارات وبيانات الإدخال والمُسلسلين.


 tinyspec -j sw2dts ./swagger.json -o Api.d.ts --namespace Api 

الآن يمكننا استخدام أنواع في وحدات التحكم:


 router.patch('/users/:id', async (ctx) => { // Specify type for request data object const userData: Api.UserUpdate = ctx.request.body.user; // Run spec validation await validate(schemas.UserUpdate, userData); // Query the database const user = await User.findById(ctx.params.id); await user.update(userData); // Return serialized result const serialized: Api.User = serialize(user, schemas.User); ctx.body = { user: serialized }; }); 

وفي الاختبارات:


 it('Update user', async () => { // Static check for test input data. const updateData: Api.UserUpdate = { name: MODIFIED }; const res = await request.patch('/users/1', { user: updateData }); // Type helper for request response: const user: Api.User = res.body.user; expect(user).to.be.validWithSchema(schemas.User); expect(user).to.containSubset(updateData); }); 

يرجى ملاحظة أنه يمكن استخدام تعريفات النوع التي تم إنشاؤها ليس فقط في مشروع API نفسه ، ولكن أيضًا في مشاريع تطبيقات العميل لوصف أنواع الوظائف التي تعمل فيها API. سوف يسعد مطورو العملاء الزاويون بشكل خاص بهذه الهدية.


5. اكتب تحويل سلسلة الاستعلام


إذا لسبب ما ، تقبل واجهة برمجة التطبيقات الخاصة بك الطلبات باستخدام application/x-www-form-urlencoded نوع MIME application/x-www-form-urlencoded وليس application/json ، application/json نص الطلب كما يلي:


 param1=value&param2=777&param3=false 

الأمر نفسه ينطبق على معلمات الاستعلام (على سبيل المثال ، في طلبات GET). في هذه الحالة ، لن يتمكن خادم الويب من التعرف تلقائيًا على الأنواع - ستكون جميع البيانات في شكل سلاسل ( هنا مناقشة في مستودع وحدة qpm npm) ، لذلك بعد التحليل ستحصل على الكائن التالي:


 { param1: 'value', param2: '777', param3: 'false' } 

في هذه الحالة ، لن يتم التحقق من صحة الطلب وفقًا للمخطط ، مما يعني أنه سيكون من الضروري التحقق يدويًا من أن كل معلمة لديها التنسيق الصحيح وإحضاره إلى النوع المطلوب.


كما قد تعتقد ، يمكن القيام بذلك باستخدام جميع المخططات نفسها من مواصفاتنا. تخيل أن لدينا نقطة نهاية ومخطط كهذا:


 # posts.endpoints.tinyspec GET /posts?PostsQuery # post.models.tinyspec PostsQuery { search, limit: i, offset: i, filter: { isRead: b } } 

فيما يلي مثال على طلب لنقطة النهاية هذه


 GET /posts?search=needle&offset=10&limit=1&filter[isRead]=true 

دعنا نكتب دالة castQuery ، والتي castQuery جميع المعلمات إلى الأنواع الضرورية لنا. سيبدو شيء من هذا القبيل:


 function castQuery(query, schema) { _.mapValues(query, (value, key) => { const { type } = schema.properties[key] || {}; if (!value || !type) { return value; } switch (type) { case 'integer': return parseInt(value, 10); case 'number': return parseFloat(value); case 'boolean': return value !== 'false'; default: return value; } }); } 

يتوفر تنفيذه الأكثر اكتمالًا مع دعم المخططات المتداخلة والمصفوفات والأنواع null في Cast -with-schema (npm). الآن يمكننا استخدامه في الكود الخاص بنا:


 router.get('/posts', async (ctx) => { // Cast parameters to expected types const query = castQuery(ctx.query, schemas.PostsQuery); // Run spec validation await validate(schemas.PostsQuery, query); // Query the database const posts = await Post.search(query); // Return serialized result ctx.body = { posts: serialize(posts, schemas.Post) }; }); 

لاحظ كيفية استخدام الأسطر الأربعة لرمز نقطة النهاية ، مخططات الاستخدام الثلاثة من المواصفات.


أفضل الممارسات


مخططات منفصلة لإنشاء وتعديل


عادةً ما تختلف المخططات التي تصف استجابة الخادم عن تلك التي تصف المدخلات المستخدمة لإنشاء النماذج وتعديلها. على سبيل المثال ، يجب أن تكون قائمة الحقول المتاحة لطلبات POST و PATCH محدودة بشكل صارم ، بينما في طلبات PATCH ، عادةً ما تكون جميع حقول المخطط اختيارية. قد تكون المخططات التي تحدد الإجابة أكثر حرية.


يستخدم الجيل التلقائي لنقاط نهاية tinyspec CRUDL Postfixes الجديدة والتحديثات . يمكن تعريف User* على النحو التالي:


 User {id, email, name, isAdmin: b} UserNew !{email, name} UserUpdate !{email?, name?} 

حاول ألا تستخدم نفس المخططات لأنواع مختلفة من الإجراءات لتجنب مشاكل الأمان العرضية بسبب إعادة استخدام أو وراثة المخططات القديمة.


دلالات في أسماء المخططات


قد تختلف محتويات نفس النماذج في نقاط النهاية المختلفة. استخدم Postfixes With* و For* في أسماء المخططات لتوضيح مدى اختلافها والغرض منها. في نماذج tinyspec يمكن أن تكون موروثة عن بعضها البعض. على سبيل المثال:


 User {name, surname} UserWithPhotos < User {photos: Photo[]} UserForAdmin < User {id, email, lastLoginAt: d} 

يمكن تغيير ودمج Postfixes. الشيء الرئيسي هو أن اسمهم يعكس الجوهر ويبسط الألفة مع التوثيق.


فصل نقاط النهاية حسب نوع العميل


غالبًا ما تُرجع نفس نقاط النهاية بيانات مختلفة اعتمادًا على نوع العميل أو دور المستخدم الذي يصل إلى نقطة النهاية. على سبيل المثال ، يمكن أن تكون نقاط النهاية لـ GET /users و GET /messages مختلفة جدًا لمستخدمي تطبيقات الهاتف المحمول ومديري المكاتب الخلفية. في الوقت نفسه ، يمكن أن يكون تغيير اسم نقطة النهاية بحد ذاته تعقيدًا كبيرًا.


لوصف نفس نقطة النهاية عدة مرات ، يمكنك إضافة نوعها بين قوسين بعد المسار. بالإضافة إلى ذلك ، من المفيد استخدام العلامات: سيساعد هذا على تقسيم وثائق نقاط النهاية الخاصة بك إلى مجموعات ، والتي سيتم تصميم كل منها لمجموعة محددة من عملاء API الخاص بك. على سبيل المثال:


 Mobile app: GET /users (mobile) => UserForMobile[] CRM admin panel: GET /users (admin) => UserForAdmin[] 

وثائق REST API


بمجرد أن يكون لديك مواصفات بتنسيق tinyspec أو OpenAPI ، يمكنك إنشاء وثائق جميلة بتنسيق HTML ونشرها لإسعاد المطورين باستخدام واجهة برمجة التطبيقات الخاصة بك.


بالإضافة إلى الخدمات السحابية المذكورة سابقًا ، هناك أدوات CLI التي تحول OpenAPI 2.0 إلى HTML و PDF ، وبعد ذلك يمكنك تنزيله إلى أي استضافة ثابتة. أمثلة:



هل تعرف المزيد من الأمثلة؟ شاركهم في التعليقات.


لسوء الحظ ، لا يزال OpenAPI 3.0 ، الذي تم إصداره قبل عام ، مدعومًا بشكل سيئ ، ولم أتمكن من العثور على أي أمثلة جديرة بالتوثيق بناءً على ذلك: لا بين حلول السحابة ولا بين أدوات CLI. للسبب نفسه ، لا يتم دعم OpenAPI 3.0 في tinyspec حتى الآن.


نشر إلى جيثب


تعد GitHub Pages من أسهل الطرق لنشر الوثائق. ما عليك سوى تمكين دعم الصفحة الثابتة للدليل /docs في إعدادات المستودع وتخزين وثائق HTML في هذا المجلد.



يمكنك إضافة أمر لإنشاء وثائق من خلال tinyspec أو أداة CLI أخرى في scripts في package.json وتحديث الوثائق مع كل التزام:


 "scripts": { "docs": "tinyspec -h -o docs/", "precommit": "npm run docs" } 

التكامل المستمر


يمكنك تضمين إنشاء الوثائق في دورة CI ونشرها ، على سبيل المثال ، في Amazon S3 تحت عناوين مختلفة اعتمادًا على البيئة أو إصدار API الخاص بك ، على سبيل المثال: /docs/2.0 ، /docs/stable ، /docs/staging .


سحابة Tinyspec


إذا كنت تحب بنية tinyspec ، يمكنك التسجيل كمتبنى مبكر على tinyspec.cloud . سنقوم على أساسها بإنشاء خدمة سحابية و CLI للنشر التلقائي للوثائق مع مجموعة واسعة من القوالب والقدرة على تطوير القوالب الخاصة بنا.


الخلاصة


ربما يكون تطوير واجهة برمجة تطبيقات REST أكثر الأنشطة متعة في كل ما هو موجود في عملية العمل على خدمات الويب والجوال الحديثة. لا توجد حديقة حيوانات للمتصفحات وأنظمة التشغيل وأحجام الشاشة ، كل شيء تحت سيطرتنا تمامًا - "في متناول يدك".


الحفاظ على المواصفات والمكافآت الحالية في شكل أتمتة مختلفة ، والتي يتم توفيرها في نفس الوقت ، تجعل هذه العملية أكثر متعة. تصبح واجهة برمجة التطبيقات هذه منظمة وشفافة وموثوقة.


في الواقع ، حتى لو انخرطنا في خلق أسطورة ، فلماذا لا نجعلها جميلة؟

Source: https://habr.com/ru/post/ar427601/


All Articles