كيفية بناء واجهة برمجة تطبيقات Node.js لكتل إيثريوم
نشرت: 2022-03-10كانت تقنية Blockchain في ارتفاع في السنوات العشر الماضية ، وقد جلبت عددًا كبيرًا من المنتجات والمنصات إلى الحياة مثل Chainalysis (تكنولوجيا التمويل) ، و Burstiq (health-tech) ، و Filament (IoT) ، و Opus (تدفق الموسيقى) و بصري (الأمن السيبراني).
من هذه الأمثلة ، يمكننا أن نرى أن blockchain يتقاطع مع العديد من المنتجات وحالات الاستخدام - مما يجعله ضروريًا ومفيدًا للغاية. في التكنولوجيا المالية (fintech) ، يتم استخدامه كسجلات لامركزية للأمان والشفافية في أماكن مثل Chain و Chainalysis ، وهو مفيد أيضًا في التكنولوجيا الصحية لتأمين البيانات الصحية الحساسة في Burstiq و Robomed - حتى لا ننسى تكنولوجيا الوسائط مثل Opus و Audius التي تستخدم أيضًا blockchain لشفافية الإتاوات وبالتالي تحصل على حقوق ملكية كاملة.
يستخدم Ocular الأمان الذي يأتي مع blockchain لإدارة الهوية لأنظمة القياسات الحيوية ، بينما يستخدم Filament دفاتر الأستاذ blockchain للاتصال المشفر في الوقت الفعلي. يوضح هذا كيف أصبحت blockchain أساسية بالنسبة لنا من خلال جعل حياتنا أفضل. ولكن ما هو بالضبط blockchain؟
blockchain هي قاعدة بيانات مشتركة عبر شبكة من أجهزة الكمبيوتر. بمجرد إضافة سجل إلى السلسلة ، من الصعب جدًا تغييره. للتأكد من أن جميع نسخ قاعدة البيانات هي نفسها ، تقوم الشبكة بإجراء فحوصات مستمرة.
فلماذا نحتاج blockchain؟ Blockchain هي طريقة آمنة لتسجيل الأنشطة والحفاظ على البيانات حديثة مع الاحتفاظ بسجل لتاريخها مقارنة بالسجلات أو قواعد البيانات التقليدية حيث تكون الاختراقات والأخطاء وأوقات التوقف ممكنة جدًا. لا يمكن لأي شخص إتلاف البيانات أو حذفها عن طريق الخطأ ، ويمكنك الاستفادة من كل من المسار التاريخي للبيانات وسجل محدث على الفور لا يمكن محوه أو يتعذر الوصول إليه بسبب تعطل الخادم.
نظرًا لتكرار blockchain بالكامل عبر العديد من أجهزة الكمبيوتر ، يمكن لأي مستخدم عرض blockchain بالكامل. لا تتم معالجة المعاملات أو السجلات بواسطة مسؤول مركزي واحد ، ولكن بواسطة شبكة من المستخدمين الذين يعملون للتحقق من البيانات وتحقيق توافق في الآراء.
التطبيقات التي تستخدم blockchain تسمى dApps (التطبيقات اللامركزية). بالنظر حولنا اليوم ، سنجد في الغالب تطبيقات لامركزية في التكنولوجيا المالية ، لكن blockchain يتجاوز التمويل اللامركزي. لدينا منصات صحية ، ومنصات تدفق / مشاركة للموسيقى ، ومنصات للتجارة الإلكترونية ، ومنصات للأمن السيبراني ، و IOTs تتجه نحو التطبيقات اللامركزية (dApps) كما هو مذكور أعلاه.
إذن ، متى يكون من المنطقي التفكير في استخدام blockchain لتطبيقاتنا ، بدلاً من قاعدة بيانات قياسية أو سجل؟
التطبيقات الشائعة لـ Blockchain
- إدارة وتأمين العلاقات الرقمية
في أي وقت تريد الاحتفاظ بسجل طويل الأجل وشفاف للأصول (على سبيل المثال ، لتسجيل حقوق الملكية أو الشقة) ، يمكن أن يكون blockchain هو الحل الأمثل. تعتبر "العقود الذكية" في Ethereum ، على وجه الخصوص ، رائعة لتسهيل العلاقات الرقمية. من خلال العقد الذكي ، يمكن تحرير المدفوعات الآلية عندما يتفق الأطراف في الصفقة على أن شروطهم قد تم الوفاء بها. - القضاء على الوسطاء / حراس البوابات
على سبيل المثال ، يتعين على معظم مقدمي الخدمة حاليًا التفاعل مع الضيوف عبر منصة تجميع مركزية ، مثل Airbnb أو Uber (والتي بدورها ، تأخذ جزءًا من كل معاملة). يمكن لـ Blockchain تغيير كل ذلك.
على سبيل المثال ، TUI مقتنعة تمامًا بقوة blockchain أنها طرق رائدة لربط أصحاب الفنادق والعملاء مباشرة. بهذه الطريقة ، يمكنهم التعامل عبر blockchain بطريقة سهلة وآمنة ومتسقة ، وليس عبر منصة حجز مركزية. - سجل المعاملات الآمنة بين الشركاء لضمان الثقة
قد تكون قاعدة البيانات التقليدية جيدة لتسجيل المعاملات البسيطة بين طرفين ، ولكن عندما تصبح الأمور أكثر تعقيدًا ، يمكن أن تساعد blockchain في تقليل الاختناقات وتبسيط العلاقات. علاوة على ذلك ، فإن الأمان الإضافي للنظام اللامركزي يجعل blockchain مثاليًا للمعاملات بشكل عام.
مثال على ذلك جامعة ملبورن التي بدأت في تخزين سجلاتها في blockchain. إن أكثر حالات الاستخدام الواعدة لـ blockchain في التعليم العالي هي تحويل "حفظ السجلات" للشهادات والشهادات والدبلومات. هذا يوفر الكثير من التكلفة من الخوادم المخصصة للتخزين أو السجلات. - الاحتفاظ بسجلات الإجراءات السابقة للتطبيقات التي تكون فيها البيانات في حالة تدفق مستمر
Blockchain هي طريقة أفضل وأكثر أمانًا لتسجيل النشاط والحفاظ على البيانات حديثة مع الاحتفاظ بسجل لتاريخها. لا يمكن لأي شخص إتلاف البيانات أو حذفها عن طريق الخطأ ، ويمكنك الاستفادة من كل من المسار التاريخي للبيانات ، بالإضافة إلى سجل محدث على الفور. مثال على حالة الاستخدام الجيد هو blockchain في التجارة الإلكترونية ، يتضمن كل من blockchain والتجارة الإلكترونية المعاملات.
تجعل Blockchain هذه المعاملات أكثر أمانًا وأسرع بينما تعتمد عليها أنشطة التجارة الإلكترونية. تتيح تقنية Blockchain للمستخدمين مشاركة الأصول الرقمية وتخزينها بشكل آمن تلقائيًا ويدويًا. تتمتع هذه التقنية بالقدرة على التعامل مع أنشطة المستخدم مثل معالجة الدفع ، والبحث عن المنتجات ، وشراء المنتجات ، وخدمة العملاء. كما أنه يقلل من النفقات التي يتم إنفاقها على إدارة المخزون ومعالجة الدفع. - تجعل اللامركزية من الممكن استخدامها في أي مكان
على عكس ما سبق حيث كان يتعين علينا تقييد أنفسنا بمنطقة معينة لأسباب مختلفة مثل سياسات صرف العملات ، فإن قيود بوابات الدفع تجعل الوصول إلى الموارد المالية للعديد من البلدان غير الموجودة في منطقتك أو قارتك أمرًا صعبًا. مع صعود وقوة اللامركزية في blockchain أو نظام الند للند ، يصبح هذا أسهل للعمل مع البلدان الأخرى.
على سبيل المثال ، يمكن أن يكون لمتجر التجارة الإلكترونية في أوروبا مستهلكون في إفريقيا ولا يتطلب وسيطًا لمعالجة طلبات الدفع الخاصة بهم. علاوة على ذلك ، تفتح هذه التقنيات الأبواب أمام تجار التجزئة عبر الإنترنت للاستفادة من الأسواق الاستهلاكية في البلدان البعيدة باستخدام البيتكوين ، أي العملة المشفرة. - Blockhain هي تقنية محايدة
تعمل Blockchain مع كل مكدس التكنولوجيا الذي يستخدمه المطور. لا يتعين عليك تعلم Node كمطور Python لاستخدام blockchain أو تعلم Golang. هذا يجعل blockchain سهل الاستخدام للغاية.
يمكننا في الواقع استخدامه مباشرة مع تطبيقاتنا الأمامية في Vue / React مع عمل blockchain كقاعدة بياناتنا الوحيدة للمهام البسيطة غير المعقدة واستخدام حالات مثل تحميل البيانات أو الحصول على تجزئات لعرض السجلات لمستخدمينا ، أو بناء ألعاب الواجهة الأمامية مثل الكازينو الألعاب وألعاب المراهنة (التي تتطلب قدرًا كبيرًا من الثقة). أيضًا ، مع قوة web3 ، يمكننا تخزين البيانات في السلسلة مباشرة.
الآن ، لقد رأينا عددًا لا بأس به من مزايا استخدام blockchain ، ولكن متى لا ينبغي لنا أن نتعامل مع blockchain على الإطلاق؟
عيوب Blockchain
- سرعة مخفضة للمعاملات الرقمية
تتطلب Blockchains كميات هائلة من قوة الحوسبة ، والتي تميل إلى تقليل سرعة المعاملات الرقمية ، على الرغم من وجود حلول بديلة ، فمن المستحسن استخدام قواعد البيانات المركزية عند الحاجة إلى معاملات عالية السرعة في أجزاء من الثانية. - ثبات البيانات
لطالما كانت ثبات البيانات أحد أكبر عيوب blockchain. من الواضح أن العديد من الأنظمة تستفيد منه بما في ذلك سلسلة التوريد والأنظمة المالية وما إلى ذلك. ومع ذلك ، فهي تعاني من حقيقة أنه بمجرد كتابة البيانات ، لا يمكن إزالتها. لكل شخص على وجه الأرض الحق في الخصوصية. ومع ذلك ، إذا كان الشخص نفسه يستخدم منصة رقمية تعمل على تقنية blockchain ، فلن يتمكن من إزالة أثره من النظام عندما لا يريده هناك. بكلمات بسيطة ، لا توجد طريقة يمكن من خلالها إزالة أثره - مما يترك حقوق الخصوصية مقطوعة. - يتطلب معرفة الخبرة
يعد تنفيذ وإدارة مشروع blockchain أمرًا صعبًا. يتطلب معرفة دقيقة لخوض العملية برمتها. هذا هو السبب في أنه من الصعب العثور على متخصصين أو خبراء في blockchain لأن الأمر يتطلب الكثير من الوقت والجهد لتدريب خبير blockchain. ومن ثم فإن هذه المقالة هي مكان جيد للبدء ودليل جيد إذا كنت قد بدأت بالفعل. - التوافقية
تعمل شبكات blockchain المتعددة بجد لحل مشكلة دفتر الأستاذ الموزع بشكل فريد مما يجعل من الصعب ربطها أو دمجها مع بعضها البعض. هذا يجعل التواصل بين السلاسل المختلفة صعبًا. - تكامل التطبيقات القديمة
لا تزال العديد من الشركات والتطبيقات تستخدم أنظمة وهندسة معمارية قديمة ؛ يتطلب اعتماد تقنية blockchain إصلاحًا كاملاً لهذه الأنظمة والتي يجب أن أقول أنها غير مجدية بالنسبة للعديد منها.
لا تزال Blockchain تتطور وتنضج طوال الوقت ، لذا لا تتفاجأ إذا تحولت هذه العيوب المذكورة اليوم إلى محترف لاحقًا. تعتبر Bitcoin ، وهي عملة مشفرة ، أحد الأمثلة الشائعة على blockchain ، وهي سلسلة blockchain الشهيرة التي كانت في ازدياد بعيدًا عن عملة البيتكوين المشفرة هي Ethereum blockchain. تركز Bitcoin على العملات المشفرة بينما تركز Ethereum أكثر على العقود الذكية التي كانت القوة الدافعة الرئيسية لمنصات التكنولوجيا الجديدة.
يوصى بقراءة : بيتكوين مقابل إيثريوم: ما الفرق؟
لنبدأ في بناء API الخاص بنا
من خلال الفهم الراسخ لـ blockchain ، دعونا الآن نلقي نظرة على كيفية بناء Ethereum blockchain ودمجها في API قياسي في Node.js. الهدف النهائي هو الحصول على فهم جيد لكيفية بناء dApps ومنصات Blockchain.
تحتوي معظم dApps على بنية وهيكل متشابهين. في الأساس ، لدينا مستخدم يتفاعل مع واجهة dApp الأمامية - سواء على الويب أو الهاتف المحمول - والتي تتفاعل بعد ذلك مع واجهات برمجة التطبيقات الخلفية. تتفاعل الواجهة الخلفية ، عند الطلب ، مع العقد (العقود) الذكية أو blockchain من خلال العقد العامة ؛ هذه إما تشغيل تطبيقات Node.js أو تستخدم الواجهة الخلفية blockchain عن طريق تشغيل برنامج Node.js مباشرة. لا يزال هناك الكثير من الأشياء بين هذه العمليات من اختيار بناء تطبيق لامركزي بالكامل أو تطبيق شبه لامركزي لاختيار ما يجب أن يكون لامركزيًا وكيفية تخزين المفاتيح الخاصة بأمان.
القراءة الموصى بها : هندسة التطبيقات اللامركزية: الواجهة الخلفية ، وأنماط الأمان والتصميم
الأشياء التي يجب أن نعرفها أولاً
في هذا البرنامج التعليمي ، سنحاول إنشاء الواجهة الخلفية لتطبيق متجر الموسيقى اللامركزي الذي يستخدم قوة Ethereum blockchain لتخزين الموسيقى ومشاركتها للتنزيل أو البث.
يتكون الهيكل الأساسي للتطبيق الذي نحاول إنشاءه من ثلاثة أجزاء:
- المصادقة ، والتي تتم عن طريق البريد الإلكتروني ؛ بالطبع نحتاج إلى إضافة كلمة مرور مشفرة إلى التطبيق.
- تخزين البيانات ، مع تخزين بيانات الموسيقى أولاً في ipfs ويتم تخزين عنوان التخزين في blockchain لاستردادها.
- الاسترداد ، مع قدرة أي مستخدم معتمد على الوصول إلى البيانات المخزنة على نظامنا الأساسي واستخدامها.
سنقوم ببناء هذا باستخدام Node.js ، ولكن يمكنك أيضًا البناء باستخدام Python أو أي لغة برمجة أخرى. سنرى أيضًا كيفية تخزين بيانات الوسائط في IPFS ، والحصول على العنوان وكتابة وظائف لتخزين هذا العنوان فيه - واسترداد هذا العنوان من blockchain باستخدام لغة برمجة Solidity.
فيما يلي بعض الأدوات التي يجب أن تكون تحت تصرفنا لبناء أو العمل مع Ethereum و Node.js.
- Node.js
الشرط الأول هو تطبيق Node. نحاول إنشاء تطبيق Node.js ، لذلك نحتاج إلى مترجم. يرجى التأكد من تثبيت Node.js - ويرجى تنزيل أحدث نسخة ثنائية للدعم طويل المدى ( LTS ). - جناح الكمأة
Truffle هي بيئة تطوير واختبار العقود ، بالإضافة إلى خط أنابيب الأصول لـ Ethereum blockchain. يوفر بيئة لتجميع البرامج النصية وتوجيهها وتشغيلها. بمجرد أن تتحدث عن تطوير blockchain ، فإن Truffle هي محطة شعبية للذهاب إليها. تحقق من Truffle Suite على Truffle Suite: Sweet Tools for Smart Contracts. - Ganache CLI
أداة أخرى تعمل بشكل جيد مع الكمأة هي Ganache-CLI. تم بناؤه وصيانته بواسطة فريق Truffle Suite. بعد البناء والتجميع ، تحتاج إلى محاكي لتطوير تطبيقات blockchain وتشغيلها ، ثم نشر العقود الذكية لاستخدامها. يسهل Ganache عليك نشر عقد في برنامج محاكاة دون استخدام الأموال الفعلية لتكلفة المعاملة والحسابات القابلة لإعادة التدوير وغير ذلك الكثير. اقرأ المزيد عن Ganache CLI في Ganache CLI و Ganache. - ريمكس
يعد Remix بمثابة بديل لـ Ganache ، ولكنه يأتي أيضًا مع واجهة مستخدم رسومية للمساعدة في التنقل في نشر واختبار عقود Ethereum الذكية. يمكنك معرفة المزيد حول هذا الموضوع على Remix - Ethereum IDE & community. كل ما عليك فعله هو زيارة https://remix.ethereum.org واستخدام واجهة المستخدم الرسومية لكتابة ونشر العقود الذكية. - ويب 3
Web3 عبارة عن مجموعة من المكتبات التي تتيح لك التفاعل مع عقدة Ethereum. يمكن أن تكون هذه العقد المحلية أو البعيدة للعقد من خلال HTTP أو IPC أو Web Sockets. مقدمة إلى Web3.js · Crash Course لمطور Ethereum Blockchain هو مكان جيد لتعلم القليل عن Web3. - IPFS
بروتوكول أساسي يتم استخدامه في بناء dApps. نظام الملفات بين الكواكب (IPFS) هو بروتوكول وشبكة نظير إلى نظير لتخزين البيانات ومشاركتها في نظام ملفات موزع. يشرح IPFS Powers the Distributed Web المزيد عن IPFS وكيف يتم استخدامه عادةً.
إنشاء واجهة برمجة تطبيقات خلفية من الصفر
لذلك علينا أولاً إنشاء خلفية خلفية لاستخدامها ، ونحن نستخدم Node.js. عندما نريد إنشاء واجهة برمجة تطبيقات Node.js جديدة ، فإن أول شيء سنفعله هو تهيئة حزمة npm. كما تعلم على الأرجح ، يرمز npm إلى Node Package Manager ، ويأتي مُعبأ مسبقًا مع ملف Node.js الثنائي. لذلك أنشأنا مجلدًا جديدًا وأطلقنا عليه اسم "blockchain-music" . نفتح Terminal في دليل المجلد هذا ، ثم نقوم بتشغيل الأمر التالي:
$ npm init -y && touch server.js routes.js
يؤدي هذا إلى بدء المشروع باستخدام ملف package.json والإجابة بنعم على جميع المطالبات. ثم نقوم أيضًا بإنشاء ملف server.js وملف route.js لكتابة وظائف routes
في واجهة برمجة التطبيقات.
بعد كل هذا ، سيتعين عليك تثبيت الحزم التي نحتاجها لجعل تصميمنا سهلًا ومباشرًا. هذه العملية مستمرة ، أي يمكنك تثبيت حزمة في أي وقت أثناء تطوير مشروعك.
دعنا نثبت أهم ما نحتاجه الآن:
- Express.js
- @ الكمأة / عقد
- كمأة
- web3.js
- دوتنف
-
short-id
- MongoDB
- nodemon
سيتعين عليك أيضًا تثبيت Truffle.js عالميًا ، حتى تتمكن من استخدامه في كل مكان في بيئتك المحلية. إذا كنت ترغب في تثبيت كل منهم مرة واحدة ، فقم بتشغيل الكود التالي في Terminal الخاص بك:
$ npm install nodemon truffle-contract dotenv mongodb shortid express web3 --save && npm install truffle -g
تستخدم علامة --save
لحفظ اسم الحزمة في ملف package.json . الغرض من العلامة -g
هو تخزين هذه الحزمة المعينة عالميًا ، حتى نتمكن من استخدامها في أي مشروع سنعمل عليه.
نقوم بعد ذلك بإنشاء ملف .env حيث يمكننا تخزين عنوان URI السري لقاعدة بيانات MongoDB الخاصة بنا للاستخدام. نقوم بذلك عن طريق تشغيل touch.env في Terminal. إذا لم يكن لديك حساب قاعدة بيانات مع MongoDB حتى الآن ، فابدأ بصفحة MongoDB أولاً.
تقوم حزمة dotenv بتصدير متغيرنا المخزن إلى بيئة عملية Node.js. يرجى التأكد من عدم دفع ملف .env عند الدفع إلى المستودعات العامة لتجنب تسريب كلمات المرور والبيانات الخاصة.
بعد ذلك ، يتعين علينا إضافة نصوص لمراحل بناء وتطوير مشروعنا في ملف package.json الخاص بنا. تبدو حزمة json الخاصة بنا حاليًا كما يلي:
{ "name": "test", "version": "1.0.0", "description": "", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1", "socket.io": "^2.3.0", "truffle-contract": "^4.0.31", "web3": "^1.3.0" } }
سنقوم بعد ذلك بإضافة برنامج نصي للبدء إلى ملف package.json لاستخدام خادم nodemon بحيث أنه كلما أجرينا تغييرًا ، فإنه يعيد تشغيل الخادم نفسه ، ويظهر نصًا برمجيًا يستخدم خادم العقدة مباشرةً ، ويمكن أن يبدو كما يلي:
{ "name": "test", "version": "1.0.0", "description": "", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "nodemon server.js", "build": "node server.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "express": "^4.17.1", "socket.io": "^2.3.0", "truffle-contract": "^4.0.31", "web3": "^1.3.0" } }
بعد ذلك ، يتعين علينا تهيئة Truffle للاستخدام في عقدنا الذكي باستخدام حزمة Truffle التي قمنا بتثبيتها عالميًا في وقت سابق. في نفس مجلد مشاريعنا ، نقوم بتشغيل الأمر التالي أدناه في المحطة الطرفية الخاصة بنا:
$ truffle init
ثم يمكننا البدء في كتابة الكود الخاص بنا في ملف server.js . مرة أخرى ، نحاول إنشاء تطبيق متجر موسيقى لامركزي بسيط ، حيث يمكن للعملاء تحميل الموسيقى لكل مستخدم آخر للوصول إليها والاستماع إليها.
يجب أن يكون خادمنا server.js نظيفًا لسهولة اقتران وفصل المكونات ، لذلك سيتم وضع المسارات والوظائف الأخرى في ملفات أخرى مثل route.js . مثالنا server.js يمكن أن يكون:
require('dotenv').config(); const express= require('express') const app =express() const routes = require('./routes') const Web3 = require('web3'); const mongodb = require('mongodb').MongoClient const contract = require('truffle-contract'); app.use(express.json()) mongodb.connect(process.env.DB,{ useUnifiedTopology: true },(err,client)=>{ const db =client.db('Cluster0') //home routes(app,db) app.listen(process.env.PORT || 8082, () => { console.log('listening on port 8082'); }) })
في الأساس ، أعلاه نستورد المكتبات التي require
إليها ، ثم نضيف برمجية وسيطة تسمح باستخدام JSON في واجهة برمجة التطبيقات الخاصة بنا باستخدام app.use
، ثم الاتصال بقاعدة بيانات MongoDB الخاصة بنا والحصول على الوصول إلى قاعدة البيانات ، ثم نحدد مجموعة قاعدة البيانات نحن نحاول الوصول (لهذا البرنامج التعليمي هو "Cluster0" ). بعد ذلك نقوم باستدعاء الوظيفة واستيرادها من ملف المسارات . أخيرًا ، نستمع لأي محاولة اتصالات على المنفذ 8082
.
يعد ملف server.js هذا مجرد أداة بسيطة لبدء تشغيل التطبيق. لاحظ أننا استوردنا route.js . سيحتوي هذا الملف على نقاط نهاية المسار لواجهة برمجة التطبيقات الخاصة بنا. قمنا أيضًا باستيراد الحزم التي نحتاجها لاستخدامها في ملف server.js وقمنا بتهيئتها .
سنقوم بإنشاء خمس نقاط نهاية لاستهلاك المستخدم:
- نقطة نهاية التسجيل لتسجيل المستخدمين فقط عبر البريد الإلكتروني. من الناحية المثالية ، سنفعل ذلك من خلال بريد إلكتروني وكلمة مرور ، ولكن نظرًا لأننا نريد فقط تحديد كل مستخدم ، فلن نغامر بأمان كلمات المرور والتجزئة من أجل اختصار هذا البرنامج التعليمي.
POST /register Requirements: email
- نقطة نهاية تسجيل الدخول للمستخدمين عن طريق البريد الإلكتروني.
POST /login Requirements: email
- تحميل نقطة نهاية للمستخدمين - واجهة برمجة التطبيقات التي تحصل على بيانات ملف الموسيقى. ستقوم الواجهة الأمامية بتحويل ملفات MP3 / WAV إلى مخزن صوتي وإرسال ذلك المخزن المؤقت إلى API.
POST /upload Requirements: name, title of music, music file buffer or URL stored
- نقطة نهاية الوصول التي ستوفر بيانات المخزن المؤقت للموسيقى لأي مستخدم مسجل يطلبها ، وتسجيل من وصل إليها.
GET /access/{email}/{id} Requirements: email, id
- نريد أيضًا توفير الوصول إلى مكتبة الموسيقى بأكملها وإعادة النتائج إلى مستخدم مسجل.
GET /access/{email} Requirements: email
ثم نكتب وظائف المسار الخاصة بنا في ملف route.js الخاص بنا. نحن نستخدم ميزات تخزين واسترجاع قاعدة البيانات ، ثم نتأكد من تصدير وظيفة المسار في نهاية الملف لإتاحة إمكانية الاستيراد في ملف أو مجلد آخر.
const shortid = require('short-id') function routes(app, db){ app.post('/register', (req,res)=>{ let email = req.body.email let idd = shortid.generate() if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.status(400).json({"status":"Failed", "reason":"Already registered"}) }else{ db.insertOne({email}) res.json({"status":"success","id":idd}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/login', (req,res)=>{ let email = req.body.email if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.json({"status":"success","id":doc.id}) }else{ res.status(400).json({"status":"Failed", "reason":"Not recognised"}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/upload', (req,res)=>{ let buffer = req.body.buffer let name = req.body.name let title = req.body.title if(buffer && title){ }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.get('/access/:email/:id', (req,res)=>{ if(req.params.id && req.params.email){ }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) } module.exports = routes
داخل وظيفة route
هذه ، لدينا العديد من الوظائف الأخرى التي يتم استدعاؤها داخل كل من معلمات app
و db
. هذه هي وظائف نقطة نهاية API التي تمكن المستخدمين من تحديد نقطة نهاية في عنوان URL. في النهاية نختار إحدى هذه الوظائف ليتم تنفيذها وتقديم النتائج كاستجابة للطلبات الواردة.
لدينا أربع وظائف رئيسية لنقاط النهاية:
-
get
: لقراءة عمليات التسجيل -
post
: لإنشاء عمليات التسجيل -
put
: لتحديث عمليات التسجيل -
delete
: لحذف عمليات التسجيل
في وظيفة routes
هذه ، استخدمنا عمليتي get
و post
. نستخدم post
لعمليات التسجيل وتسجيل الدخول والتحميل get
إلى عمليات البيانات. لمزيد من التوضيح حول ذلك ، يمكنك مراجعة مقالة Jamie Corkhill حول "كيفية البدء مع Node: مقدمة لواجهات برمجة التطبيقات و HTTP و ES6 + JavaScript".
في الكود أعلاه ، يمكننا أيضًا رؤية بعض عمليات قاعدة البيانات مثل مسار التسجيل . قمنا بتخزين البريد الإلكتروني لمستخدم جديد مع db.createa
من البريد الإلكتروني في وظيفة تسجيل الدخول باستخدام db.findOne
. الآن ، قبل أن نتمكن من القيام بكل ذلك ، نحتاج إلى تسمية مجموعة أو جدول بطريقة db.collection
. هذا هو بالضبط ما سنقوم بتغطيته بعد ذلك.
ملاحظة : لمعرفة المزيد حول عمليات قاعدة البيانات في MongoDB ، تحقق من وثائق mongo Shell Methods.
بناء عقد ذكي بسيط blockchain مع Solidity
سنقوم الآن بكتابة عقد Blockchain في Solidity (هذه هي اللغة التي تمت كتابة العقود الذكية بها) لمجرد تخزين بياناتنا واستعادتها عندما نحتاج إليها. البيانات التي نريد تخزينها هي بيانات ملف الموسيقى ، مما يعني أنه يتعين علينا تحميل الموسيقى إلى IPFS ، ثم تخزين عنوان المخزن المؤقت في blockchain.
أولاً ، نقوم بإنشاء ملف جديد في مجلد العقد وتسميته Inbox.sol . لكتابة عقد ذكي ، من المفيد أن يكون لديك فهم جيد لـ Solidity ، لكنه ليس صعبًا لأنه يشبه JavaScript.
ملاحظة : إذا كنت مهتمًا بمعرفة المزيد عن Solidity ، فقد أضفت بعض الموارد في أسفل المقالة لتبدأ.
pragma solidity ^0.5.0; contract Inbox{ //Structure mapping (string=>string) public ipfsInbox; //Events event ipfsSent(string _ipfsHash, string _address); event inboxResponse(string response); //Modifiers modifier notFull (string memory _string) { bytes memory stringTest = bytes(_string); require(stringTest.length==0); _; } // An empty constructor that creates an instance of the conteact constructor() public{} //takes in receiver's address and IPFS hash. Places the IPFSadress in the receiver's inbox function sendIPFS(string memory _address, string memory _ipfsHash) notFull(ipfsInbox[_address]) public{ ipfsInbox[_address] = _ipfsHash; emit ipfsSent(_ipfsHash, _address); } //retrieves hash function getHash(string memory _address) public view returns(string memory) { string memory ipfs_hash=ipfsInbox[_address]; //emit inboxResponse(ipfs_hash); return ipfs_hash; } }
في العقد المبرم بيننا ، لدينا وظيفتان رئيسيتان: وظائف sendIPFS
و getHash
. قبل أن نتحدث عن الوظائف ، يمكننا أن نرى أنه كان علينا تحديد عقد يسمى Inbox
أولاً. داخل هذه الفئة ، لدينا هياكل مستخدمة في كائن ipfsInbox
(الأحداث الأولى ، ثم المعدلات).
بعد تحديد الهياكل والأحداث ، يتعين علينا تهيئة العقد عن طريق استدعاء وظيفة constructor
. ثم حددنا ثلاث وظائف. (تم استخدام وظيفة checkInbox
في الاختبار لنتائج الاختبار.)
sendIPFS
هو المكان الذي يقوم فيه المستخدم بإدخال المعرف وعنوان التجزئة وبعد ذلك يتم تخزينه على blockchain. تسترد وظيفة getHash
عنوان التجزئة عندما يتم منحه المعرف. مرة أخرى ، المنطق وراء ذلك هو أننا نريد في النهاية تخزين الموسيقى في IPFS. لاختبار كيفية عمله ، يمكنك الانتقال إلى Remix IDE ونسخ العقد ولصقه واختباره ، بالإضافة إلى تصحيح أي أخطاء وتشغيله مرة أخرى (نأمل ألا تكون هناك حاجة لذلك!).
بعد اختبار أن الكود الخاص بنا يعمل بشكل صحيح في الريمكس ، دعنا ننتقل إلى تجميعه محليًا باستخدام مجموعة Truffle. لكن أولاً ، نحتاج إلى إجراء بعض التغييرات على ملفاتنا وإعداد المحاكي الخاص بنا باستخدام ganache-cli
:
أولاً ، دعنا ganache-cli
. في نفس الدليل ، قم بتشغيل الأمر التالي في جهازك الطرفي:
$ npm install ganache-cli -g
ثم لنفتح Terminal ونشغل أمرًا آخر في نفس المجلد:
$ ganache-cli
يؤدي هذا إلى بدء تشغيل المحاكي لعقد blockchain الخاص بنا للاتصال والعمل. قم بتصغير Terminal واستمر مع Terminal الآخر الذي كنت تستخدمه.
انتقل الآن إلى ملف truffle.js إذا كنت تستخدم Linux / Mac OS أو truffle-config.js في Windows ، وقم بتعديل هذا الملف ليبدو كما يلي:
const path = require("path"); module.exports = { // to customize your Truffle configuration! contracts_build_directory: path.join(__dirname, "/build"), networks: { development: { host: "127.0.0.1", port: 8545, network_id: "*" //Match any network id } } };
ما فعلناه بشكل أساسي هو إضافة مسار مجلد الإنشاء حيث يتم تحويل العقد الذكي إلى ملفات JSON. ثم حددنا أيضًا الشبكة التي يجب أن يستخدمها Truffle للترحيل.
ثم ، في مجلد التهجيرات أيضًا ، أنشئ ملفًا جديدًا باسم 2_migrate_inbox.js وأضف الكود التالي داخل الملفات:
var IPFSInbox = artifacts.require("./Inbox.sol"); module.exports = function(deployer) { deployer.deploy(IPFSInbox); };
لقد فعلنا ذلك للحصول على ملف العقد ونشره تلقائيًا في JSON ، باستخدام وظيفة النشر أثناء ترحيل deployer
.
بعد التغييرات المذكورة أعلاه نقوم بتشغيل:
$ truffle compile
يجب أن نرى بعض الرسائل في النهاية والتي تُظهر التجميع الناجح ، مثل:
> Compiled successfully using: - solc: 0.5.16+commit.9c3226ce.Emscripten.clang
بعد ذلك ، نقوم بترحيل عقدنا من خلال تشغيل:
$ truffle migrate
بمجرد قيامنا بترحيل عقودنا بنجاح ، يجب أن يكون لدينا شيء مثل هذا في النهاية:
Summary ======= > Total deployments: 1 > Final cost: 0.00973432 ETH
وها نحن على وشك الانتهاء! لقد قمنا ببناء واجهة برمجة التطبيقات الخاصة بنا مع Node.js ، وقمنا أيضًا بإعداد وبناء عقدنا الذكي.
يجب علينا أيضًا كتابة اختبارات لعقدنا لاختبار سلوك العقد والتأكد من أنه السلوك المطلوب. عادة ما يتم كتابة الاختبارات ووضعها في مجلد test
. اختبار مثال مكتوب في ملف يسمى InboxTest.js تم إنشاؤه في مجلد الاختبار هو:
const IPFSInbox = artifacts.require("./Inbox.sol") contract("IPFSInbox", accounts =>{ it("emit event when you send a ipfs address", async()=>{ //ait for the contract const ipfsInbox = await IPFSInbox.deployed() //set a variable to false and get event listener eventEmitted = false //var event = () await ipfsInbox.ipfsSent((err,res)=>{ eventEmitted=true }) //call the contract function which sends the ipfs address await ipfsInbox.sendIPFS(accounts[1], "sampleAddress", {from: accounts[0]}) assert.equal(eventEmitted, true, "sending an IPFS request does not emit an event") }) })
لذلك نجري الاختبار بإجراء ما يلي:
$ truffle test
يختبر عقدنا مع الملفات الموجودة في مجلد الاختبار ويظهر عدد الاختبارات التي تم اجتيازها وفشلها. في هذا البرنامج التعليمي ، يجب أن نحصل على:
$ truffle test Using network 'development'. Compiling your contracts... =========================== > Compiling .\contracts\Inbox.sol > Artifacts written to C:\Users\Ademola\AppData\Local\Temp\test--2508-n0vZ513BXz4N > Compiled successfully using: — solc: 0.5.16+commit.9c3226ce.Emscripten.clang Contract: IPFSInbox √ emit event when you send an ipfs address (373ms) 1 passing (612ms)
دمج العقد الذكي مع الواجهة الخلفية API باستخدام Web3
في معظم الأوقات عندما ترى برامج تعليمية ، ترى تطبيقات لامركزية مصممة لدمج الواجهة الأمامية مباشرة في blockchain. ولكن هناك أوقات يلزم فيها التكامل مع الواجهة الخلفية أيضًا ، على سبيل المثال عند استخدام واجهات برمجة التطبيقات والخدمات الخلفية لجهة خارجية ، أو عند استخدام blockchain لإنشاء نظام إدارة محتوى.
يعد استخدام Web3 أمرًا مهمًا جدًا لهذا السبب ، حيث يساعدنا في الوصول إلى عقد Ethereum المحلية أو البعيدة واستخدامها في تطبيقاتنا. قبل أن نواصل ، سنناقش عقد Ethereum المحلية والبعيدة. العقد المحلية هي العقد المنتشرة على نظامنا مع محاكيات مثل ganache-cli
ولكن العقدة البعيدة هي تلك التي يتم نشرها على الصنابير / الأنظمة الأساسية عبر الإنترنت مثل ropsten أو rinkeby . للتعمق أكثر ، يمكنك اتباع برنامج تعليمي حول كيفية النشر على دليل مدته 5 دقائق من ropsten لنشر العقود الذكية مع Truffle و Ropsten أو يمكنك استخدام مزود محفظة الكمأة ونشرها عبر طريقة أسهل لنشر العقود الذكية الخاصة بك.
نحن نستخدم ganache-cli
في هذا البرنامج التعليمي ، ولكن إذا كنا ننشر على ropsten ، فيجب علينا نسخ عنوان عقدنا أو تخزينه في مكان ما مثل ملف env الخاص بنا ، ثم الانتقال لتحديث ملف server.js ، واستيراد web3 ، واستيراد العقد الذي تم ترحيله وإعداد مثيل Web3.
require('dotenv').config(); const express= require('express') const app =express() const routes = require('./routes') const Web3 = require('web3'); const mongodb = require('mongodb').MongoClient const contract = require('truffle-contract'); const artifacts = require('./build/Inbox.json'); app.use(express.json()) if (typeof web3 !== 'undefined') { var web3 = new Web3(web3.currentProvider) } else { var web3 = new Web3(new Web3.providers.HttpProvider('https://localhost:8545')) } const LMS = contract(artifacts) LMS.setProvider(web3.currentProvider) mongodb.connect(process.env.DB,{ useUnifiedTopology: true }, async(err,client)=>{ const db =client.db('Cluster0') const accounts = await web3.eth.getAccounts(); const lms = await LMS.deployed(); //const lms = LMS.at(contract_address) for remote nodes deployed on ropsten or rinkeby routes(app,db, lms, accounts) app.listen(process.env.PORT || 8082, () => { console.log('listening on port '+ (process.env.PORT || 8082)); }) })
في ملف server.js ، نتحقق مما إذا كان مثيل web3 قد تمت تهيئته بالفعل. إذا لم يكن الأمر كذلك ، فإننا نقوم بتهيئته على منفذ الشبكة الذي حددناه سابقًا ( 8545
). ثم نبني عقدًا استنادًا إلى ملف JSON الذي تم ترحيله وحزمة truffle-contract
، وقمنا بتعيين مزود العقد على مزود مثيل Web3 الذي يجب أن يكون قد تمت تهيئته الآن.
ثم نحصل على حسابات عن طريق web3.eth.getAccounts
. بالنسبة لمرحلة التطوير ، نسمي الوظيفة المنشورة في فئة العقد لدينا والتي تطلب ganache-cli
- والتي لا تزال قيد التشغيل - أن تعطينا عنوان عقد لاستخدامه. ولكن إذا قمنا بالفعل بنشر عقدنا على عقدة بعيدة ، فإننا نسمي دالة تقوم بإدخال العنوان كوسيطة. تم التعليق على دالة العينة أسفل متغير lms
المحدد في الكود أعلاه. ثم نقوم باستدعاء وظيفة routes
لإدخال مثيل التطبيق ، ومثيل قاعدة البيانات ، ومثيل العقد ( lms
) ، وبيانات الحسابات كوسائط. أخيرًا ، نستمع إلى الطلبات على المنفذ 8082
.
أيضًا ، الآن ، يجب أن نثبت حزمة MongoDB ، لأننا نستخدمها في واجهة برمجة التطبيقات الخاصة بنا كقاعدة بياناتنا. بمجرد حصولنا على ذلك ، ننتقل إلى صفحة المسارات حيث نستخدم الطرق المحددة في العقد لإنجاز مهام مثل حفظ واسترداد بيانات الموسيقى.
في النهاية ، يجب أن تبدو مساراتنا path.js بالشكل التالي:
const shortid = require('short-id') const IPFS =require('ipfs-api'); const ipfs = IPFS({ host: 'ipfs.infura.io', port: 5001,protocol: 'https' }); function routes(app, dbe, lms, accounts){ let db= dbe.collection('music-users') let music = dbe.collection('music-store') app.post('/register', (req,res)=>{ let email = req.body.email let idd = shortid.generate() if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.status(400).json({"status":"Failed", "reason":"Already registered"}) }else{ db.insertOne({email}) res.json({"status":"success","id":idd}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/login', (req,res)=>{ let email = req.body.email if(email){ db.findOne({email}, (err, doc)=>{ if(doc){ res.json({"status":"success","id":doc.id}) }else{ res.status(400).json({"status":"Failed", "reason":"Not recognised"}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.post('/upload', async (req,res)=>{ let buffer = req.body.buffer let name = req.body.name let title = req.body.title let id = shortid.generate() + shortid.generate() if(buffer && title){ let ipfsHash = await ipfs.add(buffer) let hash = ipfsHash[0].hash lms.sendIPFS(id, hash, {from: accounts[0]}) .then((_hash, _address)=>{ music.insertOne({id,hash, title,name}) res.json({"status":"success", id}) }) .catch(err=>{ res.status(500).json({"status":"Failed", "reason":"Upload error occured"}) }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.get('/access/:email', (req,res)=>{ if(req.params.email){ db.findOne({email: req.body.email}, (err,doc)=>{ if(doc){ let data = music.find().toArray() res.json({"status":"success", data}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) app.get('/access/:email/:id', (req,res)=>{ let id = req.params.id if(req.params.id && req.params.email){ db.findOne({email:req.body.email},(err,doc)=>{ if(doc){ lms.getHash(id, {from: accounts[0]}) .then(async(hash)=>{ let data = await ipfs.files.get(hash) res.json({"status":"success", data: data.content}) }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) }else{ res.status(400).json({"status":"Failed", "reason":"wrong input"}) } }) } module.exports = routes
At the beginning of the routes file, we imported the short-id
package and ipfs-http-client
and then initialized IPFS with the HTTP client using the backend URL ipfs.infura.io
and port 5001
. This allowed us to use the IPFS methods to upload and retrieve data from IPFS (check out more here).
In the upload route, we save the audio buffer to IPFS which is better compared to just storing it on the blockchain for anyone registered or unregistered to use. Then we saved the address of the buffer in the blockchain by generating an ID and using it as an identifier in the sendIFPS
function. Finally, then we save all the other data associated with the music file to our database. We should not forget to update our argument in the routes function since we changed it in the server.js file.
In the access route using id
, we then retrieve our data by getting the id
from the request, using the id
to access the IPFS hash address, and then access the audio buffer using the address. But this requires authentication of a user by email which is done before anything else.
Phew, we're done ! Right now we have an API that can receive requests from users, access a database, and communicate to a node that has the software running on them. We shouldn't forget that we have to export our function with module.exports
though!
As we have noticed, our app is a decentralized app . However, it's not fully decentralized as we only stored our address data on the blockchain and every other piece of data was stored securely in a centralized database which is the basis for semi-dApps . So the consumption of data can be done directly via request or using a frontend application in JavaScript to send fetch requests.
Our music store backend app can now safely store music data and provide access to anyone who needs to access it, provided it is a registered user. Using blockchain for music sharing makes it cheaper to store music data while focusing on connecting artists directly with users, and perhaps it could help them generate revenue that way. This wouldn't require a middleman that uses royalty; instead, all of the revenue would go to the artist as users request their music to either download or stream. A good example of a music streaming application that uses blockchain just like this is Opus OPUS: Decentralized music sharing platform. However, there are also a few others like Musicoin, Audius, and Resonate.
ماذا بعد؟
The final thing after coding is to start our server by running npm run start
or npm run build
and test our backend endpoints on either the browser or with Postman. After running and testing our API we could add more features to our backend and blockchain smart contract. If you'd like to get more guidance on that, please check the further reading section for more articles.
It's worth mentioning that it is critical to write unit and integration tests for our API to ensure correct and desirable behaviors. Once we have all of that done, we can deploy our application on the cloud for public use. This can be done on its own with or without adding a frontend (microservices) on Heroku, GCP, or AWS for public use. Happy coding!
Note : You can always check my repo for reference. Also, please note that the .env file containing the MongoDB database URI is included for security reasons.
Further Reading And Related Resources
- “How to Build Ethereum Dapp with React.js: Complete Step-By-Step Guide,” Gregory McCubbin
- “Ethereum + IPFS + React DApp Tutorial Pt. 1,” Alexander Ma
- “Ethereum Development with Go,” Miguel Mota
- “Create your first Ethereum dAPP with Web3 and Vue.JS (Part 1),” Nico Vergauwen
- “Deploy a Smart Contract on Ethereum with Python, Truffle and web3py,” Gabriel Saldanha
- “Why Use Blockchain Technology?,” Bernard Marr
- “How To Build Your Own Blockchain Using Node.js,” DevTeam.Space
- “How To Build A Blockchain App With Ethereum, Web3.js & Solidity Smart Contracts,” Gregory McCubbin
- “How To Build A Simple Cryptocurrency Blockchain In Node.js,” Alfrick Opidi
- “How Blockchain Technology Is Going To Revolutionize Ecommerce,” Sergii Shanin
- “4 Ways Blockchain Will Transform Higher Education — Smarter With Gartner,” Susan Moore
- “How To Learn Solidity: The Ultimate Ethereum Coding Tutorial,” Ryan Molecke
- “Developing Ethereum Smart Contracts For Beginners,” Coursetro
- “Learn about Ethereum,” Ethereum official site