اذهب إلى المحتوى

عبد المجيد شرفاوي

الأعضاء
  • المساهمات

    11
  • تاريخ الانضمام

  • تاريخ آخر زيارة

2 متابعين

المعلومات الشخصية

  • النبذة الشخصية
    عبد المجيد شرفاوي، مطور نظم خلفية Backend Developer، مهتم بالبرمجة عموما، ريادة الأعمال والتعليم الإلكتروني.
  • الموقع

آخر الزوار

3494 زيارة للملف الشخصي

إنجازات عبد المجيد شرفاوي

عضو مساهم

عضو مساهم (2/3)

14

السمعة بالموقع

1

إجابات الأسئلة

  1. بعد أن غطينا معظم ما يتعلق بالواجهات البرمجية وكيفية عملها، مرورًا بالتعرف على الواجهة البرمجية لمنصة زد، سنعمل على بناء تطبيق يتصل بالواجهة البرمجية لمنصة زد ويوسع من عمل المتاجر المبنية بتلك المنصة بإضافة ميزة لها وهي زيادة المبيعات بزيادة الاحتفاظ العملاء وكسب ولائهم. هذا المقال هو جزء من سلسلة مقالات حول الواجهة البرمجية API وكيفية الاستفادة منها في بناء تطبيق ويب: مدخل إلى الواجهات البرمجية API الاتصال بواجهة زد البرمجية وفهم عملية الاستيثاق والتصريح أمثلة عملية لاستخدام واجهة برمجة متاجر زد zid API تطوير تطبيق عملي يزيد من احتفاظ العملاء عبر واجهة زد البرمجية فكرة التطبيق فكرة التطبيق سهلة وبسيطة، بحيث سنستخدم نقطة الوصول الخاصة بسلات الشراء المتروكة لاستعراض العملاء الذين تركوا سلة ما دون إتمام عملية الشراء لمتجر ما ومن ثم سنولد عبر نقطة وصول القسائم قسيمة تخفيض Coupons ونرسلها عبر البريد اﻹلكتروني للعملاء لحضهم على استعمال قسيمة التخفيض وإتمام عملية الشراء. يُحدد المتجر بالمفتاح X-Manager-Token الذي سيزودنا به صاحب المتجر الذي يريد الاستفادة من هذا التطبيق وسنستعمل مفتاح متجر تجريبي أثناء عملية التطوير. سيكون بإمكانك استغلال هذا التطبيق وبناء منصة متكاملة لزيادة عملاء متاجر زد الإلكترونية، وبالتالي زيادة المداخيل السلبية Passive Income لأصحاب المتاجر، الأمر الذي يحقق الفائدة والنفع لهم. المتطلبات المسبقة لبناء التطبيق سنبني التطبيق باستخدام تقنية NodeJS كنظام خلفي Backend، مع واجهة مستخدم بسيطة تكفينا فقط ﻻستخدام سهل وسلس للتطبيق، وسنبني التطبيق باستخدام محرك القوالب Template Engine المعروف باسم Pug. يُفترض أن لديك معرفةً مسبقةً ولو قليلةً بالبرمجة باستخدام NodeJS وإطار العمل ExpressJS لهذا لن نتطرق إلى شرحهما. يمكنك استخدام مدير الحزم Package Manager الذي تفضله سواءً NPM أو YARN، سأستخدم YARN في هذا المشروع. تهيئة المشروع لبداية مشروع جديد، يكفي أن تفتح سطر أوامر وتكتب الأمر التالي: yarn init سيسألك مدير الحزم عن معلومات التطبيق الذي تريد إنشاؤه، يكفي أن تجيب بالقبول عن كل الأسئلة دون تعديل. بعدها، سينشئ مدير الحزم ملفًا باسم package.json بهذا المحتوى: { "name": "zid", "version": "1.0.0", "main": "index.js", "license": "MIT" } الآن سنثبت عددًا من الإضافات اللازمة لعمل التطبيق بصورة طبيعية، وسنبدأ بتثبيت إطار العمل ExpressJS عن طريق تنفيذ الأمر التالي في سطر الأوامر: yarn add express بعد انتهاء مدير الحزم من تثبيت ExpressJS، سنثبت مكتبة Nodemon والتي تمكننا من تشغيل خادم دائم للتطبيق بحيث يعيد Nodemon تشغل الخادم آليًا في كل مرة نعدل على شفرة التطبيق. مكتبة Nodemon تستخدم فقط في مرحلة التطوير وليس في البيئة الإنتاجية، لهذا يجب علينا تثبيتها على هذا الأساس، ويكون ذلك باستخدام هذا الأمر: yarn add nodemon --dev الآن، الملف package.json سيظهر كالتالي: { "name": "zid", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "express": "^4.17.1" }, "devDependencies": { "nodemon": "^2.0.7" } } الآن أنشئ ملفًا باسم nodemon.json، وهو ملف خاص بإعدادات Nodemon ويجب أن يحتوي على الشفرة التالية: { "ext": "js", "exec": "node index.js" } السطر اﻷول، يعني أن على Nodemon أن يتتبع التغيرات الحاصلة على أي ملف بامتداد js. والسطر الثاني يمثل الأمر المراد تنفيذه عند حصول أي تغيير على أي ملف بالامتداد المحدد. إنشاء أول نقطة وصول من الواجهة الخلفية الآن، دعنا ننشئ أولى نقاط الوصول Endpoint الخاصة بنا. أولًا، نعدّل على ملف package.json ونضيف له سكريبت كالتالي "scripts": { "start": "nodemon" } سيكون الملف النهائي كالتالي: { "name": "zid", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "express": "^4.17.1" }, "devDependencies": { "nodemon": "^2.0.7" }, "scripts": { "start": "nodemon" } } الآن كل شيء جاهز. ننشئ ملف جديد باسم index.js يحتوي على الشفرة التالية: import express from "express"; var app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: false })); const port = process.env.PORT || 3000; app.listen(port, () => { console.log(`Server started on ${port}`); }); سنشرح هذه الشفرة المصدرية لأنها أساس كل ما سيأتي لاحقًا. السطرين الأول والثاني: import express from "express"; var app = express(); استدعينا إطار العمل express، بعدها أنشأنا نسخة منه Instance منه باسم app، ومنها سيعمل التطبيق ككل. السطرين الثالث والرابع تخص إطار Express إذ أخبرنا ببساطة Express بأن كل الطلبات Requests ستكون على شكل JSON. السطر الخامس: const port = process.env.PORT || 3000; أنشأنا ثابتًا يحدد رقم المنفذ Port الذي سيعمل عليه الخادم الخاص بنا. بحيث إن كان معرفا كمتغير نظام أو سيؤخذ المنفذ 3000. السطر السادس هو إنشاء الخادم الخاص بالتطبيق والذي سيعمل على المنفذ Port الذي حددناه سابقًا: app.listen(port, () => { console.log(`Server started on ${port}`); }); الآن أضف الشفرة المصدرية التالية مباشرةً بعد السطر الرابع: app.get("/", (req, res) => { res.send(‘Hello Hsoub’); }); سيكون شكل الملف كالتالي: import express from "express"; var app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.get("/", (req, res) => { res.send(`Hello Hsoub`); }); const port = process.env.PORT || 3000; app.listen(port, () => { console.log(`Server started on ${port}`); }); سنثبت بعض المكتبات التي سنستخدمها في بناء التطبيق الخاص بنا. نفِّذ الأمر التالي في سطر الأوامر في مجلد المشروع: yarn add axios pug ثبتنا المكتبتين التاليتين: Axios: هو مكتبة مهمتها القيام بإرسال طلبيات HTTP. Pug: مكتبة تخص قوالب لبناء واجهات المستخدم Frontend Templating Engine. هنالك عدة مكتبات تخص بناء واجهات المستخدم، وقع اﻹختيار على مكتبة Pug بسبب أن الشيفرة البرمجية الخاصة بها بسيطة وسهلة القراءة، باﻹضافة إلى أنها متوافقة بامتياز مع إطار العمل ExpressJS. الآن نفّذ الأمر: yarn start ستظهر لك رسالة خطأ تفيد بأنه ﻻ يمكنك استيراد إطار العمل express داخل المشروع عبر import، ويكفي لحل هذه المشكلة فقط أن تضيف السطر التالي إلى الملف package.json: "type": "module", في حالة واجهت رسالة خطأ مثل الرسالة التالية: Error: listen EADDRINUSE: address already in use :::3000 تأكد من إيقاف التطبيقات الأخرى التي تستخدم المنفذ 3000 أو غير المنفذ الخاص بالتطبيق ليكون مثلا 3001: افتح المتصفح، وادخل العنوان التالي: http://localhost:3000 يفترض أن تحصل على الرسالة التالية: تهانينا، أتممت تهئية التطبيق وإنشاء أولى نقاط الوصول Endpoint الخاصة بالواجهة الخلفية فيه باستخدام NodeJS وExpressJS. بناء تطبيق الاحتفاظ بمستخدمي متاجر زد الآن وقد شرحنا باختصار شديد طريقة بناء واجهة خلفية برمجية بسيطة باستخدام تقنية NodeJS وإطار عمل ExpressJS، سننتقل إلى بناء تطبيق بسيط لزيادة ولاء العملاء. قبل أن نبدأ، عليك أن تحاول الاستزادة قدر الإمكان في ما يتعلق بالبرمجة باستخدام NodeJS، وطريقة بناء الواجهات البرمجية، لأن هدفنا هنا هو التطبيق، لهذا لن تجدني أشرح باستفاضة الأمور البسيطة. جلب سلات الشراء المتروكة أنشئ ملفًا جديدًا باسم zid.js يحوي على الشفرة المصدرية التالية: // axios استيراد مكتبة import axios from "axios"; // إنشاء متغير يحمل رابط الواجهة البرمجية const ZidAPI = "https://api.zid.dev/app/v1"; const AbandonedCarts = async () => { const headers = { "X-MANAGER-TOKEN": process.env.MANAGER_TOKEN, Authorization: "Bearer " + process.env.auth, }; try { const getAbandondCarts = await axios.get( `${ZidAPI}/managers/store/abandoned-carts`, { headers: headers, params: { page: 1, page_size: 10, duration: 4 }, } ); if (getAbandondCarts) { return getAbandondCarts.data; } } catch (error) { return error; } }; export default AbandonedCarts; والآن، لنشرح الشيفرة باختصار شديد. بدايةً، استدعينا المكتبة axios من أجل إرسال بطلبات للواجهة البرمجية الخاصة بمنصة زد، ثم أنشأنا ثابتًا باسم ZidAPI ويحوي أساس نقطة الوصول الخاصة بالواجهة البرمجية لمنصة زد. أنشأنا دالة Function غير متزامنة باسم AbandonedCarts ومهمتها هي جلب سلات الشراء المتروكة على متجرنا. أنشأنا داخل تلك الدالة ثابتًا باسم headers، وهو كائن يحتوي على قيمتين مفتاح المتجرX-MANAGER-TOKEN و مفتاح الواجهة البرمجية Authorization. إن لم تعرف من أين حصلنا على هذين المتغيرين فارجع إلى المقالات السابقة. قد أجدك تتساءل ما معنى process.env؟ هي طريقة لحماية مفاتيح الوصول، وذلك عن طريق إضافة المفتاح كمتغير بيئة Environment Variable. فمثلا، في تطبيقنا هذا، حمينا مفتاح الوصول الخاص بالمتجر باسم X-MANAGER-TOKEN. تُنفّذ هذه العملية على نحو فتح سطر الأوامر وإدخال الأمر التالي: export X-MANAGER-TOKEN=value استبدل value بقيمة مفتاح المتجر بدون إضافة مسافة بعد علامة = ونفس الشيء بالنسبة للمتغير Authorization. سنشرح في عجالة طريقة تثبيت WSL2 على نظام التشغيل ويندوز، ومن ثم طريقة إنشاء متغيرات النظام. بداية تأكد من تحديث نظام التشغيل عندك إلى آخر نسخة ممكنة حتى تستطيع الاستفادة من خاصية تثبيت نظام لينكس كنظام ثانوي داخل ويندوز. افتح PowerShell كمستخدم مدير، ونفذ الأمر التالي: dism.exe /online /enable-feature/featurename:Microsoft-Windows-Subsystem-Linux /all /norestart بعد انتهاء تنفيذ الأمر، نحتاج الآن إلى تفعيل خاصية الأنظمة الوهمية Virtual Machine الخاصة بنظام التشغيل ويندوز وذلك عن طريق تنفيذ الأمر التالي في نفس نافذة PowerShell السابقة: dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart بعد انتهاء تنفيذ الأمر، أعد تشغيل جهازك حتى يتسنى للنظام تفعيل جميع الخصائص المطلوبة. علينا الآن تحديث نواة نظام التشغيل لينكس، وذلك بتنزيل آخر تحديث متوفر، بعد انتهاء التنزيل، افتح الملف واتبع الخطوات لتثبيته كأي برنامج آخر. إفتح نافذة PowerShell، ونفذ الأمر التالي: wsl --set-default-version 2 افتح متجر تطبيقات ويندوز وابحث عن Ubuntu وثبِّته مثل أي تطبيق آخر، وبعد الانتهاء أعد تشغيل جهازك. بإمكانك الآن تنفيذ أوامر لينكس داخل نظام ويندوز دون مشاكل. لمزيد من التفاصيل، ارجع إلى مقال تطبيق Hyper-V في ويندوز 10. على أي حال، هنالك طريقة أخرى ﻹضافة متغيرات النظام عن طريق مكتبة dotenv، وتكون كالتالي: في سطر اﻷوامر أدخل الأمر التالي: yarn add dotenv أنشئ ملفًا باسم env. داخل المجلد الرئيسي للتطبيق، وضع بداخله قيمتي مفتاح المتجر ومفتاح الواجهة البرمجية، النتيجة ستكون كالتالي: MANAGER_TOKEN=value auth=value لا تنسى تبديل القيمة value ووضع المفتاح المناسب الخاص بك مكانها. في بداية الملف index.js نضيف الشيفرة البرمجية التالية: import dotenv from "dotenv"; بقي علينا اﻵن أن نضيف شيفرة تخبر إطار Express أننا سنستخدم مكتبة dotenv لجلب متغيرات البيئة من الملف ‎.env عوض استخدام المتغيرات المخزنة فعلا في نظام التشغيل. في ملف index.js وقبل السطر التالي: var app = express(); نضيف ما يلي: dotenv.config(); بإمكانك اﻵن إضافة متغيرات النظام مباشرةً للملف env. دون إضافتها بصورة مباشرة إلى نظام التشغيل. بعد الانتهاء من ضبط متغيرات البيئة، أنشأنا كتلة برمجية باستخدام Try-Catch لتجريب الإتصال بالواجهة البرمجية لمنصة زد. أنشأنا متغيرًا باسم getAbandondCarts وأسندنا إليه القيمة الراجعة من إرسال الطلب إلى الواجهة البرمجية لمنصة زد. بحيث أرسلنا طلب Request من نوع GET، يحمل المعلومات المطلوبة في توثيق الواجهة البرمجية، وهي ترويسة الطلب headers وأيضا استعلامًا Query فيه عدد الصفحات وأيضا عدد العناصر في الصفحة. بعدها تحققنا إن استقبلنا إجابة خادم الواجهة البرمجية لمنصة زد، وفي حالة وجود الإجابة، فإننا نرجع المحتوى خاصتها؛ أما في حالة وجود خطأ، فسننتقل إلى الجزء catch والذي سيرجع قيمة الخطأ مثل رسالة. في آخر الملف، صدرنا الدالة لنستخدمها في مواضع أخرى. الآن ننتقل إلى الملف index.js ونستدعي الملف zid.js بالطريقة التالية: import AbandonedCarts from "./zid.js"; ثم نضيف نقطة وصول جديدة بنفس الطريقة السابقة: app.get("/carts", async (req, res) => { const response = await AbandonedCarts(); const renderedData = response["abandoned-carts"]; res.send(renderedData); }); دعنا نفهم الشيفرة السابقة: أنشأنا نقطة وصول جديدة بحيث تستقبل طلبات من نوع GET أنشأنا ثابتًا جديدًا باسم response بحيث يستقبل إجابة الخادم من الدالة التي أنشأناها سابقًا باسم AbandonedCarts أنشأنا ثابتًا جديدًا باسم renderedData يحمل قيمة فرعية من الثابت response أعدنا محتوى الثابت renderedData لنجرب الآن نقطة الوصول الجديدة، افتح برنامج Insomnia، وأنشئ طلبًا جديدًا من نوع GET لنقطة الوصول التالية: http://localhost:3000/carts وأرسل الطلب، إن لم توجد سلات شراء متروكة، فإن الواجهة البرمجية لمنصة زد، ستعيد لنا مصفوفة فارغة، أما إن وجدت سلات شراء متروكة، ستحصل على مصفوفة مشابهة لهذه: [ { "id": "6718344e-8e2c-4667-b2cd-1178632de6e9", "store_id": "a739c51c-8103-4648-873b-cc3a8ea2dc8a", "session_id": "xQH4imSzunyafhd2QkD2llkjz8qjEKvW", "cart_id": "904142370", "order_id": 7231078, "phase": "completed", "customer_id": 5835, "customer_name": "man", "customer_email": "m.a***at@zid.sa", "customer_mobile": "966550*****", "city_id": 1, "products_count": 1, "reminders_count": 0, "cart_total": 138, "cart_total_string": "138.00 SAR", "created_at": "2021-05-20 08:59:54", "updated_at": "2021-05-20 10:59:35" }, { "id": "33e932a1-0a9f-4468-a8de-c09540f9aa56", "store_id": "a739c51c-8103-4648-873b-cc3a8ea2dc8a", "session_id": "b6fRKKmcwVtLssqQNgvPSEaY2FvzAG7B", "cart_id": "914265844", "order_id": null, "phase": "shipping_address", "customer_id": 3450024, "customer_name": "Mohammad", "customer_email": "asha.k@fast.com", "customer_mobile": "966506766***", "city_id": 1, "products_count": 2, "reminders_count": 0, "cart_total": 504.85, "cart_total_string": "504.85 SAR", "created_at": "2021-05-19 09:09:45", "updated_at": "2021-05-19 12:23:16" } ] أصبحنا الآن قادرين على تتبع كل السلات المتروكة وحالتها والتفاصيل الخاصة بها وفعل أي شيء متاح معها عبر هذه التفاصيل مع كل سلة وهنا مربط الفرس. سننتقل الآن إلى إنشاء واجهة استخدام بسيطة باستخدام محرك القوالب Pug. بناء شريط التنقل وواجهة السلات المتروكة سنبني واجهات التطبيق عبر محركة القوالب Pug وسنبدأ بواجهة السلات المتروكة، ولكن دعنا أول أن نفهم ما هو محرك القوالب. محرك القوالب Template Engine هو نظام قوالب يسمح لنا بإنشاء واجهات الإستخدام على الخادم ومن ثم إخراجها Render للعميل. يمكنك الإطلاع على التوثيق الخاص بمحرك القوالب Pug من الموقع الرسمي الخاص به. أنشئ مجلدًا جديدًا باسم views داخل المجلد الرئيسي للمشروع، وأنشئ ملفًا جديدًا باسم page.pug، ضع بداخله الشيفرة البرمجية التالية: doctype html block head meta(charset='UTF-8') meta(http-equiv='X-UA-Compatible' content='IE=edge') meta(name='viewport' content='width=device-width, initial-scale=1.0') link(href='https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css' rel='stylesheet') body .w-full.max-w-8xl.min-w-0.mx-auto.px-6 .flex.mt-12.bg-white.rounded-md.shadow .w-64.bg-blue-100.rounded-l-md.border-r.border-dashed.border-blue-200 .flex.justify-center.items-center.h-32.text-blue-700.text-center.font-semibold.text-3xl.italic | Loyalty Program .mt-8.border-t.border-blue-200 a.block.py-3.px-6.text-blue-700.font-semibold.border-b.border-blue-200(href='/') | Home a.block.py-3.px-6.text-blue-700.font-semibold.border-b.border-blue-200(href='/carts') | Abandoned Carts a.block.py-3.px-6.text-blue-700.font-semibold.border-b.border-blue-200(href='/coupon') | Coupons a.block.py-3.px-6.text-blue-700.font-semibold.border-b.border-blue-200(href='/loyalty') | Loyalty block content .flex-grow .flex.flex-col.mx-2.mt-1 .px-3.py-4.flex.justify-center لن نشرح صيغة كتابة قوالب pug لأنها بسيطة جدًا، وتحفيزك أيضًا للإطلاع على التوثيق الرسمي الخاص بـ Pug. يتيح محرك القوالب Pug إنشاء كتل برمجية blocks وإعادة استخدامها لاحقا في أي مكان تحتاجه، كمثال على ذلك، هو ما فعلناه في الملف السابق page.pug، بحيث أنشأنا كتلة برمجية سنستخدمها في بقية الصفحات. في الشيفرة البرمجية السابقة التي تخص الملف page.pug، ﻻحظ أننا أنشأنا كتلة block باسم head وأضفنا إليها ما يتعلق بالبيانات الوصفية Metadata، مع إرفاق ملف خاص بإطار TailwindCSS، باستخدام شبكات الوصول CDN. بعدها أضفنا جسم الصفحة تحت ترويسة body، تحتوي على قائمة جانبية. وتحتها أضفنا كتلة جديدة تحت اسم content وهي ما سيحمل مختلف محتوى الصفحات الخاصة بالتطبيق. سنريكم صورةً عن الناتج النهائي المتوقع الحصول عليه: ننتقل اﻵن ﻹنشاء صفحة لعرض قائمة سلات الشراء المتروكة، باستخدام نقطة الوصول التي أنشأناها سابقًا، بحيث سنسترجع مصفوفة الكائنات التي تحصلنا عليها من الواجهة البرمجية والتي تخص متجر العميل، ونستخرج المعلومات التي نحتاجها باستخدام حلقة تكرارية بسيطة. أنشئ ملفًا جديدًا داخل المجلد views باسم abandoned.pug وضع بداخله الشيفرة التالية: extends page.pug block append head title Abandoned Carts block content table.w-full.text-md.bg-white.shadow-md.rounded.mb-6.max-w-6xl.min-w-0.mx-auto.px-6 thead tr.border-b th.text-left.p-1.px-4 Customer Name th.text-left.p-1.px-4 Customer Email th.text-left.p-1.px-4 Customer Mobile th.text-left.p-1.px-4 Products In Cart th.text-left.p-1.px-4 Cart Total(SAR) th.text-left.p-1.px-4 Phase tbody each element in renderedData tr.border-b.bg-gray-100(class='hover:bg-orange-100') td.p-3.px-5=element.customer_name td.p-3.px-5=element.customer_email td.p-3.px-5=element.customer_mobile td.p-3.px-5=element.products_count td.p-3.px-5=element.cart_total td.p-3.px-5=element.phase سأشرح هذا الكود باستفاضة. في السطر اﻷول، عملنًا تمديدًا للقالب اﻷب الذي أنشأناه سابقا، بحيث أن القالب الجديد (القالب ابن) سيأخذ كل محتوى القالب السابق ويضيف عليه ما نريد: extends page.pug أما في السطرين التاليين، طلبنا من محرك القوالب Pug أن يعدل الكتلة block المسمى head في القالب الأب بما تحت هذا السطر، وهنا أعدنا تسمية عنوان الصفحة بـ Abandoned Carts: block append head title Abandoned Carts بعدها أنشأنا جدولًا Table وقسمناه إلى 6 أعمدة تحمل عناوين المعلومات التي نريد عرضها. each element in renderedData في هذا السطر، أنشأنا حلقة تكرارية تستخرج المعلومات المطلوبة من مصفوفة الكائنات Array of Objects التي تحصلنا عليها سابقا، إذ وضعنا المعلومات المطلوبة في سطور حسب نوعيتها. بقيت لنا خطوة واحدة الآن، وهي ربط الصفحة التي أنشأناها مع نقطة الوصول التي سبق و اضفناها. توجه إلى الملف index.js وعدِّل نقطة الوصول السابقة لتكون كالتالي: app.get("/carts", async (req, res) => { const response = await AbandonedCarts(); const renderedData = response["abandoned-carts"]; res.render("abandoned", { renderedData }); }); لاحظ أننا غيرنا السطر الأخير واستبدلنا التابع send بتابع جديد هو render، والذي يأخذ معاملين، المعامل الأول هو القالب، والمعامل الثاني هي البيانات التي ستُعرَض في القالب. يجب التأكد من أن اسم القالب المرسل كمعامل للتابع render هو بنفس الاسم الذي يحمله القالب المعني. يجب التأكد أيضًا أن عنوان المعامل الثاني والمرسل كبيانات للعرض، هي بنفس الأسم الموجود في القالب الذي أُنشئ لهذا الشأن. شغِّل الآن الخادم الخاص بنا عن طريق تنفيذ الأمر: yarn start لم يعمل معك! بل وظهرت الكثير من رسائل الخطأ، صحيح؟ عد إلى ملف index.js وأضف الأسطر التالية مباشرة قبل أول نقطة وصول Endpoint أنشأناها: app.set("views", path.join(__dirname, "views")); app.set("view engine", "pug"); app.use(express.static(path.join(__dirname, "public"))); ما الذي تعنيه تلك الأسطر؟ ببساطة، طلبنا من إطار ExpressJS أن يستخدم Pug كنظام قوالب، وأيضًا أن يتعرف على مسار ملفات القوالب التي أنشأناها والموجودة داخل المجلد views. أما بالنسبة للسطر الأخير، فهي أننا أخبرنا ExpressJS بأن المجلد النهائي للقوالب بعد أن تحدث عملية التصدير/الاستخراج rendering أن يضع الملفات الناتجة في المجلد public. قبل أن تعيد تشغيل الخادم، استورد المكتبة path في بداية الملف، تمامًا بعد استيراد express مع إنشاء ثابت جديد باسم dirname__ والذي سيحوي التابع resolve الخاص بالمكتبة path وبالتالي سيكون الملف index.js كالتالي: import express from "express"; import path from "path"; import AbandonedCarts from "./zid.js"; const __dirname = path.resolve(); var app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.set("views", path.join(__dirname, "views")); app.set("view engine", "pug"); app.use(express.static(path.join(__dirname, "public"))); app.get("/carts", async (req, res) => { const response = await AbandonedCarts(); const renderedData = response["abandoned-carts"]; res.render("abandoned", { renderedData }); }); const port = process.env.PORT || 3000; app.listen(port, () => { console.log(`Server started on ${port}`); }); الآن، شغل الخادم الخاص بالتطبيق، وافتح المتصفح وادخل العنوان التالي: http://localhost:3000/carts ستظهر لنا النافذة التالي (اُخفيت معلومات العملاء حفاظا على الخصوصية): تهانينا، لقد أكملت أول صفحات تطبيق. إنشاء قسائم التخفيض Coupons ننتقل الآن إلى بناء صفحة إنشاء قسيمة تخفيض باستخدام الواجهة البرمجية لمنصة زد، يرجى مراجعة التوثيق الخاص بها من أجل معرفة المعلومات المطلوبة. أنشئ ملفًا جديدًا داخل المجلد views باسم coupon.pug وضع الشيفرة البرمجية التالية: extends page.pug block append head title Coupon block content form#form(action='/add-coupon' method='POST').place-items-center.max-w-max.m-4.p-2.bg-white.rounded.shadow-xl p.text-gray-800.font-medium Adding new coupon code div label.block.text-sm.text-gray-00(for='name') Choose a name for the coupon input.w-full.px-5.py-1.text-gray-700.bg-gray-200.rounded(name='name' type='text' required='' placeholder='Coupon Name') .mt-2 label.block.text-sm.text-gray-600(for='code') Coupon Code input.w-full.px-5.py-4.text-gray-700.bg-gray-200.rounded(name='code' type='text' required='' placeholder='Hsoub10') .mt-2 label.block.text-sm.text-gray-600(for='discount_type') Discount Type input.w-full.px-2.py-2.text-gray-700.bg-gray-200.rounded(name='discount_type' type='text' required='' placeholder='p for percentage and f for fixed') .mt-2 label.text-sm.block.text-gray-600(for='discount') Discount input.w-full.px-2.py-2.text-gray-700.bg-gray-200.rounded(name='discount' type='text' required='' placeholder='discount') .inline-block.mt-2.pr-1(class='w-1/2') label.block.text-sm.text-gray-600(for='free_shipping') Free Shipping input.w-full.px-2.py-2.text-gray-700.bg-gray-200.rounded(name='free_shipping' type='text' required='' placeholder='1 to enable, 0 to disable') .inline-block.mt-2.-mx-1.pl-1(class='w-1/2') label.block.text-sm.text-gray-600(for='free_cod') Free Cash on Delivery input.w-full.px-2.py-2.text-gray-700.bg-gray-200.rounded(name='free_cod' type='text' required='' placeholder='1 to enable, 0 to disable') div label.block.text-sm.text-gray-600(for='total') Total to apply coupon input.w-full.px-2.py-2.text-gray-700.bg-gray-200.rounded(name='total' type='text' required='' placeholder='Total to apply coupon') .inline-block.mt-2.pr-1(class='w-1/2') label.block.text-sm.text-gray-600(for='date_start') Starting Date input.w-full.px-2.py-2.text-gray-700.bg-gray-200.rounded(name='date_start' type='text' required='' placeholder='2021-06-01') .inline-block.mt-2.-mx-1.pl-1(class='w-1/2') label.block.text-sm.text-gray-600(for='date_end') Ending Date input.w-full.px-2.py-2.text-gray-700.bg-gray-200.rounded(name='date_end' type='text' required='' placeholder='2021-12-31') .mt-2 label.block.text-sm.text-gray-600(for='uses_total') Total Using input.w-full.px-2.py-2.text-gray-700.bg-gray-200.rounded(name='uses_total' type='text' required='' placeholder='1000') .mt-2 label.block.text-sm.text-gray-600(for='uses_customer') Total Using Per Customer input.w-full.px-2.py-2.text-gray-700.bg-gray-200.rounded(name='uses_customer' type='text' required='' placeholder='5') .mt-2 label.block.text-sm.text-gray-600(for='apply_to') Apply for all Products? input.w-full.px-2.py-2.text-gray-700.bg-gray-200.rounded(name='apply_to' type='text' required='' placeholder='all or apply_to_array[]') .mt-2 label.block.text-sm.text-gray-600(for='status') Active? input.w-full.px-2.py-2.text-gray-700.bg-gray-200.rounded(name='status' type='text' required='' placeholder='1 to enable, 0 to disable') .mt-4 button.px-4.py-1.text-white.font-light.tracking-wider.bg-gray-900.rounded(type='submit') Add في بداية الملف، استوردنا الشيفرة الموجودة في الملف page.pug والتي تحوي القائمة الجانبية واستيراد إطار TailwindCSS. بعدها أنشأنا نموذج Form لإرسال البيانات إلى نقطة الوصول التي سنبنيها الآن. أنشئ ملفًا جديدًا باسم addCoupon.js ونفّذ ما فعلناه في الملف zid.js ألا وهو استيراد مكتبة Axios من أجل إرسال طلبات إلى الواجهة البرمجية لمنصة زد ولكن هذه المرة بطريقة POST، وهذا حسب التوثيق الخاص بالمنصة: import axios from "axios"; const ZidAPI = "https://api.zid.dev/app/v1"; الآن سنحتاج إلى إنشاء دالة function ونسند إليها مهمة إرسال الطلب إلى الواجهة البرمجية لمنصة زد بالشكل التالي: const AddCoupon = async (couponInfo) => { const headers = { "X-MANAGER-TOKEN": process.env.MANAGER_TOKEN, Authorization: "Bearer " + process.env.auth, }; أنشأنا الدالة تحت اسم addCoupon والتي تأخذ معاملًا واحدًا ويجب أن يكون كائنًا. حددنا ترويسة الطلب الذي سنرسله داخل الثابت headers. الخطوة الثانية هي أن ننشئ ثابتًا constant يحوي جميع المعلومات المطلوبة من طرف الواجهة البرمجية لمنصة زد، الثابت يكون كائنا من أجل أن يحمل جميع المعلومات. const data = { name: couponInfo.name, code: couponInfo.code, discount_type: couponInfo.discount_type, discount: couponInfo.discount, free_shipping: couponInfo.free_shipping, free_cod: couponInfo.free_cod, total: couponInfo.total, date_start: couponInfo.date_start, date_end: couponInfo.date_end, uses_total: couponInfo.uses_total, uses_customer: couponInfo.uses_customer, apply_to: couponInfo.apply_to, status: couponInfo.status, }; الآن ننشئ كتلة Try - Catch لإرسال الطلب للواجهة البرمجية بحيث أنشأنا ثابتًا باسم addCoupon يحوي الطلب المرسل إلى الواجهة البرمجية عن طريق مكتبة Axios كالتالي: try { const addCoupon = await axios.post( `${ZidAPI}/managers/store/coupons/add`, data, { headers: headers, } ); if (addCoupon) { return addCoupon.data; } } catch (error) { return error; } تحققنا من عدم وجود أي خطأ وفي حالة وجود إجابة من الخادم نرجع محتوى الإجابة عن طريق السطر: return addCoupon.data; أما في حالة وجود خطأ، فسيكون الانتقال مباشرةً إلى الجزء catch وهنا سيُسترجع محتوى الخطأ عن طريق السطر: return error; في أخر الملف، نصدِّر الدالة حتى نستطيع استخدامها في أماكن أخرى باستخدام السطر: }; export default AddCoupon; اﻵن نضيف نقطة وصول جديدة Endpoint إلى الملف index.js بنفس الطريقة التي أضفنا بها نقاط الوصول السابقة. استدع في أعلى الملف الملف addCoupon كالتالي: import AddCoupon from ‘./addCoupon.js’ لتكون بداية الملف تمامًا كالتالي: import express from "express"; import dotenv from "dotenv"; import path from "path"; import AbandonedCarts from "./zid.js"; import AddCoupon from "./addCoupon.js"; بعدها سنضيف نقطة الوصول بالشكل التالي: app.post("/add-coupon", async (req, res) => { const data = req.body; const dataToSend = Object.assign({}, data); const response = await AddCoupon(dataToSend); if (response) { res.redirect("/"); } else { res.redirect("/error"); } }); أعتقد أنك قد ﻻحظت أن نقطة الوصول هذه مختلفة بعض الشيء عن سابقاتها، ﻻ تقلق، سأشرح كل شيء بالتفصيل. في السطر اﻷول، أنشأنا نقطة الوصول الجديدة والتي تستعمل POST ﻹرسال البيانات، الرابط سيكون: /add-coupon ﻻحظت أننا أضفنا كلمة مفتاحية جديدة هي async وهي ببساطة تعني أن هنالك عملية ستأخذ وقتا غير معروف لهذا قبل الانتهاء من جميع العمليات المطلوبة، يجب إنهاء العمليات التي تأخذ وقتا، من الأفضل أن تتعرف أكثر على تقنية async/await خصوصا في NodeJS. في السطر الثاني، أنشأنا ثابتا جديدا باسم data والذي يحوي جسم الطلب المرسل Request إلى نقطة الوصول، في هذه النقطة ﻻ يزال جسم الطلب خاما، ويجب أن يُعدَّل ليكون كائنًا Object؛ أما في السطر الثالث، فقد عدّلنا أو تنقية الثابت data باستخدام التابع assign المدمج افتراضيًا في لغة Javascript، أُسنِدت النتيجة إلى الثابت dataToSend. بينما في السطر الرابع، أنشأنا ثابتًا جديدًا باسم response وأسندنا نتيجة الدالة AddCoupon إليه. لاحظ أننا استخدمنا كلمة مفتاحية جديدة هي await قبل الدالة AddCoupon، وهنا طلبنا أن ينتظر NodeJS العملية حتى انتهائها قبل القيام بتنفيذ السطر الموالي. كخطوة أخيرة، وضعنا شرطًا للتحقق إن كنا قد تحصلنا على إجابة من الخادم Response أم ﻻ. في حالة الحصول على إجابة، سيُنفَّذ السطر: res.redirect("/"); وهنا، سيُعاد توجيه المستخدم إلى الصفحة الرئيسية. أما في حالة عدم الحصول على إجابة، فسيُنفَّذ السطر: res.redirect("/error"); ويعني أنه سيُعاد توجيه المستخدم إلى صفحة الخطأ وهي في هذه الحالة نقطة وصول ستُنشأ لاحقًا لعرض رسائل الخطأ. اﻵن، بقيت لنا خطوة أخيرة، وهي إنشاء صفحة يستطيع المتصفح الوصول إليها. ببساطة، ننشئ نقطة وصول جديدة باسم coupon والتي تكون من نوع GET، تعرض فقط القالب coupon الذي سبق وأنشأناه. نقطة الوصول ستكون كالتالي: app.get("/coupon", async (req, res) => { res.render("coupon"); }); شغل خادم التطبيق باستخدام الأمر: yarn start توجه إلى الرابط التالي: http://localhost:3000/coupon إن ظهرت لديك رسالة خطأ مشابهة لهذه الرسالة: Error:/zid-local/views/coupon.pug:5:1 Only named blocks and mixins can appear at the top level of an extending template at makeError (/zid-local/node_modules/pug-error/index.js:34:13) تأكد من إزاحة indentation السطور في الصفحة، ويفضل استعمال إضافة pug (jade) formatter والتي تساعدك في تنسيق الشفرات البرمجية الخاصة بمحرك القوالب Pug. بعد تثبيت اﻹضافة، اضغط على Alt+Shift+F لتنسيق الشيفرة البرمجية وحل المشكلة. سيظهر نموذج إنشاء قسيمة التخفيض التي أنشأناها سابقًا باستخدام الملف coupon.pug: أدخل المعلومات الخاصة بقسيمة التخفيض واضغط على إضافة Add من أجل إرسال المعلومات إلى نقطة الوصول التي اضفناها سابقًا add-Coupon ومنها تُعالَج البيانات وتُرسَل إلى الواجهة البرمجية لمنصة زد. في حالة إنشاء قسيمة التخفيض، فسيوجَّه المستخدِم إلى الصفحة الرئيسية التي نحن بصدد إنشائها، أما في حالة وجود خطأ ما، أو عدم القدرة على إرسال الطلب بطريقة صحيحة، سيُعاد توجيه المستخدم إلى صفحة الخطأ التي أنشأناها سابقًا. إنشاء صفحة الأخطاء اﻵن، أنشئ ملفًا جديدًا داخل المجلد views باسم error.pug وضع بداخله الشيفرة البرمجية التالية: doctype html block head meta(charset='UTF-8') meta(http-equiv='X-UA-Compatible' content='IE=edge') meta(name='viewport' content='width=device-width, initial-scale=1.0') link(href='https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css' rel='stylesheet') body block content style. .gradient { background-image: linear-gradient(135deg, #684ca0 35%, #1c4ca0 100%); } .gradient.text-white.min-h-screen.flex.items-center .container.mx-auto.p-4.flex.flex-wrap.items-center .w-full.text-center.p-4(class='md:w-7/12 md:text-left') .text-6xl.font-medium 404 .text-xl.font-medium.mb-4(class='md:text-3xl') | Oops. This page has gone missing. .text-lg.mb-8 | You may have mistyped the address or the page may have moved. a.border.border-white.rounded.p-4(href='/') Go Home في الملف index.js، أنشئ نقطة وصول جديدة كالتالي: app.get("/error", (req, res) => { res.render("error"); }); اﻷمر بسيط ونقطة الوصول هذه تعرض القالب error.pug الذي أنشأناه قبل قليل، حول أي أخطاء تظهر معك إلى الرابط ‎/error من أجل عرض هذه الصفحة. إنشاء الصفحة الرئيسية للتطبيق لننشئ الصفحة الرئيسية للتطبيق، أنشئ ملفًا جديدًا داخل المجلد views باسم index.pug، ثم ضع الشيفرة التالية بداخله: extends page.pug block append head title Welcome block content .flex.mx-auto.items-center.justify-center.shadow-lg.mt-65.mx-8.mb-4.max-w-lg form.w-full.max-w-xl.bg-white.rounded-lg.px-4.pt-2 .flex.flex-wrap.-mx-3.mb-6 h2.px-4.pt-3.pb-2.text-gray-800.text-lg أضف مفتاح المتجر الخاص بك .w-full.px-3.mb-2.mt-2(class='md:w-full') textarea.bg-gray-100.rounded.border.border-gray-400.leading-normal.resize-none.w-full.h-20.py-2.px-3.font-medium.placeholder-gray-700(class='focus:outline-none focus:bg-white' name='body' placeholder='Paste your store X-MANAGER-TOKEN HERE' required='') .w-full.flex.items-start.px-3(class='md:w-full md:w-full') .-mr-1 input.bg-white.text-gray-700.font-medium.py-1.px-4.border.border-gray-400.rounded-lg.tracking-wide.mr-1(type='submit' class='hover:bg-gray-100' value='Add') الآن، علينا أن ننشئ نقطة الوصول الخاصة بالصفحة الرئيسية، في ملف index.js ننشئ نقطة الوصول كما تعودنا، تستخدم طريقة GET لاستقبال البيانات من الخادم: app.get("/", async (req, res) => { res.render("index"); }); نقطة الوصول هذه بسيطة، بحيث أن رابطها هو الرابط الرئيسي للخادم، وتعرض فقط القالب الخاص بالصفحة الرئيسية، والنتيجة ستكون كالتالي: أضفنا حقلًا لإدخال مفتاح مفتاح الوصول الخاص بالمتجر X-MANAGER-TOKEN ليُستخدم مستقبلًا، وسنشرح سبب إضافة هذا الحقل -الواضح- عند الانتهاء من بناء المنصة. بناء خدمة إرسال رسائل بريد إلكتروني بعد أن استرجعنا واستعراض سلات الشراء المتروكة، وأنشأنا قسيمة تخفيض، علينا الآن إرسال بريد إلكتروني يحمل قسيمة التخفيض التي أنشأناها لأصحاب سلات الشراء المتروكة، من أجل تحفيزهم على إنهاء طلباتهم وبالتالي زيادة مبيعات المتجر الخاص بنا. لإرسال رسائل البريد الإلكتروني بطريقة بسيطة، سنستخدم SendGrid والذي يوفر خدمة إرسال مجاني لرسائل البريد الإلكتروني جيدًا للاستخدام البسيط (أو أي خدمة أخرى تختارها). أنشئ حسابًا على منصة SendGrid وفعل حسابك. بعدها، افتح نافذة سطر أوامر في نفس مجلد التطبيق ونفذ الأمر التالي: yarn add @sendgrid/mail سيثبّت هذا الأمر المكتبة الخاصة بمنصة SendGrid. أنشئ ملفا جديدا باسم mail.js وأضف الشيفرة البرمجية التالية: import sgMail from "@sendgrid/mail"; sgMail.setApiKey(process.env.SENDGRID_API_KEY); const sendMail = async (mailData) => { const msg = { to: mailData.to, // SendGrid أضف البريد اﻹلكتروني الذي سجلت به في منصة from: "info@email.com", subject: mailData.subject, text: mailData.text, html: mailData.html, }; const sendingMail = await sgMail.send(msg); if (sendingMail) { return "Mail has been sent"; } else { console.log("SENDING MAIL ERROR ===> ", sendingMail); return "There was a problem in sending the mail"; } }; export default sendMail; بداية، استوردنا مكتبة منصة SendGrid التي ثبتناها قبل قليل، بعدها أضفنا المفتاح المساعد الخاص بحسابنا على المنصة، والذي تحصل عليه من لوحة التحكم الخاصة بحسابك. أنشأنا دالة باسم sendMail والتي تأخذ معاملًا واحدًا يجب أن يكون كائنًا Object والذي سيحوي المعلومات المطلوبة لإرسال البريد الإلكتروني. أنشأنا ثابتًا جديدًا باسم msg والذي يحوي كل من الحقول التالي: Subject: يمثل عنوان البريد الإلكتروني الذي نريد إرساله From: وهو عنوان البريد الإلكتروني الذي سنرسل منه الرسائل، وهو نفس عنوان البريد الإلكتروني الذي أضفتَه إلى حسابك على منصة SendGrid `Subject: عنوان رسالة البريد الإلكتروني التي سنرسلها. Text: نص رسالة البريد الإلكتروني التي سترسله، يجب أن يكون نصا فقط Html: نفس نص رسالة البريد الإلكتروني، ولكن بإمكانك أن تضيف تنسيقات HTML. أنشأنا ثابتًا باسم sendingMail يحوي القيمة الراجعة من التابع send الخاص بمكتبة SendGrid والتي سترسل رسالة البريد اﻹلكتروني إن كانت جميع المدخلات صحيحة. أنشأنا شرطًا بعدها يتحقق إن كانت هنالك إجابة من الواجهة البرمجية لمنصة SendGrid، إن كانت هنالك إجابة ستُرجَع رسالة تفيد بأنه قد تمت عملية اﻹرسال بنجاح. في حالة عدم وجود إجابة من الواجهة البرمجية أو أرجعَت خطأ، نعرض الخطأ عن السطر الموجود بداخل الجزء الثاني من كتلة الشرط، وبعدها نرجع رسالة تفيد بأن هنالك مشكلة عند إرسال البريد اﻹلكتروني: console.log("SENDING MAIL ERROR ===> ", sendingMail); return "There was a problem in sending the mail"; في النهاية، صدّرنا الدالة من أجل نستخدمها في مختلف أجزاء التطبيق. اﻵن سنضيف نقطة وصول جديدة لمشروعنا، في الملف index.js أضف الشيفرة البرمجية التالية: app.post("/mail", async (req, res) => { const data = req.body; const dataToSend = Object.assign({}, data); const send = await sendMail(dataToSend); if (send) { res.send("mail has been sent"); } else { res.send("there was an error"); } }); متأكد أنك قد تعودت على صيغة إضافة نقاط الوصول إلى المشروع، نقطة الوصول هذه مشابهة جدا لنقطة الوصول السابقة التي أضفناها سابقًا. تركيب أجزاء التطبيق مع بعضها انتهينا إلى الآن من بناء الخصائص اﻷساسية للتطبيق، بقي لنا أن نجمع هذه الخصائص كلها من أجل الوصول إلى هدفنا، وهو إرسال بريد إلكتروني لجميع أصحاب سلات الشراء المتروكة حتى نحفزهم على إكمال عملية الشراء بإرسال قسيمة تخفيض إليهم عن طريق البريد اﻹلكتروني. أنشئ ملفًا جديدًا داخل المجلد views باسم loyalty.pug وضع بداخله الشيفرة البرمجية التالية: extends page.pug block append head title Loyalty block content .wrapper.px-2.w-full p.text3xl.items-center.justify-center Send a coupon code to all abandoned carts form.max-w-sm.bg-gray-100.px-3.py-5.rounded.shadow-lg.my-10.m-auto(action='/loyalty' method='POST') .flex.flex-col.space-y-3 .flex.items-center.bg-white.border.border-gray-100.rounded.px-2 input.w-full.py-2.px-1.placeholder-indigo-400.outline-none.placeholder-opacity-50(type='text' placeholder='Enter Coupon Code' autocomplete='off') button.text-white.bg-indigo-500.px-4.py-2.rounded(type='submit') | Send Coupon الصفحة بسيطة، فيها نافذة فقط ﻹضافة قسيمة التخفيض أنشئ ملفًا جديدًا باسم loyalty.js يحمل الشفرة البرمجية التالية: import AbandonedCarts from "./zid.js"; import sendMail from "./mail.js"; const Loyalty = async (couponCode) => { const getAbandondCarts = await AbandonedCarts(); if (getAbandondCarts) { const response = getAbandondCarts["abandoned-carts"]; if (response) { const getEmails = []; for (let i = 0; i < response.length; i++) { getEmails.push(response[i].customer_email); } const mailData = { to: getEmails, // استخدم عنوان البريد اﻹلكتروني الذي سجلت به from: "info@geekcademy.com", subject: "Special Offer for you", text: "يرجى استخدام قسيمة التخفيض التالية " + couponCode + " من أجل إنهاء طلبك", html: "يرجى استخدام قسيمة التخفيض التالية " + couponCode + " من أجل إنهاء طلبك", }; return await sendMail(mailData); } else { return "There was an error getting abandoned carts"; } } else { return "There is a server error"; } }; export default Loyalty; بداية استوردنا كل من دالة جلب سلات الشراء المتروكة AbandonedCarts ودالة إرسال رسائل البريد اﻹلكتروني. بعدها أنشأنا دالةً جديدةً تحت اسم Loyalty والتي ستدمج الدالتين السابقتين بحيث ستجلب سلات الشراء المتروكة أوﻻ، ومن ثم التحقق من وجود المعلومات المطلوبة: const getEmails = []; هنا أنشأنا ثابتًا جديدًا يمثل مصفوفة فارغة، ستوضع عناوين البريد المستخرجة من المعلومات التي حُصِّلت عليها من سلات الشراء المتروكة لعملاء المتجر، بعدها أنشأنا حلقة تكرارية، بحيث تمسح جميع المعلومات المتحصل عليها من الثابت response بعد التحقق من أنه يحوي المعلومات المطلوبة وهي مصفوفة كائنات. مع كل دورة للحلقة التكرارية، يُستخرَج البريد الإلكتروني للعميل الذي ترك سلته دون شراء وإضافته إلى الثابت getEmails ثم أنشأنا بعدها ثابتًا جديدًا تحت اسم mailData والذي سيحوي المعلومات المطلوبة في الدالة sendMail من أجل إرسال رسائل البريد اﻹلكتروني، بعدها أسندت قيمة الثابت mailData إلى الدالة sendMail من أجل إرسال رسالة إلى جميع أصحاب سلات الشراء المتروكة على عناوين بريدهم الإلكتروني المسجل. علينا اﻵن أن نضيف هذا الخاصية إلى ملف index.js، مثل أي نقطة نهاية أضفناها سابقا. نقطة الوصول اﻷولى، خاصة بعرض الصفحة التي أنشأناها للتو: app.get("/loyalty", async (req, res) => { res.render("loyalty"); }); تعرض نقطة الوصول هذه القالب الموجود داخل المجلد views المسمى باسم loyalty.pug. نقطة الوصول الثانية، وهي التي ستحوي على الدالة التي أضفناها قبل قليل بالشكل التالي: app.post("/loyalty", async (req, res) => { const response = await Loyalty(); res.send(response); }); يمكنك اﻵن التوجه إلى الرابط وجرب التطبيق: http://localhost:3000/loyalty اﻵن يمكنك إدخال قسيمة التخفيض في المكان المخصص وإرسالها إلى جميع أصحاب سلات الشراء المتروكة. عند اﻹنتهاء من جميع الخطوات التي ذُكرت في هذا المقال، ستكون الشيفرة البرمجية في الملف index.js كالتالي: import express from "express"; import path from "path"; import AbandonedCarts from "./zid.js"; import AddCoupon from "./addCoupon.js"; import sendMail from "./mail.js"; import Loyalty from "./loyality.js"; const __dirname = path.resolve(); var app = express(); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.set("views", path.join(__dirname, "views")); app.set("view engine", "pug"); app.use(express.static(path.join(__dirname, "public"))); app.get("/carts", async (req, res) => { const response = await AbandonedCarts(); const renderedData = response["abandoned-carts"]; res.render("abandoned", { renderedData }); }); app.get("/", async (req, res) => { res.render("index"); }); app.get("/loyalty", async (req, res) => { res.render("loyalty"); }); app.get("/coupon", async (req, res) => { res.render("coupon"); }); app.get("/error", (req, res) => { res.render("error"); }); app.post("/loyalty", async (req, res) => { const response = await Loyalty(); res.send(response); }); app.post("/add-coupon", async (req, res) => { const data = req.body; const dataToSend = Object.assign({}, data); const response = await AddCoupon(dataToSend); if (response) { res.redirect("/"); } else { res.redirect("/error"); } }); app.post("/mail", async (req, res) => { const data = req.body; const dataToSend = Object.assign({}, data); const send = await sendMail(dataToSend); if (send) { res.send("mail has been sent"); } else { res.send("there was an error"); } }); const port = process.env.PORT || 3000; app.listen(port, () => { console.log(`Server started on ${port}`); }); أخيرًا، تجد شيفرة التطبيق كاملةً على GitHub بالمستودع zid-retention-app. خاتمة لقد استغللنا في البداية الواجهة البرمجية لمنصة زد وما تقدمه من نقاط وصول وبناء فكرة تطبيق منها يمكن أن يستفيد منه أصحاب المتاجر الذين يعتمدون على منصة زد، إذ يمكنك توفير التطبيق لهم بمقابل لكي يستفيدوا هم أيضًا منه وبذلك يستفيد الجميع. لا يقتصر الأمر على فكرة السلات المتروكة وزيادة الولاء وإنما يمكن بناء عشرات التطبيقات المفيدة لأصحاب المتاجر التي توسع من عمل متاجرهم وكان هذا مجرد مثال، وهو في الحقيقة ما يمكنك عمله مع معظم منصات التجارة اﻹلكترونية مثل منصة سلة وشوبيفاي Shopify، يكفي فقط أن تقرأ التوثيق الخاص بالواجهات البرمجية لتلك المنصات وبناء أفكار مفيدة منها. لكي يكون التطبيق تجاريًا، عليك إضافة نظام لتسجيل الاعضاء ونظام اشتراكات وأيضا نظام تسجيل الدخول والخروج مع إمكانية إضافة المعلومات الشخصية لصاحب المتجر الراغب في التسجيل، وهنا سنستخدم الصفحة الرئيسية التي أضفناها إلى التطبيق index.pug، بحيث سيكون بإمكان العميل المسجل إضافة مفتاح المتجر الخاص به سواءً على منصة زد، أو إضافة المعلومات المطلوبة للربط مع التطبيق في حالة استخدامه لمنصة أخرى مثل Shopify. يمكنك أيضًا إضافة خصائص جديدة لتطبيق كما أشرنا مثل إرسال رسالة نصية للعملاء أصحاب سلات الشراء المتروكة بالتزامن مع إرسال بريد إلكتروني. يمكنك استخدام منصات إرسال الرسائل النصية المتوفرة في بلدك إن وجدت أو استخدام حلول مثل Twilio أو MessageBird. وطبعًا يمكنك توسيع الخدمات التي تقدمها إلى خدمات أخرى يطلبها أصحاب المتاجر كما أشرنا وهنا نترك الأمر لك ولإبداعك. تهانينا، لقد أتممت بناء تطبيق مفيد بإمكانك استعماله بطريقة تجارية إن أحببت وﻹطلاق شركتك الناشئة العاملة في هذا المجال، ولم ﻻ توسعها لتشمل منصات أكثر غير منصة زد فقط! نرجو لك كل التوفيق في رحلتك القادمة. اقرأ أيضًا مدخل إلى الواجهات البرمجية API أمثلة عملية لاستخدام واجهة برمجة متاجر زد zid API التعرف على لوحة تحكم متجر زد الإلكتروني وضبط عمليات المتجر كيفية إنشاء متجر إلكتروني متكامل باستعمال منصة زد
  2. تعرفنا في المقال اﻷول على الواجهة البرمجية للتطبيقات API وكيفية استعمالها في تطوير المواقع وتطبيقات الويب على ماهية الواجهات البرمجية وأسس عملها ولماذا نحتاج إليها، وتعلمنا في المقال الثاني، المعنون بـ الاتصال بواجهة برمجة التطبيقات API وفهم عملية الاستيثاق والتصريح كيفية الاتصال بالواجهة البرمجية بصورة صحيحة، وأخذنا مثاﻻ عن ذلك باستخدام الواجهة البرمجية لمنصة زد، وإن كنت تتبعت جميع الخطوات التي ذُكرت في المقالين السابقين، فسنفترض اﻵن أن لديك حساب مطور على منصة زد وأيضا متجر للتجربة عليه أو عد إليهما ثم أكمل بعدهما قراءة هذا المقال. هذا المقال هو جزء من سلسلة مقالات حول الواجهة البرمجية API وكيفية الاستفادة منها في بناء تطبيق ويب: مدخل إلى الواجهات البرمجية API الاتصال بواجهة زد البرمجية وفهم عملية الاستيثاق والتصريح أمثلة عملية لاستخدام واجهة برمجة متاجر زد zid API تطوير تطبيق عملي يزيد من احتفاظ العملاء عبر واجهة زد البرمجية متطلبات مسبقة حتى تستطيع العمل بجميع التجارب، يجب عليك الحصول على كل من مفتاح الوصول Access Token وهو المفتاح المساعد الخاص بحسابك كمطور، وأيضا مفتاح المتجر X-Manager-Token وهو المفتاح المساعد الخاص بالمتجر المنشود الذي ستطبق عليه العملية. يمكنك جلب مفتاح الوصول بعد تفعيل تطبيقك في منصة تطور زد للمطورين أما بخصوص مفتاح المتجر المساعد، فيمكنك جلب واحد من متجر حقيقي منشور أو تجريبي تنشئه بغرض التجربة ولكن يفضل استخدام متجر تجريبي حتى ﻻ يتأثر متجرك الفعلي بأية عمليات تجريبية سنطبقها في هذا المقال (انظر مقال كيفية إنشاء متجر إلكتروني متكامل باستعمال منصة زد). لن أذكر أنك تحتاج لكل من مفتاح الوصول Access Token ومفتاح المتجر X-Manager-Token واللغة في جميع التجارب التي سنجريها على نقاط وصول الواجهة البرمجية ﻷنها مطلوبة في ترويسات الطلبيات كلها دون استثناء. استعراض العملاء توفر واجهة زد البرمجية إمكانية استعراض العملاء عبر إرسال طلب HTTP من النوع GET إلى نقطة الوصول التالية: /managers/store/customers تستعمل نقطة الوصول هذه لاستعراض بيانات عملاء المتجر الذي حددناه بالمفتاح X-Manager-Token المرسل مع الطلبية وتذكر دومًا أننا سنرسل مع الطلبية متفاح المتجر ومفتاح الوصول مع الطلبية حتى لو لم نذكر ذلك صراحةً. المعلومات المطلوبة: page: ويعني كم من صفحة تريد استعراضها per_page: عدد العملاء المراد استعراضهم في الصفحة الواحدة هذه المعلومات نحتاجها في جميع طلباتنا القادمة، وهي تخص ترقيم الصفحات Pagination لترتيب البيانات في واجهة المستخدم بتنسيق مقبول التي نحصل عليها والتي قد تكون بيانات آلاف العملاء. حسب التوثيق، فإنها ترسل مثل استعلام Query، وبالتالي الطلب سيكون كالتالي: سنرسل الطلب بهذا الشكل للواجهة البرمجية لمنصة زد، وننتظر إجابة الخادم Response والتي ستكون كالتالي: نلاحظ أن الرد يحوي على مفتاح Key تحت اسم customers ونوعه مصفوفة، وفي حالتنا هذه، مصفوفة فارغة ﻷن متجرنا التجريبي ﻻ يحوي عملاء مسجلين فيه. إضافة منتج جديد توفر واجهة زد البرمجة إمكانية إضافة منتج جديد إلى المتجر المحدد بالمفتاح المرسل عبر إرسال طلبية إلى نقطة الوصول التالية: /products المعلومات المطلوبة في الترويسة: STORE_ID: وهو الرقم التعريفي الخاص بالمتجر خاصتك، ستحصل على الرقم التعريفي الخاص بالمتجر من نفس الصفحة التي حصلت منها على مفتاح المتجر X-MANGER-TOKEN ROLE: وهو السماحية الخاصة بك، ويمكن أن تأخذ القيمة Manager أي المدير، أو Customer أي عميل، في حالتنا سنحتاج إلى استخدام السماحية Manager. أما جسم الطلب Request Body فيجب أن يحوي المعلومات التالية: cost: وتعني التكلفة ويجب أن تكون سلسلة نصية string quantity: الكمية ويجب أن تكون سلسلة نصية string keywords: الكلمات المفتاحية ويجب أن تكون مصفوفة من السلاسل النصية name: الاسم، ويكون كائن Object يحوي مفتاحين ar و en description: التوصيف ويجب أن يكون كائنًا يحوي مفتاحين ar و en price: السعر ويكون سلسلة نصية sale_price: سعر البيع ويكون سلسلة نصية weight: الوزن، ويكون كائنا يحوي على مفتاحين unit ويعني وحدة القياس، و value وهي القيمة Is_published: و يجب أن يكون بولياني Boolean، وبالتالي إما True أو False، وتعني هل المنتج معروض للشراء أم ﻻ. سنضيف منتجًا جديدًا عن طريق إرسال طلب باستخدام برنامج Insomnia، وسيكون من نوع Post كالتالي: توضح الصورة التالية نموذج عن جسم الطلبية المرسل بصيغة json: إن كانت كل المعلومات المطلوبة صحيحة، فسيُنشأ المنتج الجديد وإرسال معلومات المنتج على النحو التالي: { "id": "37c99a36-4a43-4c96-8566-6158b0263c74", "sku": "Z.111684.16216931837021275", "parent_id": null, "name": { "ar": "منتج تجريبي", "en": "Testing Product" }, "slug": "منتج-تجريبي", "price": 150.0, "sale_price": 130.0, "formatted_price": "150.00 ر.س ", "formatted_sale_price": "130.00 ر.س ", "currency": "SAR", "currency_symbol": "ر.س ", "attributes": [], "categories": [], "display_order": null, "has_options": false, "has_fields": false, "images": [], "is_draft": false, "quantity": 1000, "is_infinite": false, "html_url": "https://zid.store/madjid/products/منتج-تجريبي", "weight": { "value": 0.5, "unit": "kg" }, "keywords": [ "أكاديمية حسوب", "حسوب", "منتج تجريبي" ], "requires_shipping": true, "is_taxable": true, "structure": "standalone", "seo": null, "sold_products_count": null, "cost": 100.0, "is_published": true, "created_at": "2021-05-22T14:19:43.702509Z", "updated_at": "2021-05-22T14:19:43.702542Z", "description": { "ar": "[\"<h1>من الممكن وضع تنسيقات هنا</h1>\"]", "en": "[\"<h1>You can add HMTL here</h1>\"]" }, "variants": [], "custom_user_input_fields": [], "custom_option_fields": [], "options": [], "related_products": [], "next_product": null, "previous_product": null } استعراض المنتجات تتيح الواجهة البرمجية لمنصة زد استعراض جميع المنتجات المعروضة على المتجر، يكفي فقط أن نرسل طلبا من نوع GET إلى نفس نقطة الوصول السابقة: /products وبنفس ترويسة الطلب Headers السابقة، بحيث تُرسل كل من الترويسة STOREID والترويسة ROLE مع إضافة المفتاحين pagesize وpage كالتالي: سترسل الواجهة البرمجية لمنصة زد ردًا Response يحوي جميع المنتجات الموجودة في المتجر في الوقت الحالي سواء كانت معروضة أو مخفية، الرد سيكون مشابهًا للرد التالي: { "count": 1, "next": null, "previous": null, "results": [ { "id": "37c99a36-4a43-4c96-8566-6158b0263c74", "sku": "Z.111684.16216931837021275", "parent_id": null, "name": { "ar": "منتج تجريبي", "en": "Testing Product" }, "slug": "منتج-تجريبي", "price": 150.0, "sale_price": 130.0, "formatted_price": "150.00 ر.س ", "formatted_sale_price": "130.00 ر.س ", "currency": "SAR", "currency_symbol": "ر.س ", "attributes": [], "categories": [], "display_order": null, "has_options": false, "has_fields": false, "images": [], "is_draft": false, "quantity": 1000, "is_infinite": false, "html_url": "https://zid.store/madjid/products/منتج-تجريبي", "weight": { "value": 0.5, "unit": "kg" }, "keywords": [ "أكاديمية حسوب", "حسوب", "منتج تجريبي" ], "requires_shipping": true, "is_taxable": true, "structure": "standalone", "seo": null, "sold_products_count": null, "cost": 100.0, "is_published": true, "created_at": "2021-05-22T14:19:43.702509Z", "updated_at": "2021-05-22T14:19:43.702542Z" } ] } كل المنتجات موجودة داخل المفتاح results وهي مصفوفة كائنات Array Of Objects. استعراض قائمة البلدان المدعومة ﻻستعراض قائمة جميع البلدان التي تدعمها منصة زد، يكفي أن نرسل طلبا من نوع GET إلى نقطة الوصول التالية: /settings/countries كالعادة، يجب أن تحوي ترويسة Header الطلب على المفاتيح المساعدة ولغة الطلب، وستعيد لنا الواجهة البرمجية لمنصة زد، إجابة Response تحوي على مصفوفة كائنات Array Of Objects تحت مفتاح باسم countries بالشكل التالي: استعراض قائمة المدن للحصول على قائمة المدن المدعومة، يجب أن نرسل طلبا من نوع GET إلى نقطة الوصول التالية: /settings/cities/by-country-id/{country_id} بحيث يتم استبدال country_id بالرقم المعرف الخاص بالبلد الذي نريد استعراض المدن الموجودة فيه، فمثلا لو أردنا استعراض المدن الموجودة في المملكة العربية السعودية، سنرسل الطلب كالتالي: /settings/cities/by-country-id/184 لنجرب الآن إرسال الطلبية وسنحصل على نتيجة مشابهة للرد التالي: في حالة كان الرقم التعريفي الخاص بالبلد صحيحًا، سترسل الواجهة البرمجية قائمة المدن على شكل مصفوفة كائنات Array Of Objects تحوي جميع المدن لذلك البلد كما هو واضح في الصورة السابقة. إضافة وسيلة شحن ﻹضافة وسيلة شحن لمتجرك باستخدام الواجهة البرمجية، يكفي أن نرسل طلبًا من النوع POST لنقطة الوصول التالية: /managers/store/delivery-options/add ترويسات الطلب Headers يجب أن تحوي كل من مفتاح الوصول Access Token ومفتاح المتجر X-Manager-Token واللغة Accept-Language مثل العادة. أما بدن الطلب Body فيجب أن يحوي المعلومات التالية: name: اسم وسيلة الشحن المراد إضافتها. cost: تكلفة الشحن وتكون ثابتة. cod_enabled: وتعني الدفع عند اﻹستلام، وتكون إما 0 لتعطيل الخيار أو 1 لتفعيله. cod_fee: تكلفة الدفع عن اﻹستلام إن كانت موجودة. cities: ويجب أن تحتوي على المعرفات الخاصة بالمدن (تُحصّل من خلال الطلب السابق). delivery_estimated_time_ar: وصف للفترة المتوقعة لوصول المشتريات باللغة العربية. delivery_estimated_time_en: وصف للفترة المتوقعة لوصول المشتريات باللغة اﻹنجليزية. سنرسل طلبًا بالشكل التالي: { "name": "Hsoub Delivery", "cost": "50", "cod_enabled": "1", "cod_fee": "20", "cities": [ 1, 71, 76, 38 ], "delivery_estimated_time_ar": "3 أيام", "delivery_estimated_time_en": "3 days" } عند إرسال الطلب، سنتلقى ردًا Response من الواجهة البرمجية يفيد بأن نقطة الوصول هذه قد حصلت على حمايتها، ولم يعد باﻹمكان الوصول إليها من الواجهة البرمجية باستخدام مفتاح الوصول Access Token الخاص بنا وقت كتابة المقال وقد تصبح متاحة لاحقًا أثناء قراءة المقال. هذا مثال جيد عن رسائل الأخطاء المختلفة التي ممكن أن تعيدها الواجهة البرمجية، ويجب أن تحصن تطبيقك جيدًا بمعالجة أي خطأ يحتمل أن تعيده الواجهة البرمجية، إذ يؤخذ بالحسبان عادة رمز الخطأ (في حالتنا هو 403) ويفترض أن تعرف معنى تلك الرموز أثناء الطوير لتعرف كيف تتصرف مع رموز الأخطاء والحالات التي تهمك، وعمومًا هذا الأمر يحتاج إلى مقال منفصل، ننصحك بالاطلاع على مقال مدخل إلى HTTP ومقال رموز الإجابة في HTTP. خاتمة اﻵن، وقد استعرضنا عددًا من نقاط الوصول التي توفرها الواجهة البرمجية لمنصة زد، وتعرفنا على طرق إرسال الطلبات، دعنا نطبق كل ما تعلمنا إلى الآن في تطبيق عملي يستعمل يستفيد من واجهة زد البرمجية وهو بناء تطبيق بسيط لزيادة وﻻء العملاء مع شرح كيفية تحويل هذا التطبيق إلى مشروع تجاري. اقرأ أيضًا المقال التالي: تطوير تطبيق عملي يزيد من احتفاظ العملاء عبر واجهة زد البرمجية كيفية إنشاء متجر إلكتروني متكامل باستعمال منصة زد الواجهة البرمجية Fetch API في جافاسكريبت HTTP - لننطلق: شرح التخاطب بين العميل والخادوم
  3. شرحنا في المقال السابق مدخل إلى الواجهات البرمجية API الفكرة العامة حول الواجهات البرمجية، وكنا قد شبهناها بالنادل في المطعم الذي يأخذ طلبات الزبائن إلى الطباخ والفريق العامل معه من أجل تحضيرها، ومن ثم استلام استجابة الطباخ للطلبية وتوصيلها إلى أصحابها، وهو ما تفعله الواجهات البرمجية بالضبط مع بعض الإختلاف بالنظر إلى طبيعة العمل في مجال التقنية. سنتعرف في هذا المقال أكثر على عملية التواصل التي تنظمها الواجهة البرمجية، ثم سنطبق ذلك عمليًا على واجهة برمجة واخترنا واجهة زد البرمجية للغرض الذي شرحنا في السابق. هذا المقال هو جزء من سلسلة مقالات حول الواجهة البرمجية API وكيفية الاستفادة منها في بناء تطبيق ويب: مدخل إلى الواجهات البرمجية API الاتصال بواجهة زد البرمجية وفهم عملية الاستيثاق والتصريح أمثلة عملية لاستخدام واجهة برمجة متاجر زد zid API تطوير تطبيق عملي يزيد من احتفاظ العملاء عبر واجهة زد البرمجية آلية التواصل وتنظيم عملية الاتصال قبل أن أكمل الحديث عن الواجهة البرمجية، هل سألت نفسك، لماذا ﻻ يذهب الزبائن مباشرةً إلى الطباخ في مقال المطعم السابق ويخبروه بما يريدون تناوله من مختلف الأطباق التي تُقدَّم في المطعم؟ الجواب ببساطة هو أن الطلبيات ستصبح عشوائيةً آنذاك ولن يستطيع الطباخ أن يحضّر أيًا من الطلبات بسبب العشوائية، وقد لا يفهم على الزبون ماذا يريد أي تحصل عشوائية وغموض في الطلب، فكل زبون يطلب طلبيته بصيغة مختلفة عن الآخر قد تكون بلغة أخرى تمامًا. في حالة أخرى، هل يستطيع أي عامل في المطعم أن يكون نادﻻ؟ في هذه الحالة ستكون فوضى أخرى ولكن بدرجة أقل، بحيث هنالك احتمالية كبيرة ﻷن تُحضّر نفس الطلبية أكثر من مرة لنفس الشخص وفي مرات أخرى من الممكن نسيان طلبية زبون آخر، وفي حالة أخرى، لن يكون باﻹمكان معرفة صاحب الطلبية من غيره أو حتى عدم فهم طلبية الزبون. كانت هذه الحالة الخاصة بالمطعم، فلك أن تتخيل كقاميف ستكون في حالة الواجهات البرمجية؟ تقريبا هي نفس الشيء ولكنها بشكل أسوأ بكثير بسبب أن الواجهة البرمجية API تنظِّم الكثير والكثير من الطلبات لعدد كبير جدا من العملاء التي قد تصل إلى أرقام كبيرة وخيالية. حُلت المشكلة في حالة المطعم بتحديد من يستطيع التحدث مع الزبائن وتدريبهم بأخذ الطلبيات إلى الطباخ وفريقه ومن ثم إعادة الاستجابة أو الناتج الذي حُضِّر إلى الزبون نفسه الذي طلبها تحديدًا ولم يسبق أن دخلت مطعمًا ونسي النادل طلبيتي أو جاءني بطلبية أخرى فهل سألت نفسك عن السبب؟ هل رأيته يكتب في ورقة أمامه ويسألك عن اسمك وينظر في الطاولة والموقع برهة ويذهب؟ وهل قلت لنفسك إن تأخر لقد نسيني أو لم يعرفني ثم يعود جالبًا لك طلبيتك التي طلبتها تمامًا دون أي نسيان؟ للنادل آلية يتذكر فيها صاحب كل طلبية وطلبيته بالضبط ولا ينساها مطلقًا والأمر في حالة الواجهة البرمجة مشابه تمامًا. حلت المشكلة السابقة عن طريق ما يسمى المفتاح المساعد Token وهو سلسلة نصية String تخص العميل طالب الخدمة وتميزه تصدرها الواجهة البرمجة غالبًا (سواءً بمقابل مادي أو مجرد التسجيل في منصة مقدم الواجهة البرمجية) بحيث يرسل المفتاح المساعد Token مع كل طلب خدمة إلى الواجهة البرمجية، من ثم تتحقق الواجهة البرمجية من صلاحية المفتاح المساعد، إن كان صالحا، فستُقدَّم الخدمة المطلوبة للعميل، أما إن لم يكن صالحا، فعادةً ما تُرجع رسالة خطأ تفيد بأن المفتاح المساعد غير صالح، أي لا يمكن إلا لأشخاص مخوليين التواصل مع الواجهة البرمجية وإلا لعمت الفوضى وجاء الجميع للاستفادة من الخدمة التي تقدمها الواجهة. التواصل مع واجهة منصة زد البرمجية حتى نفهم أكثر هذه العملية، سنأخذ مثالًا من الحياة العملية، بحيث سنوجه طلبات إلى الواجهة البرمجية لمنصة زد من أجل اﻹستعلام عن بعض الخدمات الخاصة بهم، دعونا نبدأ. قبل أن نبدأ، ستحتاج إلى التالي: حساب مطور على منصة زد برناج إرسال طلبات HTTP مثل Insomnia أو البرنامج الأكثر شهرة Postman (أصبح البرنامج بطيئًا نوعا ما موازنةً ببرنامج Insomnia ولهذا سنستخدم اﻷخير). إنشاء حساب مطور على منصة زد ندخل إلى بوابة المطورين في منصة زد، سنجدها بسيطة وسهلة اﻹستخدام، يكفي فقط أن عنوان بريدك اﻹلكتروني في الخانة المخصصة، كما في الصورة التالية: بعد أن تدخل عنوان بريدك اﻹلكتروني، والضغط على الزر START NOW، سيُعاد توجيهك إلى لوحة تحكم المطورين، أين يمكنك أخذ نظرة عن الواجهة البرمجية لمنصة زد عند الضغط على ZidAPI ﻻكتشاف تفاصيل الواجهة البرمجية لمنصة زد، كما في الصورة الموالية: ستظهر لنا النافذة التالية: وفيها نجد جميع المعلومات اللازمة للاتصال بالواجهة البرمجية لمنصة زد، بحيث ذُكرت جميع نقاط الوصول Endpoints، مع المعلومات التي يجب إرسالها والمعلومات التي ستُحصّل عند كل نقطة وصول. في الجزء Gateway Environments، وعند الضغط على القائمة Production and Sandbox، ستظهر معلومات مهمة، هي نقطة الوصول الرئيسية للواجهة البرمجية، ولكن ما الذي تعنيه Production and Sandbox. ببساطة Production Environment، هي البيئة الإنتاجية للواجهة البرمجية التي عليك استخدامها في مشروعك النهائي المقدم كخدمة للزبائن، بحيث أن كل العمليات التي تحدث فيها، هي عمليات فعلية. أما Sandbox Environment، فهي البيئة التطويرية التجريبية التي تستخدم أثناء عملية التطوير، بحيث أن جميع العمليات التي تتم فيها، هي عمليات تجريبية فقط. في الواجهة البرمجية لمنصة زد، نلاحظ أن اﻹختلاف بين البيئة الإنتاجية والبيئة التطويرية التجريبية طفيف، فهو يمكن فقط في البروتوكول المستخدم HTTP. فهم طلبيات HTTP وأنواعها نريد اﻵن ااتصال بالواجهة البرمجية لمنصة زد، كل المعلومات لدينا ولم يبقى إﻻ عملية اﻹتصال. للقيام بذلك، نحتاج برنامجا ﻹرسال طلبات HTTP، أو ما يسمى باللغة اﻹنجليزية HTTP Client، ولكن ما هو هذا البرنامج، وما هو عمله؟ ببساطة، برنامج HTTP Client، هو وسيط بينك وبين الواجهة البرمجية، بحيث يرسل الطلبات حسب بروتوكول HTTP. هنالك عدة أنواع من الطلبات الخاصة ببروتوكول HTTP، أشهرها GET و POST و PUT و DELETE. كمعلومة جانبية، متصفح اﻹنترنت الذي تعرفه، مثل كروم Google Chrome، وفايرفوكس أو أي متصفح آخر يعتبر HTTP Client، أي لديه القدرة أن يرسل طلبات HTTP للاستزادة في هذه النقطة، سأشرح أنواع طلبيات HTTP وهي: الطلب GET: يستخدم لجلب بيانات من الخادم أو الواجهة البرمجية. الطلب POST: يستخدم ﻹرسال البيانات إلى الخادم أو الواجهة البرمجية. الطلب PUT: يستخدم لتحديث بيانات في الخادم. الطلب DELETE: يستخدم لحذف البيانات على الخادم. استعمال Insomnia لإدارة الطلبيات التجريبية سنستخدم برنامج Insomnia من أجل إرسال الطلبات لواجهة زد البرمجية، يمكنك تنزيل البرنامج من الموقع الرسمي للشركة المطورة. بعد التحميل والتثبيت، ستظهر نافذة البرنامج كما في الصورة: واجهة بسيطة وسهلة اﻹستخدام، أليس كذلك؟ نضغط على الزر New Request ﻹرسال طلب للواجهة البرمجية لمنصة زد: لتسمية الطلب الجديد، يمكنك اختيار أي اسم كان، أو ترك الاسم الافتراضي، ولكن يفضل أن تُسمى الطلبات بأسماء ذات معنى للعمل الذي تنجزه. نوع الطلب، ويمكننا تحديد أي طلب كان حسب حاجتنا وحسب ما تفرضه الواجهة البرمجية. إنشاء وحفظ الطلب الجديد. احفظ الطلب الجديد باسم Get Profiles، لأننا سنتصل بالواجهة البرمجية لمنصة زد من أجل جلب الملفات الشخصية Profiles المتعلقة بحسابنا على منصة زد. التعرف على نقاط الوصول حينما نتصفح صفحة Developer Portal التي وفرتها منصة زد، سنجد توثيقا يخص الواجهة البرمجية لمنصة زد. التوثيق هو شرح لجميع نقاط الوصول Endpoints للواجهة البرمجية، وما هي المعلومات التي عليك إرسالها لكل نقطة وصول والمعلومات التي ستتحصل عليها من نقطة الوصول تلك. تلاحظ أن هناك نقطة وصول تتيح لنا الحصول على الملفات الشخصية Profiles، وهي موجودة على المسار Path: /managers/account/profile تذكر أن علينا إضافة نقطة الوصول الرئيسية للواجهة البرمجية قبل رابط تلك المسارات أو نقاط الوصول الفرعية، وبالتالي يصبح الرابط النهائي الذي علينا توجيه الطلب إليه كالتالي: http://api.zid.dev/app/v1/managers/account/profile ولكن كيف كونا الرابط النهائي لنقطة الوصول هذه؟ اﻷمر بسيط جدا، من التوثيق الخاص بالواجهة البرمجية لمنصة زد، فنجد Servers والتي تحوي الرابط الرئيسي لكل من البيئة الإنتاجية والبيئة التجريبية للواجهة البرمجية. طلب التصريح والاستيثاق من الطلبية بعدها نجد مسار نقطة الوصول Endpoint تمامًا مثل هذا المثال: لكل نقطة وصول معلومات مطلوبة حتى تستطيع الوصول إليها واستخدامها، فمثلا نقطة الوصول الموضح بالصورة تتطلب مُعامِلات Parameters خاصة بها وهي: X-MANAGER-TOKEN: وهو المفتاح المتجر المساعد الذي يخص المتجر اﻹلكتروني المراد تطبيق العملية عليه ولكل متجر في زد مفتاح مساعد خاص به فقط. Accept-Language: وهي اللغة التي تريد أن ترسل لك الواجهة البرمجية الإجابة Response فيها، وتأخذ القيمة ar للغة العربية أو en للغة اﻹنجليزية. الآن، سنرسل الطلب للواجهة البرمجية لمنصة زد، وننتظر الرد: لقد واجهتنا رسالة تفيد بأن علينا إرفاق مفتاح المبرمج المساعد Token مع الطلب حتى يتم التحقق بأننا مخولون للدخول واستعمال نقاط الوصول الخاصة بالواجهة البرمجية، هو نفسه الذي شرحناه آنفًا في بداية المقال فكما ذكرنا أنه يجب أن يكون مصرحًا لك استعمال الواجهة البرمجية وإلا جاء أي أحد واستعملها وستتأكد الواجهة البرمجة من ذلك التصريح وتستوثق منه. تذكر أن العملية مشابهة تمامًا للباب ومفتاحه فلأي مكان باب مثل منزلك عليه باب ولا يخول لأي أحد دخوله إلا من يملك مفتاح الباب، وتخيل أن يكون باب المنزل دون مفتاح أو أن يملك أي أحد مفتاح باب منزلك! العملية هنا نفسها تمامًا. الحصول على مفاتيح التصريح المخولة التوثيق الخاص بالواجهة البرمجية لمنصة زد، يشرح طريقة الحصول على المفتاح المبرمج المساعد أي المفتاح الخاص بك الذي يصرح لك استعمال الواجهة البرمجية، يكفيك أن تتوجه إلى التبويب Subscriptions ومنه أنشئ التطبيق الخاص بك، باستخدام Subscriptions & Key Generation Wizard. سيطلب منك معلومات بسيطة تعريفية بالتطبيق، تابع الصور التالية: عليك الآن أن تنتظر إلى حين الموافقة على التطبيق من طرف فريق منصة زد. بعد أن يوافق فريق منصة زد على تطبيقك، سيصبح لديك حق الاتصال بالواجهة البرمجية لمنصة زد، ولكن بقيت خطوة أخيرة وهي إنشاء مفتاح مساعد Token. هنالك طريقتان: الأولى، عن طريق لوحة التحكم في منصة زد نفسها، بحيث من نفس الصفحة السابقة، نختار التطبيق الذي أنشاناه، ونختار Manage App، وبعدها نختار Sandbox Keys، حتى نستعمل الواجهة البرمجية الخاصة بالتجربة فقط: نضغط على Generate Access Token، لتظهر نافذة منبثقة، تطلب تأكيد توليد المفتاح المساعد Token: بعد الضغط على GENERATE، ستظهر سلسلة نصية متكونة من أحرف وأرقام، علينا نسخها ولصقها في مكان يسهل علينا الرجوع إليه. الطريقة الثانية ﻹنشاء مفتاح مساعد هي أن نتجه إلى التبويب Subscriptions في قسم Zid Developer Portal، ونختار التطبيق الذي أنشأناه سابقًا: نضغط على Sandbox Keys: ثم نضغط بعدها على CURL TO GENERATE ACCESS TOKEN: نختار الرابط الثاني (الطريقة الثانية) ﻹنشاء المفتاح المساعد Access Token ونلضغط على الزر الموجود على الجانب من أجل نسخه، ونفتح برنامج Insomnia: بعدها نختار كما موضح في الصورة: ستظهر نافذة تسألك إن كنت تريد استيراد السطر في نفس النافذة أم نافذة جديدة، اختر ما يناسبك سيُنشَأ طلب جديد من نوع POST مثل الصورة الموالية: اﻵن علينا أن نضيف ترويسة إلى قبل إرسال طلبنا عن طريق الذهاب إلى التبويب Header وإضافته كالتالي: ما الذي يعنيه هذا الجزء من الطلب؟ يعني هذا الجزء ببساطة، إرسال مفتاح فرعي مع الطلب يثبت أن لدينا حسابًا مفعلا في الواجهة البرمجية لمنصة زد حتى يكون بإمكاننا إرسال طلب إنشاء مفتاح مساعد، ولكن من أين أتينا بهته المعلومات؟ هي معلومات موجودة في الرابط الذي نسخناه ولصقناه قبل قليل. إن لم تستوعب الفكرة اﻵن فلا داعي للقلق، سنشرح كل شيء بالتفصيل في المقاﻻت القادمة ويكفي اﻵن أن تضغط على Send، ﻹرسال طلب إنشاء مفتاح مساعد جديد، وسيُرسَل إليك كالتالي: بقيت اﻵن خطوة أخيرة وهي إنشاء متجر تجريبي على منصة زد من أجل التجربة عليه، المنصة تمنحك فترة 14 يوما من أجل اكتشاف خصائص المنصة والتعرف على طريقة التعامل معها (انظر مقال كيفية إنشاء متجر إلكتروني متكامل باستعمال منصة زد لمزيد من التفاصيل حول كيفية إنشاء متجر). بعد أن تنشئ متجرًا على منصة زد، أدخُل إلى حسابك وتوجه إلى صفحة "اﻹعدادات"، ثم اختر "الربط مع الخدمات"، ثم اضغط على زر "قم بإنشاء رمز المصادقة Manager Token": إنشاء أول اتصال مع الواجهة البرمجية اﻵن وبعد أن توافرت لدينا كل المفاتيح والمعلومات المطلوبة للاتصال بالواجهة البرمجية، يمكننا العودة للطلب الذي أنشأناه سابقا واﻹتصال بالواجهة البرمجية لمنصة زد كالتالي: ﻻحظ أننا ضمنا كلًا من مفتاح المبرمج Access Token ومفتاح المتجر Manager Token في ترويسة Header الطلب تحت تسمية Authorization و X-MANAGER-TOKEN على الترتيب، وهو ما يسمح للواجهة البرمجية لمنصة زد من التحقق من قدرتنا على الوصول إلى نقطة الوصول Endpoint هته وهل نمتلك الصلاحية لذلك وتعرف أيضًا أي متجر بالتحديد نريد تطبيق العمليات عليه. إن كنت قد تساءلت لماذا أضفنا كلمة Bearer قبل السلسلة النصية في Authorization، فببساطة هنالك عدة أنواع من المفاتيح المساعدة ولكن أشهرها هي Basic وBearer، اﻹختلاف بينهما هو في نمط التشفير وفك التشفير فقط. خاتمة تعلمنا في هذا المقال كيفية إنشاء أول اتصال مع واجهة برمجية نموذجية -مثل واجهة منصة زد- بتأمين مفاتيح التصريح المطلوبة وكل المعلومات اللازمة لها وأصبح بإمكانك الآن تطبيق ما تعلمته في المقال على أي واجهة برمجية والاتصال بها والاستفادة من الخدمات التي تقدمها على الوجهة التي تريد. سنتعرف في المقال التالي أكثر على واجهة منصة زد والاتصال بمختلف نقاط وصول الواجهة البرمجية والاطلاع على المعلومات التي يمكن أن تزودنا فيها وكيف يمكن الاستفادة منها. اقرأ أيضًا المقال التالي: أمثلة عملية لاستخدام واجهة برمجة متاجر زد zid API التعرف على لوحة تحكم متجر زد الإلكتروني وضبط عمليات المتجر كيفية إنشاء متجر إلكتروني متكامل باستعمال منصة زد الواجهة البرمجية Fetch API في جافاسكريبت
  4. سنتعرف في هذا المقال على مفهوم واجهة برمجية التطبيقات Application Programming Interface، هذا المصطلح السهل المعقد حيث سنحاول فهمه وكيفية بناء مواقع الويب والتطبيقات الحديثة في يومنا هذا بالاعتماد على الواجهات البرمجية ونجيب على سؤال مهم وهو كيف ترتبط الواجهة الأمامية مع الواجهة الخلفية لتطبيق الويب أو الموقع الإلكتروني. هذا المقال هو جزء من سلسلة مقالات حول الواجهة البرمجية API وكيفية الاستفادة منها في بناء تطبيق ويب: مدخل إلى الواجهات البرمجية API الاتصال بواجهة زد البرمجية وفهم عملية الاستيثاق والتصريح أمثلة عملية لاستخدام واجهة برمجة متاجر زد zid API تطوير تطبيق عملي يزيد من احتفاظ العملاء عبر واجهة زد البرمجية مفهوم الواجهة البرمجية للتطبيقات API قبل أن ندخل في أية تفاصيل تقنية عن موضوعنا اليوم، سأحكي لك يومًا في حياة علي. علي هو مبرمج تطبيقات ويب يعمل في إحدى الشركات التقنية العربية، علي يحب تجربة المأكوﻻت المختلفة، بحيث يجرب في كل يوم أكلة جديدة في المطاعم المحيطة وإن سمع بافتتاح مطعم جديد بالقرب من مكان عمله، فإنه ﻻ يتوانى في زيارته وتذوق مختلف اﻷطباق التي يقدمها. ذهب علي ﻷحد المطاعم التي فتحت أبوابها مؤخرا، واختار مكانا هادئًا ونادى النادل يسأله عن اﻷطباق التي يقدمونها من أجل أن يأخذ طلبيته إلى الطباخ لتحضير ما طلبه علي. دوَّن النادل ما يريد علي تناوله من مأكوﻻت وذهب بها إلى الطباخ من أجل تحضيرها، بعد مدة وجيزة، عاد النادل إلى علي وهو يحمل كل ما طلبه وقدمها متمنيا أنه يعجبه اﻷكل، تذوق علي المأكوﻻت وأبدى إعجابه اﻷولي بها، وبدأ في اﻷكل إلى أن أنهى كل ما في الصحون، دفع الحساب، وخرج من المطعم شاكرا النادل على حسن اﻷستقبال. هل تتساءل اﻵن، ما علاقة هذه القصة بالواجهات البرمجية؟ وهل تساءلت يومًا عن طريقة عمل تطبيقات الهواتف الذكية، وكيف تتصل بخوادم الشركات المطورة لها، هل استطعت الوصول إلى إجابات كافية عن ذلك؟ سأبين لك ما العلاقة بين المثال السابق والواجهات البرمجية وكيف أن الواجهات البرمجية ماهي إﻻ تطبيق لمثالنا باختلاف بسيط وهو مكان التطبيق فقط، فمثالنا هو من الواقع الذي نعيشه يوميًا ونراه دائمًا حتى تعودنا عليه حتى أصبحنا ﻻ ندركه، أما الواجهات البرمجية، فقد أصبحت جزءًا ﻻ يتجزأ من حياة مبرمج المواقع وتطبيقات الويب المهنية. كنت قد نوهتك ﻷن تسأل نفسك عن طريقة ربط تطبيقات الهواتف الذكية مع خوادم الشركات. هنالك طريقتين لربط تطبيقات الهواتف الذكية مع خوادم الشركات المطورة، الطريقة اﻷقدم تسمى SOAP وهي اختصار لجملة Simple Object Access Protocol، أما الطريقة اﻷحدث فهي الواجهة البرمجيةللتطبيقات API وهي اختصار لجملة Application Programming Interface، وهي التي سأركز عليها، ولكن باختصار، API هي طريقة لتواصل البرمجيات في ما بينها باستخدام صيغة JavaScript Object Notation والتي تعرف اختصارا بـ JSON. لن أدخل في التفاصيل التاريخية وسأبقى مركزا على الجانب التقني فقط، لهذا أتوقع منك أن تحاول البحث عن تاريخ ابتكار وتطوير تقنية API والتقنية المكملة لها REST والتي هي اختصار لجملة REpresentational State Transfer. مصطلحات وجب معرفتها سنسرد بعض المصطلحات باللغة الإنجليزية والعربية الضروري على كل مطور ويب أن يعرفها: Backend: الواجهة الخلفية، هي المسؤولة عن العمليات المنطقية للنظام، تتعامل مع الملفات أيضا ومع قواعد البيانات. Frontend: الواجهات الأمامية، كل ما يراه المستخدم ويتعامل معه بشكل مباشر، ويتم ربطها مع النظم الخلفية بما يعرف بالواجهة البرمجية للتطبيقات API. API: الواجهة البرمجية للتطبيقات، هي حلقة الوصل ما بين النظم أو الواجهة الخلفية والواجهات الأمامية. Request: الطلب الذي يرسله العميل (قد تكون الواجهة الأمامية) إلى الخادم Server الموجود في الواجهة الخلفية. Header: ترويسة الطلب Request المرسل والذي يحوي بعض البيانات الوصفية التي تصف الطلبية وحالها وأية معلومات إضافية مطلوبة. Body: جسم أو متن الطلب المرسل والذي يحوي غالبًا على البيانات المتبادلة في الطلبية. Response: استجابة أو رد الخادم وهي المعلومات الراجعة من الخادم إلى العميل مقدم الطلب ردًا على طلبه. تحوي المعلومات الراجعة من الخادم إلى العميل على ترويسة Header وأيضا على متن Body. Endpoint: نقطة الوصول، وهي نقطة اتصال الواجهات الأمامية مع موقع محدد في الواجهة الخلفية أي نقطة محددة تتصل عبرها الواجهة الأمامية مع الواجهة الخلفية لغرض محدَّد. HTTP Client Software: عميل خادم HTTP وهو برنامج يساعد على تسريع التعامل مع الواجهات البرمجية بتوفير آلية واضحة في عملية إرسال واستقبال الطلبيات والردود. هل تعرفت على أي من المصطلحات التي ذكرناها قبل قليل؟ لا بأس إن لم تفعل، فسنشرحها لك حتى تكون لديك معرفة مبدئية بموضوع الواجهات البرمجية. لماذا نستخدم الواجهات البرمجية للتطبيقات APIs وما هي فائدتها؟ تُعَد الواجهات البرمجية للتطبيقات طبقة الحماية الأولى First Security Layer للبرمجية الموجودة على خادم الويب، بسبب أنها تفصل ما بين النظم الخلفية والعمليات الجارية على قواعد البيانات عن الواجهات الأمامية سواءً كانت صفحات ويب عادية أو تطبيقات هواتف ذكية. أي أن أي تطبيق ويب أو موقع اليوم يتألف من واجهة خلفية وواجهة أمامية وواجهة برمجية تعد وصلة وصل بينهما. أما الواجهة الخلفية، فتحوي على كامل العمليات والإجراءات والخدمات التي يوفرها التطبيق أو الموقع مثل معالجة صورة أو بيانات أو حتى تقديم خدمة الطقس. أما الواجهة الأمامية فهي الواجهة التي يراها المستخدم والمسؤولة عن عرض البيانات القادمة من الواجهة الخلفية للمستخدم بصورة مناسبة ومتناسقة مع إرسال البيانات من المستخدم إلى الخادم بالشكل الذي يطلبها، فالبيانات المتبادلة تلك تكون بشكلها الخام (تستعمل غالبًا صيغة JSON أو حتى صيغة XML)، أما الواجهة البرمجية للتطبيقات API فهي صلة الوصل كما ذكرنا ووظيفتها استلام البيانات من الواجهة الأمامية وتسلميها للواجهة الخلفية وإرسال البيانات من الواجهة الخلفية إلى الأمامية بطريقة وأسلوب موحد أي هي التي تؤمن عملية التفاهم بين الواجهة الأمامية والخلفية لتأمين التخاطب فيما بينهما. كيف تعمل الواجهات البرمجية للتطبيقات API سأحاول قدر اﻹمكان تبسيط آلية عمل الواجهات البرمجية بمثال عملي من حياتنا اليومية، وليكن مثلا منصة فيسبوك. كما تعلم أنه بإمكانك الدخول إلى حسابك في فيسبوك من أي جهاز تريد، سواءً من هاتفك الذكي أو من جهازك اللوحي أو من جهاز الحاسوب بل بإمكانك الدخول منها مجتمعة وفي نفس الوقت، وهنا يجب أن تطرح سؤاﻻ مهمًا، كيف تتم مزامنة حسابك في كل تلك اﻷجهزة؟ هنا تأتي أهمية الواجهة البرمجية، بحيث أن كل تلك اﻷجهزة متصلة بنظام خلفي واحد وكلها تتصل بالواجهة البرمجية التي تكون حلقة الوصل ما بين كل اﻷجهزة المتصلة و النظام الخلفي. سنأخذ مثاﻻ من حياتنا اليومية وهو موقع فيسبوك، سنقوم بالدخول إلى حسابنا باستخدام الأجهزة التي بحوزتنا، إن لم تكن لديك أجهزة غير جهاز الحاسوب، افتح أكثر من متصفح، ليس نفس المتصفح، مثلا متصفح كروم Google Chrome ومتصفح فايرفوكس Mozilla Firefox، في هذه الحالة يمكنك فتح حسابك 4 مرات باستخدام التصفح الخفي، في متصفح كروم يسمى Incognito Mode أما في متصفح فايرفوكس فيسمى Private Mode. هل قمت بذلك؟ كيف تستطيع إرسال رسائل إلى أصدقائك من أي متصفح وتشاهدها في نفس الوقت من بقية المتصفحات؟ قم بالدخول إلى حسابك على فيسبوك من هاتفك الذكي، من التطبيق الرسمي أو من المتصفح، هل تستطيع أن ترى الرسائل التي قمت بإرسالها على هاتفك أيضا، كيف يحدث ذلك؟ كيف تستطيع الدخول إلى حسابك من أماكن مختلفة في نفس الوقت؟ سأشرح العملية بأكملها بشكل بسيط وبالمقارنة مع مثالنا في بداية المقال وبدون الدخول في التفاصيل الدقيقة في الوقت الحالي. عند دخول علي مطور الويب إلى المطعم، كان عليه أن يختار طاولة محددة برقم حتى يعلم النادل موقعه وأنه يريد تناول الطعام وبالتالي يستطيع تقديم مختلف الخدمات التي يعرضها المطعم. هنا الطاولة وتفاصيلها (من رقم وحجم وغيرهما) تعتبر المكان المتفق عليه من أجل اﻹستفادة من خدمات المطعم، ويمكن القول أنها نقطة الوصول إلى خدمات المطعم Endpoint. في حالة موقع فيسبوك، وعند قيامك فتح التطبيق مثلا، سيتصل تطبيقك بخادم الشركة، في نقطة متفق عليها ومحددة مسبقًا في التطبيق وفيها فقط يستطيع الخادم أن يقدم خدماته للتطبيق. جاء النادل إلى عليٍ والذي يسمى العميل client ليأخذ الطلبات منه، ودون أية ملاحظات أو أي خدمات أخرى، وبعدها ذهب إلى المطبخ ليخبر الطباخ بالطلبات من أجل تحضيرها. هنا نسمي العملية: إرسال طلب Send Request من العميل علي إلى الطباخ في المطعم مقدمة الخدمة. في حالة موقع فيسبوك، أقرب عملية لذلك المثال عملية تسجيل الدخول حيث تُدخل اسم المستخدم الخاص بك مع كلمة المرور، تأخذ الواجهة الأمامية منك هذه المعلومات وترسلها للواجهة الخلفية لموقع فيسبوك لتتحقق منها ومن الطلب الخاص بك، طلب تسجيل الدخول. يستلم الطباخ الطلبية ويتأكد من أنها طلبية صالحة ويمكنك تحضيرها (أي ليست طلبية شراء ملابس مثلًا) ثم يبدأ بتحضيرها وعندما ينتهي منها، يعطيها للنادل الذي يرتبها بدوره في صينية ويأخذها إلى علي ليضعها على طاولته حتى يتسنى له البدء في تذوقها. هذه العملية تسمى: اﻹستجابة Send Response أي استجاب الطباخ لطلبية علي وقدم له ما يريد. وفي حالة موقع فيسبوك، إن كانت المعلومات المقدمة صالحة، سيقوم خادم فيسبوك بالسماح لك بالدخول واستعراض مختلف الصفحات واﻷجزاء الخاصة به والاستفادة من خدمته التي يقدمها. هل اتضحت الصورة العامة اﻵن؟ ببساطة، الواجهة البرمجية تنفذ عمل النادل في المطعم، حيث أن النادل يقوم بأخذ طلبات الزبائن إلى الطباخ وفريقه لتحضيرها وبعد ذلك، يقوم بأخذ تلك استجابة الطباخ لتلك الطلبات إلى أصحابها، أي أن الواجهة البرمجية تأخذ الطلبات من المستخدمين (الواجهة الأمامية) إلى النظام الخلفي لتقوم بعمل محدد ومن ثم تعيد النتائج المتحصل عليها إلى طالبيها أي تعيدها للواجهة الأمامية مرةً أخرى. خاتمة تعرفنا على ماهية الواجهة البرمجية للتطبيقات وأهم المصطلحات فيها وكيف يستفيد منها المطورون في بناء تطبيقات الويب الحديثة واستثمارها في التواصل ما بين الواجهة الأمامية والخلفية لتطبيقات الويب والمواقع الحالية، فالتعامل مع الواجهة البرمجية للتطبيقات ضروري لأي مبرمج متخصص في تطوير الويب، وعليه أن يعي مفهوم الواجهة البرمجة تمامًا إذ أصبح هذا المفهوم هو المفهوم الحديث في التواصل ما بين الواجهة البرمجية الخلفية والأمامية للمواقع وتطبيقات الويب، أضف إلى ذلك أن الكثير من الخدمات والمواقع أصبحت تتيح واجهتها البرمجية (مثل الواجهة البرمجية للمطورين من فيسبوك وتويتر وغيرهما) للاستفادة منها أو حتى هنالك واجهة برمجية مخصصة فقط لتقديم خدمات محددة (مثل واجهة برمجية للحصول على معلومات الطقس) وتقدمها للمطورين للاستفادة من تلك الخدمات في مختلف المشاريع. اقرأ أيضًا المقال التالي: الاتصال بواجهة زد البرمجية وفهم عملية الاستيثاق والتصريح كيفية إنشاء متجر إلكتروني متكامل باستعمال منصة زد الواجهة البرمجية Fetch API في جافاسكريبت
  5. و عليكم السلام و رحمة الله تعالى و بركاته الأمر يعتمد على البلد الذي تقيم فيه حاليا و هل هنالك قوانين تنظم شركات الإنترنت أم لا. إن كان بالفعل قوانين تنظم هذا النوع من النشاطات فمن الأفضل أن تقوم باستشارة أخصائي قانوني في بلدك حتى يعطيك المعلومات المطلوبة لديك حتى تكون في حالة قانونية اتجاه المؤسسات التشريعية في بلدك. في حالة عدم وجود قوانين في بلدك، بإمكانك افتتاح شركة في بلد آخر مثل الإمارات، المملكة المتحدة، الولايات المتحدة. شخصيا أنصحك باختيار الولايات المتحدة لما تقدمه من تسهيلات في هذا الشأن. يمكنك البحث عن شركات أو مكاتب استشارات قانونية من أجل تسهيل و تسريع العملية. يمكنك التواصل مع شركة Stripe فهم يقدمون خدمة إنشاء الشركات في ولاية ديلاوار Delaware بمبلغ 500 دولار تدفع مرة واحدة(و بعدها أظن أن الإشتراك السنوي هو 100 دولار) و لكن ليكن في علمك أن لديهم شروطا لقبول العمل معك و إنشاء الشركة( و في بعض الأحيان يطلبون منك السفر إلى الولايات المتحدة من أجل تخليص بعض العمليات). أتمنى أن أكون قد أفدتك. تحياتي
  6. لا يمكن بأي حال من الأحوال أن تتم المقارنة ما بين لغتي برمجة خصوصا عندما يتعلق الأمر بلغتي PHP و Python. في ما يتعلق بتطوير الويب، فما نراه عموما أن PHP هي الأكثر دعما من حيث توفر الإستضافات المشتركة و التي نجد أن أسعارها منخفضة جدا، و لكن بالإمكان الحصول على سيرفر وهمي VPS لتشغيل المواقع/المنصات التي يتم تطويرها باستخدام Python (أو PHP أو أي لغة برمجة أخرى) بأسعار جيدة جدا، فمثلا شركة Digital Ocean توفر VPS بسعر 5 دولارات شهريا. شخصيا أرى أنه من الأفضل أن تقوم بتجربة كلا اللغتين و بعدها يمكنك إختيار الأنسب لك، و اللغة التي ارتحت لها بشكل أكبر. تحياتي.
  7. شكرا لك أخي أسامة الشركة الأفضل حاليا كما ذكر الأخ الفاضل هي شركة Envato و منصتها Theme Forest و لكن لها شروط كثيرة من أجل قبول تصميماتك في المنصة و لكن كن متأكدا من أنك ما ستجنيه من هناك سيكون مجزيا لحد كبير. توجد أيضا منصة Template Monster و تتميز بأن اسعار القوالب فيها مرتفعة قليلا عن Theme Forest ليست لدي معلومات كافية حولها. توجد المنصة العربية بيكاليكا و على حسب ما رأيته من المنصة فالأمر يستحق التجربة
  8. هنالك العديد من الطرق لجمع التمويل المبدئي اللازم للمشروع - يمكنك العمل في وظائف بسيطة تؤمن لك مبلغا من المال كافيا لإطلاق مشروعك - يمكنك أيضا دخول مجال العمل الحر من أجل جمع المبلغ الذي تحتاجه لإطلاق المشروع - أطلب مالا من أصدقائك أو عائلتك و اشرح لهم المشروع الذي تود الدخول فيه(يمكنك أن تطلب منهم مشاركتك في المشروع بنسب تراها مناسبة لك و لهم عوض ان يكونوا مدينا لهم) - توجد منصات التمويل الجماعي إن كنت ترى بأن فكرة مشروعك تحتاج إلى تمويل كبير نسبيا:توجد منصة ذومال العربية و Kick Starter و التي تقبل المشاريع من بلدان محددة فقط و هنالك أيضا Indiegogo توجد ألف طريقة و طريقة،عليك فقط أن تجد الطريقة الأنسب لك و لمشروعك
  9. و عليكم السلام و رحمة الله تعالى و بركاته سأعطيك نظرة عامة حول صناعة القالب(المقصود بها تجارة القوالب) أفضل مجال للعمل فيه هي قوالب التجارة الإلكترونية عموما و ماجنتو على وجه الخصوص:أسعار قوالب ماجنتو تعتبر الأعلى. أيضا قوالب سكريبت CS Cart تعتبر مرتفعة جدا اذا ما قورنت بغيرها من القوالب.لكن لا أنصحك بأي منهما لسبب رئيسي هو أن عملية بيع قوالب سكريبتات التجارة الإلكترونية بطيء نوعا ما خصوصا فيما يتعلق بماجنتو و CS Cart. أنصحك بتعلم تصميم و تطوير قوالب سكريبت ووردبريس،حاول أن تجعله عاما Multipurpose Theme لأنه يعتبر الأكثر طلبا من العملاء و أولئك الذين يودون بدء مواقع على الأنترنت. أنصحك أيضا بتعلم تصميم و تطوير قوالب منصة Shopify فالمستقبل القريب يوحي بأنها ستكون رائدة في مجال التجارة الإلكترونية. أسعار قوالب ووردبريس عادة ما يتم تسعيرها ما بين 35-59 دولار على منصة Theme Forest. قبل أن تريد تعلم تصميم القوالب عليك فهم آلية عمل السكريبت نفسه(أتحدث هنا عن ووردبريس،ماجنتو،أوبن كارت و غيرها-جميعهم يوفرون دليلا عن طريق بناء القوالب) أما فيما يتعلق بمنصة Shopify فهم يوفرون دليلا شاملا عن كيفية بناء قوالب تتوافق مع المنصة. أتمنى أن أكون قد أفدتك.
  10. Software As A Service و معناها تقديم برمجية ما كخدمة على الأنترنت،تماما مثل برنامج Office 365 الخاص بشركة مايكروسوفت،فهو يوفر برنامج الأوفيس المعروف و لكن عبر الأنترنت
  11. في نظري الشخصي، ﻻ يوجد منتج أو خدمة سهلة المبيع و أخرى صعبة. النقطة الجوهرية في هذا الموضوع هو خدمة أو منتج يحل مشكلة ما بطريقة جيدة و بالتالي سيكون هنالك طلب عليها و بالتالي يمكنك تحقيق عائدات جراء بيعها، هذا من جهة. من جهة أخرى فالتسويق يلعب دورا مهما جدا في بيع الخدمات و المنتجات خصوصا إن كنت تستخدم وسائل تسويق ذات فاعلية مثل أسلوب إعلانات حسوب و جوجل أدسنس (الدفع للنقرة) وبالتالي تحول الجمهور المستهدف إلى مشترين فعليين.
×
×
  • أضف...