برمجه وتصميم

كيفية إنشاء REST API الأول الخاص بك مع Fastify

اربط هو إطار عمل مصمم لتطوير الويب الخلفي. يوفر بديلاً خفيف الوزن أكثر لأطر Node.js الأثقل ، مثل Hapi و Express. من يوليو 2020 ، أصدرت Fastify نسختها الثالثة من إطار العمل.

يأتي هذا الإصدار الثالث مزودًا بقدرات تحقق محسنة للتحقق من الطلبات الواردة والصادرة ، كمعلمات للطلب. علاوة على ذلك ، يدمج الإصدار الثالث من إطار العمل مطالبات الإنتاجية الخاصة به باعتباره أسرع إطار عمل Node.js مقارنةً بـ Koa و Resitfy و Hapi و Express. يمكن العثور على مزيد من المعلومات على صفحة المعايير.

اكتسب Fastify شعبية كبيرة بسبب تصميمه خفيف الوزن. ومع ذلك ، فإن الكثير من الاهتمام يذهب إليه النظام البيئي للمكوِّن الإضافي. تبنت Fastify فكرة أن كل شيء عبارة عن مكون إضافي ، بينما في JavaScript ، كل شيء هو كائن. يسمح لك هذا بتغليف الوظائف بسرعة لمشروعك كمكوِّن إضافي وتوزيعها بحيث يمكن للمشاريع الأخرى استخدام التعليمات البرمجية الخاصة بك.

لنبدأ بهذا البرنامج التعليمي. ستتعلم الجوانب التالية من Fastify:

  • كيفية إعداد أول Fastify API الخاص بك
  • كيفية تحديد مسارات Fastify API
  • كيفية إضافة التحقق من صحة المخطط للطلبات
  • كيفية تحميل واستخدام ملحقات Fastify
  • كيفية تحديد Fastify hooks

المتطلبات والتثبيت

لمتابعة هذا البرنامج التعليمي ، ستحتاج إلى:

  1. أحدث إصدار من Node.js
  2. أداة لإرسال الطلبات ، مثل لفة أو ساعي البريد

بعد ذلك ، تأكد من إنشاء مشروع Node.js فارغ. إذا لم يكن لديك واحد حتى الآن ، يمكنك استخدام الأمر التالي لإعداد مشروعك:

npm init -y

أخيرًا ، نريد إضافة تبعية Fastify إلى مشروعنا:

npm i fastify --save

الامور جيدة؟ لنقم بإنشاء إعداد API الأساسي الخاص بنا في الخطوة التالية.

الخطوة 1: إعداد API الأساسي

أولاً ، لنقم بإنشاء إعداد API الأساسي الخاص بنا. للبدء ، نحتاج إلى إنشاء ملف جديد يسمى index.js داخل جذر مشروعنا:

touch index.js

بعد ذلك ، دعنا نضيف إعداد الخادم الأساسي. انسخ الكود أدناه:


const app = require('fastify')({
    logger: true
})


app.get("https://www.sitepoint.com/", function (req, reply) {
    reply.send({ hello: 'world' })
})


app.listen(3000, (err, address) => {
    if (err) {
        app.log.error(err)
        process.exit(1)
    }
    app.log.info(`server listening on ${address}`)
})

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

دعنا نتحقق مما إذا كان إعداد الخادم الأساسي الخاص بك يعمل. أولاً ، نحتاج إلى بدء تشغيل الخادم عن طريق تشغيل ملف index.js ملف:

node index.js

بعد ذلك ، انتقل إلى http://localhost:3000 في متصفحك. يجب أن ترى الرد التالي:

{
    "hello": "world"
}

نجاح؟ دعنا ننتقل إلى الخطوة 2 لتحديد مسارات CRUD المختلفة.

الخطوة 2: تحديد مسارات CRUD

API عديم الفائدة مع مسارات GET فقط. دعنا نحدد المزيد من الطرق للتعامل مع المدونات. لذلك ، دعنا ننشئ المسارات التالية:

  • احصل على جميع المدونات على / api / blogs
  • احصل على مدونة واحدة على / api / blogs /: id
  • أضف مدونة في / api / blogs
  • تحديث مدونة PUT في / api / blogs /: id
  • احذف حذف المدونة من / api / blogs /: id

أول شيء يجب فعله هو إنشاء وحدة تحكم في المدونة.

الخطوة 2.1: إنشاء وحدة تحكم المدونات

للحفاظ على الكود الخاص بنا نظيفًا ، دعنا نحدد ملف controller مجلد في جذر المشروع. هنا ، نقوم بإنشاء ملف يسمى blogs.js.

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

علاوة على ذلك ، نحدد المعالجات المختلفة لجميع المسارات المذكورة أعلاه في هذا الملف. المعالِج يقبل دائمًا ملف req (طلب) و reply معامل. معلمة الطلب مفيدة للوصول إلى معلمات الطلب أو طلب بيانات الجسم.

أضف الكود التالي إلى ملف /controller/blogs.js ملف:


let blogs = [
    {
        id: 1,
        title: 'This is an experiment'
    },
    {
        id: 2,
        title: 'Fastify is pretty cool'
    },
    {
        id: 3,
        title: 'Just another blog, yea!'
    }
]


const getAllBlogs = async (req, reply) => {
    return blogs
}

const getBlog = async (req, reply) => {
    const id = Number(req.params.id) 
    const blog = blogs.find(blog => blog.id === id)
    return blog
}

const addBlog = async (req, reply) => {
    const id = blogs.length + 1 
    const newBlog = {
        id,
        title: req.body.title
    }

    blogs.push(newBlog)
    return newBlog
}

const updateBlog = async (req, reply) => {
    const id = Number(req.params.id)
    blogs = blogs.map(blog => {
        if (blog.id === id) {
            return {
                id,
                title: req.body.title
            }
        }
    })

    return {
        id,
        title: req.body.title
    }
}

const deleteBlog = async (req, reply) => {
    const id = Number(req.params.id)

    blogs = blogs.filter(blog => blog.id !== id)
    return { msg: `Blog with ID ${id} is deleted` }
}

module.exports = {
    getAllBlogs,
    getBlog,
    addBlog,
    updateBlog,
    deleteBlog
}

لاحظ كيف يمكننا الوصول إلى معلمة الطلب لمسارات مثل /api/blogs/:id عبر req.params.id. بالنسبة إلى مسارات POST و PUT ، يمكننا الوصول إلى نص الطلب عبر req.body.

في الخطوة 2.2 ، سنقوم بتوصيل معالجات المسار بكائنات المسار.

الخطوة 2.2: تحديد مسارات المدونة ووحدة تحكم مدونات الزوجين

مرة أخرى ، للحفاظ على نظافة الكود الخاص بنا ، دعنا نحدد ملف routes مجلد في جذر المشروع. هنا ، نقوم بإنشاء ملف يسمى blogs.js. يحتوي هذا الملف على كائن المسارات لمسارات مدونتنا:

mkdir routes
cd routes
touch blogs.js

لحسن الحظ ، يتيح لنا Fastify تحديد مصفوفة تحتوي على كائنات مسار. هنا ، يمكننا ربط المعالجات التي حددناها مسبقًا بالمسارات المختلفة. لا تنس أن تطلب وحدة تحكم المدونات. لنلقي نظرة:

const blogController = require('../controller/blogs');

const routes = [{
        method: 'GET',
        url: '/api/blogs',
        handler: blogController.getAllBlogs
    },
    {
        method: 'GET',
        url: '/api/blogs/:id',
        handler: blogController.getBlog
    },
    {
        method: 'POST',
        url: '/api/blogs',
        handler: blogController.addBlog
    },
    {
        method: 'PUT',
        url: '/api/blogs/:id',
        handler: blogController.updateBlog
    },
    {
        method: 'DELETE',
        url: '/api/blogs/:id',
        handler: blogController.deleteBlog
    }
]
module.exports = routes

الآن قمنا بتعريف جميع المسارات. ومع ذلك ، لا يعرف Fastify عن هذه المسارات. توضح الخطوة التالية كيف يمكنك تسجيل المسارات باستخدام كائن تطبيق Fastify الخاص بك.

الخطوة 2.3: تسجيل Fastify Routes

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


const app = require('fastify')({
    logger: true
})


app.get("https://www.sitepoint.com/", function (req, reply) {
    reply.send({ hello: 'world' })
})


const blogRoutes = require('./routes/blogs')
blogRoutes.forEach((route, index) => {
    app.route(route)
})


app.listen(3000, (err, address) => {
    if (err) {
        app.log.error(err)
        process.exit(1)
    }
    app.log.info(`server listening on ${address}`)
})

منجز؟ حان الوقت للتحقق مما إذا كانت مسارات المدونة تعمل. تدور الخادم باستخدام node index.js وزيارة http://localhost:3000/blogs/1 للحصول على أول مدونة من البيانات التجريبية. يجب أن ترى النتيجة التالية:

{
    "id": 1,
    "title": "This is an experiment"
}

الامور جيدة؟ دعنا نتعلم في الخطوة 3 كيفية إضافة التحقق من صحة المخطط للطلبات والاستجابات.

الخطوة 3: إضافة التحقق من صحة المخطط

تعلمك هذه الخطوة كيفية إضافة التحقق من صحة المخطط إلى مشروعك. يمكننا الاستفادة من schema مفتاح في لدينا routes تعريف لتمرير مخطط التحقق من الصحة إلى مسار معين.

لنبدأ بتحديد مخطط للمسار /api/blogs/:id للتحقق من صحة معلمة الطلب والاستجابة. المتطلبات؟

  1. :id يجب أن تكون المعلمة من نوع السلسلة
  2. يجب أن تحتوي الاستجابة على كائن بخاصيتين id (عدد صحيح) و title (خيط)

أضف كائن التحقق التالي إلى ملف routes/blogs.js ملف:

const getBlogValidation = {
        params: {
            id: { type: 'string' }
        },
        response: {
            200: {
                type: 'object',
                properties: {
                    id: { type: 'integer' },
                    title: { type: 'string' }
                }
            }
        }
}

لربط كائن التحقق بطريقنا ، يتعين علينا تحديد مفتاح المخطط. بحث عن /api/blogs/:id الطريق في routes صفيف وقم بتغيير الكائن وفقًا لذلك:

...
{
    method: 'GET',
    url: '/api/blogs/:id',
    schema: getBlogValidation, 
    handler: blogController.getBlog
},
...

لنفعل الشيء نفسه لإضافة مدونة POST /api/blogs. هنا ، نريد التحقق مما إذا كان req.body الكائن يحتوي على title معامل. لنلقي نظرة:

const addBlogValidation = {
    body: {
        type: 'object',
        required: [
            'title'
        ],
        properties: {
            title: { type: 'string' }
        }
    },
    response: {
        200: {
            type: 'object',
            properties: {
                id: { type: 'integer' },
                title: { type: 'string' }
            }
        }
    }
}

بعد ذلك ، يتعين علينا توصيل كائن التحقق مرة أخرى بالمسار الصحيح:

...
{
    method: 'POST',
    url: '/api/blogs',
    schema: addBlogValidation, 
    handler: blogController.addBlog
},
...

للتحقق من صحة موقعنا ، دعنا نسترجع المدونة بالمعرف 3. افتح المتصفح الخاص بك على http://localhost:3000/api/blogs/3. يجب أن ترى الرد التالي:

{
    "id": 3,
    "title": "Just another blog, yea!"
}

الآن ، دعنا نخطئ ونغير ملف params التحقق من صحة id مجال من sting إلى object مثل ذلك:

const getBlogValidation = {
        params: {
            id: { type: 'object' } 
        },
        response: {
            200: {
                type: 'object',
                properties: {
                    id: { type: 'integer' },
                    title: { type: 'string' }
                }
            }
        }
}

عند طلب نفس المورد من API الخاص بك ، سوف تتلقى رسالة الخطأ التالية.

{
    "statusCode": 400,
    "error": "Bad Request",
    "message": "params.id should be object"
}

هل ترى الخطأ؟ حسن! لنعد التغيير إلى string لتجنب الأخطاء المستقبلية والانتقال إلى الخطوة التالية.

الخطوة 4: تحميل Fastify Plugins

هنا ، دعنا نستفيد من Fastify’s rich النظام البيئي للمكوِّن الإضافي. يمكنك العثور على المكونات الإضافية التي تساعدك في العديد من المهام ، مثل تكامل قاعدة البيانات أو إعدادات التفويض. لماذا تقضي وقتًا في كتابة الإذن من البداية بينما يمكنك الاستفادة من مكونات Fastify الإضافية؟ غالبًا ما تريد البحث عن حزم خارج النظام البيئي لـ Fastify والتي تساعدك في حل مشكلات أو مهام معينة. ومع ذلك ، من خلال توفير نظام مكوّن إضافي غني ، يصبح Fastify حلاً شاملاً يعمل بالتأكيد على تحسين تجربة المطور!

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

حسنًا ، لنكن عمليين! أود استخدام ملف fastify- البيئة البرنامج المساعد ، الذي يساعدك في تحميل متغيرات البيئة وتعيين الإعدادات الافتراضية لكل متغير. لذلك ، دعنا نضيف هذه التبعية إلى مشروعنا:

npm install --save fastify-env

بعد ذلك ، يمكننا تحميل التبعية بعد تحميل كائن تطبيق Fastify في ملف index.js ملف. الخاص بك index.js الملف يبدو كالتالي:


const app = require('fastify')({
    logger: true
})


const fastifyEnv = require('fastify-env') 

const options = {
    confKey: 'config', 
    schema: {
        type: 'object',
        required: ['PORT'],
        properties: {
            PORT: {
                type: 'string',
                default: 1000
            }
        }
    }
}

app
    .register(fastifyEnv, options)
    .ready((err) => {
        if (err) console.error(err)

        console.log(app.config)
        
    })


app.get("https://www.sitepoint.com/", function (req, reply) {
    reply.send({ hello: 'world' })
})


const blogRoutes = require('./routes/blogs')
blogRoutes.forEach((route, index) => {
    app.route(route)
})


app.listen(app.config.PORT, (err, address) => {
    if (err) {
        app.log.error(err)
        process.exit(1)
    }
    app.log.info(`server listening on ${address}`)
})

لاحظ أنه يتعين علينا تحديد ملف options الكائن الذي يخبر المكون الإضافي fastify-env ما هي متغيرات env التي يجب البحث عنها وأيها يجب تعيينها. هنا ، أريد تحميل ملف PORT متغير بقيمة افتراضية 1000.

بشكل افتراضي ، سيجعل المكون الإضافي fastify-env جميع متغيرات البيئة متاحة عبر كائن تطبيق Fastify مثل: app.config.PORT. لماذا ا؟ يرفق المكون الإضافي fastify-env التكوينات المحملة بملف confKey، والذي يتم تعيينه افتراضيًا على config. ومع ذلك ، إذا كنت ترغب في ذلك ، يمكنك تغيير هذا إلى مفتاح آخر.

ابدأ المشروع بـ node index.js ومراقبة الإخراج. يجب أن تشاهد ملف PORT متغير يتم طباعته في جهازك.

ملحقات أخرى مثيرة للاهتمام لاستخدامها؟

  1. fastify- المصادقة: قم بتشغيل وظائف مصادقة متعددة في Fastify
  2. fastify- حامل- المصادقة: حامل المصادقة الإضافي لـ Fastify
  3. fastify- التخزين المؤقت: ذاكرة التخزين المؤقت العامة من جانب الخادم ودعم etag
  4. fastify- كورس: يتيح استخدام CORS في تطبيق Fastify

الخطوة 5: تحديد الخطافات

أخيرًا ، دعنا نحدد بعض الخطافات. من Fastify هوكس الوثائق، يمكننا قراءة ما يلي. “يتم تسجيل الخطافات باستخدام طريقة fastify.addHook وتسمح لك بالاستماع إلى أحداث معينة في التطبيق أو دورة حياة الطلب / الاستجابة. يجب عليك تسجيل خطاف قبل بدء الحدث ، وإلا فسيتم فقد الحدث “.

تأكد من تحديد الخطافات قبل تحديد أي مسارات:


app.addHook('onRoute', (routeOptions) => {
    console.log(`Registered route: ${routeOptions.url}`)
})


app.get("https://www.sitepoint.com/", function (req, reply) {
    reply.send({ hello: 'world' })
})

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

تفاصيل محددة لـ onRoute صنارة صيد يمكن العثور عليها في الوثائق.

لنبدأ API بـ node index.js لمعرفة الطرق التي تم تسجيلها. يجب أن يبدو الإخراج الطرفي كما يلي:

Registered route: /
Registered route: /api/blogs
Registered route: /api/blogs/:id
Registered route: /api/blogs
Registered route: /api/blogs/:id
Registered route: /api/blogs/:id

حصلت على نفس الناتج؟ نجاح! في نفس الوقت ، كانت هذه نهاية البرنامج التعليمي Fastify. لننهي هذا المشروع بخاتمة قصيرة.

تغليف

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

أنا شخصياً أحب وظيفة Fastify hooks حيث يمكنك الاستماع إلى أحداث دورة الحياة المختلفة داخل تطبيقك.

لمعرفة المزيد حول Fastify ، تحقق من صفحات التوثيق التالية:

يمكنك أيضًا التحقق من الريبو لهذه المقدمة على جيثب.

المصدر

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

زر الذهاب إلى الأعلى