دليل Deno: أمثلة على العمل باستخدام JavaScript من جانب الخادم الجديد و TypeScript Runtime



يوم جيد ، أيها الأصدقاء!



أقدم انتباهكم إلى ترجمة مقال "The Deno Handbook: A TypeScript Runtime Tutorial with Code Examples" لـ Flavio Copes.



في هذه المقالة سوف نتعلم كيفية العمل مع دينو. سنقارنه بـ Node.js ونبني بواجهة برمجة تطبيقات REST بسيطة معها.



ما هو دينو؟



إذا كنت معتادًا على Node.js ، نظام JavaScript البيئي الشهير من جانب الخادم ، فإن Deno هو نفس الشيء إلى حد كبير. تقريبًا ، لكن ليس تمامًا.



لنبدأ بقائمة ميزات Deno التي أحبها أكثر من غيرها:



  • يعتمد على JavaScript الحديث
  • لديها مكتبة قياسية قابلة للتوسيع
  • يحتوي على دعم TypeScript قياسي (وهذا يعني أنه ليس عليك ترجمة TypeScript يدويًا ، فإن Deno يقوم بذلك تلقائيًا)
  • يدعم وحدات ES
  • ليس لديها مدير حزم
  • لديها ملف await
  • لديها مرفق اختبار مدمج
  • هدفه هو أقصى توافق للمتصفح. لهذا ، فإنه يوفر fetchكائنًا مضمنًا وعموميًاwindow


في هذا البرنامج التعليمي ، سوف نستكشف كل هذه الاحتمالات.



بعد التعرف على Deno وقدراته ، سيبدو Node.js قديمًا بعض الشيء.



خاصة وأن Node.js يعتمد على وظائف رد الاتصال (تمت كتابته قبل الوعود وغير المتزامن / الانتظار). من غير المحتمل أن تظهر هناك على الإطلاق ، لأن هذا يعني أن هناك حاجة إلى تغييرات أساسية.



Node.js رائع وسيظل المعيار الفعلي في عالم JavaScript. ومع ذلك ، أعتقد أن شعبية Deno ستنمو بسرعة بفضل دعم TypeScript والمكتبة القياسية الحديثة.



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



لماذا دينو؟ لماذا الان؟



تم الإعلان عن Deno منذ عامين تقريبًا بواسطة مبتكر Node.js Ryan Dahl في JSConf EU. شاهد فيديو YouTube ، إنه ممتع للغاية ويجب أن ترى ما إذا كنت تعمل مع Node.js و JavaScript.



كل مدير مشروع (مبتكر) مجبر على اتخاذ قرارات. يأسف ريان على بعض القرارات المبكرة في Node. بالإضافة إلى ذلك ، تتقدم التكنولوجيا وأصبح JavaScript لغة مختلفة تمامًا اليوم عما كانت عليه في عام 2009 عندما كانت Node. فكر في العودة إلى ES6 / 2016/2017 وما إلى ذلك.



لذلك قرر بدء مشروع جديد ، نوع من الموجة الثانية من تطبيقات JavaScript من جانب الخادم.



السبب في أنني أكتب هذا المقال فقط الآن هو أن التكنولوجيا تستغرق وقتًا طويلاً لتنضج. أخيرًا ، حصلنا على Deno 1.0 (تم إصداره في 13 مايو 2020) ، وهو أول إصدار مستقر.



قد يبدو هذا رقمًا شائعًا ، ولكن 1.0 يعني أنه لن يكون هناك أي تغييرات جذرية حتى الإصدار 2.0 من Deno. عندما تتعلم تقنية جديدة ، فأنت لا تريدها أن تتغير بسرعة كبيرة.



هل يجب أن تتعلم دينو؟



سؤال جيد.



يتطلب تعلم شيء جديد مثل Deno الكثير من الجهد. نصيحتي: إذا كنت بدأت للتو مع JS من جانب الخادم ولا تعرف Node.js حتى الآن ، ولم تكتب TypeScript من قبل ، فابدأ بـ Node.



لم يُطرد أحد من قبل لاختياره Node (إعادة صياغة اقتباس مشهور).



ولكن إذا كنت تحب TypeScript ، والذي لا يعتمد على عدد كبير من حزم npm ، وتريد استخدامه في كل مكان await، فقد يكون Deno هو ما تبحث عنه.



هل سيحل محل Node.js؟



لا. Node.js هي شركة عملاقة ، سلطة كبيرة ، تقنية مدعومة جيدًا بشكل لا يصدق لن تذهب إلى أي مكان في العقد المقبل.



دعم TypeScript من الدرجة الأولى



تمت كتابة Deno بلغة Rust و TypeScript ، وهما لغتان شائعتان جدًا في عالم اليوم.



هذا يعني أننا نحصل على الكثير من الفوائد من TypeScript ، حتى لو كنا نكتب JavaScript.



لا يتطلب تشغيل رمز TypeScript مع Deno تجميعًا مسبقًا - يقوم Deno بذلك تلقائيًا.



لا يتعين عليك كتابة كود TypeScript ، ولكن حقيقة أن نواة Deno مكتوبة بلغة TypeScript تحدث فرقًا كبيرًا.



أولاً ، هناك نسبة كبيرة من مطوري JavaScript يحبون TypeScript.



ثانيًا ، يمكن للأدوات التي تستخدمها الحصول على الكثير من المعلومات حول برنامج TypeScript مثل Deno.



هذا يعني أنه عندما نكتب تعليمات برمجية في VS Code ، على سبيل المثال (التي تكاملت بشكل وثيق مع TypeScript منذ إنشائها) ، فإننا نحصل على مزايا مثل التحقق من النوع عند كتابة التعليمات البرمجية أو قدرات IntelliSense المتقدمة. بمعنى آخر ، تصبح مساعدة محرر الكود أكثر فاعلية.



الاختلافات من Node.js



نظرًا لأن Deno هو أساسًا بديل لـ Node.js ، فمن المنطقي المقارنة بين الاثنين.



جنرال لواء:



  • كلاهما يعتمد على محرك V8
  • كلاهما رائع لتطوير JavaScript من جانب الخادم


اختلافات:



  • العقدة مكتوبة بلغة C ++ و JavaScript. تمت كتابة Deno بلغة Rust و TypeScript.
  • لدى Node مدير حزم رسمي npm. لا يمتلك Deno مثل هذا المدير ، ولكنه يتيح لك بدلاً من ذلك استيراد أي وحدة باستخدام عنوان URL.
  • تستخدم Node بنية CommonJS لاستيراد الحزم. يستخدم Deno الطريقة الرسمية - وحدات ES.
  • Deno ECMAScript , Node.js .
  • Deno () . . Node.js , .
  • Deno , .. , , Go, . .




إن عدم وجود مدير حزم واستخدام عنوان URL للحصول على حزم واستيرادها له مزايا وعيوب. إحدى الميزات الرئيسية هي المرونة الكبيرة في القدرة على إنشاء الحزم دون الحاجة إلى نشرها في مستودع مثل npm.



أعتقد أن بعض البدائل لمدير الحزم في Deno ستظهر عاجلاً أم آجلاً.



يستضيف موقع Deno الرسمي حزم الطرف الثالث: https://deno.land/x/



تثبيت Deno



يكفي الحديث! لنقم بتثبيت Deno.



أسهل طريقة للقيام بذلك هي استخدام Homebrew:



    brew install deno 






طرق التثبيت الأخرى مذكورة هنا .



بعد التثبيت ، يصبح الأمر متاحًا deno. إليك المساعدة التي يمكنك الحصول عليها عن طريق كتابة deno --help:



flavio@mbp~> deno --help
deno 0.42.0
A secure JavaScript and TypeScript runtime

Docs: https://deno.land/std/manual.md
Modules: https://deno.land/std/ https://deno.land/x/
Bugs: https://github.com/denoland/deno/issues

To start the REPL, supply no arguments:
  deno

To execute a script:
  deno run https://deno.land/std/examples/welcome.ts
  deno https://deno.land/std/examples/welcome.ts

To evaluate code in the shell:
  deno eval "console.log(30933 + 404)"

Run 'deno help run' for 'run'-specific flags.

USAGE:
    deno [OPTIONS] [SUBCOMMAND]

OPTIONS:
    -h, --help
            Prints help information

    -L, --log-level <log-level>
            Set log level [possible values: debug, info]

    -q, --quiet
            Suppress diagnostic output
            By default, subcommands print human-readable diagnostic messages to stderr.
            If the flag is set, restrict these messages to errors.
    -V, --version
            Prints version information


SUBCOMMANDS:
    bundle         Bundle module and dependencies into single file
    cache          Cache the dependencies
    completions    Generate shell completions
    doc            Show documentation for a module
    eval           Eval script
    fmt            Format source files
    help           Prints this message or the help of the given subcommand(s)
    info           Show info about cache or info related to source file
    install        Install script as an executable
    repl           Read Eval Print Loop
    run            Run a program given a filename or url to the module
    test           Run tests
    types          Print runtime TypeScript declarations
    upgrade        Upgrade deno executable to newest version

ENVIRONMENT VARIABLES:
    DENO_DIR             Set deno's base directory (defaults to $HOME/.deno)
    DENO_INSTALL_ROOT    Set deno install's output directory
                         (defaults to $HOME/.deno/bin)
    NO_COLOR             Set to disable color
    HTTP_PROXY           Proxy address for HTTP requests
                         (module downloads, fetch)
    HTTPS_PROXY          Same but for HTTPS


فرق دينو



هل لاحظت المقطع SUBCOMMANDS؟ هذه قائمة بجميع الأوامر التي يمكننا تشغيلها. ما الفرق التي لدينا؟



  • bundle - يجمع تبعيات الوحدة النمطية والمشروع في ملف واحد
  • cache - مخابئ التبعيات
  • completions - يولد عبوات شل
  • doc - يعرض وثائق الوحدة
  • eval - تستخدم لحساب كتلة من التعليمات البرمجية ، على سبيل المثال deno eval "console.log(1 + 2)"
  • fmt- منسق كود مدمج (كما goFmtفي Go)
  • help - يعرض قائمة بالأوامر المساعدة
  • info - يعرض معلومات حول ذاكرة التخزين المؤقت أو الملف
  • install - يحدد البرنامج النصي على أنه قابل للتنفيذ
  • repl - دورة قراءة-حساب-إخراج (افتراضي)
  • run - يدير البرنامج بالاسم المحدد أو عنوان URL للوحدة
  • test - يدير الاختبارات
  • types - يعرض قائمة بميزات TypeScript
  • upgrade - تحديثات Deno إلى أحدث إصدار


يمكنك الجري deno <subcommand> helpللحصول على معلومات حول أمر معين ، على سبيل المثال deno run --help.



يمكننا استخدام أمر denoلبدء حلقة قراءة-تقييم-إخراج:







هذا هو نفس البدء deno repl. تُستخدم



عادةً denoلتشغيل تطبيق Deno الموجود في ملف TypeScript.



يمكنك تشغيل ملفات TypeScript (.ts) وملفات JavaScript (.js).



إذا كنت مستخدمًا جديدًا لـ TypeScript ، فلا تقلق: تمت كتابة Deno بلغة TypeScript ، ولكن يمكنك كتابة تطبيقات العميل الخاصة بك في JavaScript.



أول تطبيق على Deno



لنقم بإنشاء تطبيقنا الأول.



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



يقوم Deno بتنزيل البرنامج وتجميعه وتشغيله:







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



هذا البرنامج بسيط للغاية وهو عبارة عن مكالمة console.log():



console.log('Welcome to Deno ') //     ,    


إذا فتحت https://deno.land/std/examples/welcome.ts في متصفح ، فسترى ما يلي:







غريب ، أليس كذلك؟ ربما كنت تتوقع أن ترى ملف TypeScript ، ولكن بدلاً من ذلك حصلت على صفحة ويب. النقطة المهمة هي أن خادم موقع ويب Deno يعرف أنك تستخدم متصفحًا ويوفر لك صفحة أكثر سهولة في الاستخدام.



قم بتحميل نفس عنوان URL باستخدام wget، على سبيل المثال ، واحصل عليه text/plainبدلاً من ذلك text/html:







عند إعادة تشغيل البرنامج ، بفضل التخزين المؤقت ، لا يلزم إعادة التشغيل:







باستخدام علامة ، --reloadيمكنك إجراء إعادة تشغيل قسري:







deno runيحتوي على العديد من الوظائف المختلفة التي لا يتم عرضها من خلال deno --help. لكي تراهم ، يجب عليك تشغيل deno run --help:



flavio@mbp~> deno run --help
deno-run
Run a program given a filename or url to the module.

By default all programs are run in sandbox without access to disk, network or
ability to spawn subprocesses.
    deno run https://deno.land/std/examples/welcome.ts

Grant all permissions:
    deno run -A https://deno.land/std/http/file_server.ts

Grant permission to read from disk and listen to network:
    deno run --allow-read --allow-net https://deno.land/std/http/file_server.ts

Grant permission to read whitelisted files from disk:
    deno run --allow-read=/etc https://deno.land/std/http/file_server.ts

USAGE:
    deno run [OPTIONS] <SCRIPT_ARG>...

OPTIONS:
    -A, --allow-all
            Allow all permissions

        --allow-env
            Allow environment access

        --allow-hrtime
            Allow high resolution time measurement

        --allow-net=<allow-net>
            Allow network access

        --allow-plugin
            Allow loading plugins

        --allow-read=<allow-read>
            Allow file system read access

        --allow-run
            Allow running subprocesses

        --allow-write=<allow-write>
            Allow file system write access

        --cached-only
            Require that remote dependencies are already cached

        --cert <FILE>
            Load certificate authority from PEM encoded file

    -c, --config <FILE>
            Load tsconfig.json configuration file

    -h, --help
            Prints help information

        --importmap <FILE>
            UNSTABLE:
            Load import map file
            Docs: https://deno.land/std/manual.md#import-maps
            Specification: https://wicg.github.io/import-maps/
            Examples: https://github.com/WICG/import-maps#the-import-map
        --inspect=<HOST:PORT>
            activate inspector on host:port (default: 127.0.0.1:9229)

        --inspect-brk=<HOST:PORT>
            activate inspector on host:port and break at start of user script

        --lock <FILE>
            Check the specified lock file

        --lock-write
            Write lock file. Use with --lock.

    -L, --log-level <log-level>
            Set log level [possible values: debug, info]

        --no-remote
            Do not resolve remote modules

    -q, --quiet
            Suppress diagnostic output
            By default, subcommands print human-readable diagnostic messages to stderr.
            If the flag is set, restrict these messages to errors.
    -r, --reload=<CACHE_BLACKLIST>
            Reload source code cache (recompile TypeScript)
            --reload
                Reload everything
            --reload=https://deno.land/std
                Reload only standard modules
            --reload=https://deno.land/std/fs/utils.ts,https://deno.land/std/fmt/colors.ts
                Reloads specific modules
        --seed <NUMBER>
            Seed Math.random()

        --unstable
            Enable unstable APIs

        --v8-flags=<v8-flags>
            Set V8 command line options. For help: --v8-flags=--help


ARGS:
    <SCRIPT_ARG>...
            script args


أمثلة التعليمات البرمجية



هناك أمثلة أخرى على موقع Deno يمكن العثور عليها هنا .



في وقت كتابة هذا التقرير ، كان من الممكن العثور على ما يلي في المستودع المحدد:



  • cat.ts - يعرض محتويات الملفات التي تم تمريرها كوسيطات
  • catj.ts- يفعل نفس الشيء ، cat.tsلكنه يقوم أولاً ببعض التلاعب بمحتويات الملفات
  • chat/ - تنفيذ الدردشة
  • colors.ts - مثال على تصميم النص باستخدام الوحدات
  • curl.ts- تطبيق بسيط curlينتج عنه محتوى عنوان URL الذي تم تمريره كوسيطة
  • echo_server.ts - خادم صدى TCP
  • gist.ts - برنامج لوضع الملفات في gist.github.com
  • test.ts - برنامج الاختبار
  • welcome.ts - البرنامج الذي أطلقناه
  • xeval.ts- يسمح لك بتشغيل TypeScript التي تم الحصول عليها من أي مصدر بيانات قياسي. deno xevalتم حذفه من قائمة الفرق الرسمية


أول تطبيق حقيقي على Deno



لنكتب بعض التعليمات البرمجية.



تمت كتابة التطبيق الأول الذي أطلقناه deno run https://deno.land/std/examples/welcome.tsبالفعل ، لذا لم تتعلم أي شيء جديد عن Deno.



لنبدأ بمثال قياسي منشور على موقع Deno الإلكتروني:



import { serve } from 'https://deno.land/std/http/server.ts'
const s = serve({ port: 8000 })
console.log('http://localhost:8000/')
for await (const req of s) {
    req.respond({ body: 'Hello World\n' })
}


نحن هنا نستورد دالة serveمن وحدة http/server. نرى؟ لم يكن علينا تثبيته ، ولم يتم تخزينه على جهاز الكمبيوتر الخاص بنا مثل وحدات Node. هذا هو أحد أسباب التثبيت السريع لـ Deno.



بمساعدة المساعدة https://deno.land/std/http/server.tsنقوم باستيراد أحدث إصدار من الوحدة. يمكن استيراد إصدار محدد باستخدام @VERSION:



import { serve } from 'https://deno.land/std@v0.42.0/http/server.ts'


هذه هي الوظيفة serve:



/**
 * Create a HTTP server
 *
 *     import { serve } from "https://deno.land/std/http/server.ts";
 *     const body = "Hello World\n";
 *     const s = serve({ port: 8000 });
 *     for await (const req of s) {
 *       req.respond({ body });
 *     }
 */
 export function serve(addr: string | HTTPOptions): Server {
  if (typeof addr === 'string') {
    const [hostname, port] = addr.split(':')
    addr = { hostname, port: Number(port) }
  }

  const listener = listen(addr)
  return new Server(listener)
}


بعد ذلك ، نسمي الوظيفة serve()ونمررها كائنًا بخاصية port.



ثم نقوم بتشغيل حلقة للرد على كل طلب من الخادم:



for await (const req of s) {
  req.respond({ body: 'Hello World\n' })
}


لاحظ أننا نستخدم الكلمة الأساسية awaitدون تغليف الكود في asyncدالة.



لنقم بتشغيل البرنامج محليًا. أنا أستخدم VS Code ، لكن يمكنك استخدام أي محرر.



أوصي بتثبيت امتداد من justjavac (هناك ملحق آخر بنفس الاسم ، لكنه مهمل وقد يختفي في المستقبل):







يوفر الامتداد العديد من الأدوات المساعدة لمساعدتك في كتابة تطبيقات Deno.



لنقم بإنشاء ملف app.tsوإدخال الكود الخاص بنا







فيه deno run app.ts: قم







بتشغيله باستخدام : سيقوم Deno بتحميل جميع التبعيات التي يحتاجها البرنامج ، ولكن أولاً الذي نقوم باستيراده في الملف.



يحتوي ملف https://deno.land/std/http/server.ts على العديد من التبعيات الخاصة به:



import { encode } from '../encoding/utf8.ts'
import { BufReader, BufWriter } from '../io/bufio.ts'
import { assert } from '../testing/asserts.ts'
import { deferred, Deferred, MuxAsyncIterator } from '../async/mod.ts'
import {
    bodyReader,
    chunkedBodyReader,
    emptyReader,
    writeResponse,
    readRequest,
} from './_io.ts'
import Listener = Deno.Listener
import Conn = Deno.Conn
import Reader = Deno.Reader


يتم استيراد هذه التبعيات تلقائيًا.



في النهاية لدينا مشكلة:







ما الذي يحدث؟ حصلنا على إذن رفض الخطأ.



لنتحدث عن الصندوق الرمل.



صندوق الرمل



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



ماذا يعني هذا؟



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



لا شيء يمنع تطبيق Node.js من الحصول على مفتاح SSH أو أي معلومات أخرى من نظامك وإرسالها إلى الخادم. لهذا السبب نقوم عادةً بتثبيت حزم Node من مصادر موثوقة فقط. ولكن كيف نعرف ما إذا كان أحد المشاريع التي نستخدمها قد تعرض للاختراق؟



يحاكي Deno نظام الأذونات الذي يستخدمه المتصفح. لا تستطيع شفرة JavaScript التي تعمل في المستعرض أن تفعل أي شيء مع نظامك ما لم تسمح له صراحةً بذلك.



بالعودة إلى Deno ، إذا احتاج أحد البرامج إلى الوصول إلى الشبكة ، فعلينا منحه الإذن للقيام بذلك.



يتم ذلك باستخدام العلم --allow-net:



deno run --allow-net app.ts






الخادم يعمل الآن على المنفذ 8000:







العلامات الأخرى:



  • --allow-env - يسمح بالوصول إلى متغيرات البيئة
  • --allow-hrtime - يسمح بقياس دقة عالية
  • --allow-net=<allow-net> - يسمح بالوصول إلى الشبكة
  • --allow-plugin - يسمح بتحميل الإضافات
  • --allow-read=<allow-read> - يسمح بقراءة الملفات
  • --allow-run - يسمح ببدء العمليات الفرعية
  • --allow-write=<allow-write> - يسمح لكتابة الملفات
  • --allow-all- يمنح جميع الأذونات (مماثلة -A)


ضوابط ل net، readو writeقد يكون جزئيا. على سبيل المثال، يمكننا أن نسمح الملفات للقراءة فقط التي هي في دليل معين: --allow-read=/dev.



تنسيق الكود



أحد الأشياء التي أحبها في Go هو الأمر gofmt. كل كود Go يبدو كما هو. الجميع يستخدمه gofmt.



عادةً ما يستخدم مطورو JavaScript Prettier ، وفي deno fmtالواقع يستخدمونها أيضًا تحت القص.



لنفترض أن لديك مثل هذا الملف المنسق بشكل سيئ:







تبدأ deno fmt app.tsويتم التنسيق التلقائي مع الفواصل المنقوطة المفقودة:







مكتبة قياسية



مكتبة دينو القياسية واسعة جدًا على الرغم من عمر المشروع.



وهي تشمل ما يلي:



  • archieve - مرافق للأرشفة
  • async - الأدوات المساعدة للعمل مع التعليمات البرمجية غير المتزامنة
  • bytes - الوظائف المساعدة لتقسيم البايت
  • datetime - تحليل التواريخ / الأوقات
  • encoding - ترميز / فك في صيغ مختلفة
  • flags - تحليل أعلام سطر الأوامر
  • fmt - التشكيل والعرض
  • fs - واجهة تطبيق للعمل مع نظام الملفات
  • hash - مكتبة التشفير
  • http - خادم HTTP
  • io - مكتبة عمليات الإدخال / الإخراج
  • log - المرافق للتسجيل
  • mime - دعم البيانات المختلطة
  • node - طبقة التوافق مع العُقدة
  • path - العمل مع المسارات
  • ws - مآخذ الويب


مثال آخر



دعنا نلقي نظرة على مثال رسمي آخر - cat.ts:



const filenames = Deno.args
for (const filename of filenames) {
    const file = await Deno.open(filename)
    await Deno.copy(file, Deno.stdout)
    file.close()
}


نقوم بتعيين filenamesالمحتوى إلى متغير Deno.args، وهو متغير يحتوي على الوسائط التي تم تمريرها باستخدام سطر الأوامر.



نحن نكررها ، ولكل منها ، نستخدم أولاً Deno.open()لفتح الملف ثم Deno.copy()نسخ المحتوى إلى Deno.stdout. أخيرًا ، نغلق الملف.



اذا ركضت:



deno run https://deno.land/std/examples/cat.ts


سيتم تحميل البرنامج وتجميعه ، لكن لا شيء يحدث لأننا لم نجتاز أي وسيطات.



الآن لنجرب هذا:



deno run https://deno.land/std/examples/cat.ts app.ts


حصلنا







على خطأ في الإذن: لا يمتلك Deno حق الوصول إلى النظام افتراضيًا. لنمنحه هذا الإذن من خلال --allow-read:



deno run --allow-read=./ https://deno.land/std/examples/cat.ts app.ts






هل يوجد Express / Hapi / Koa / * لدينو؟



بالطبع. ألق نظرة على المشاريع التالية:





مثال: استخدام البلوط لإنشاء واجهة برمجة تطبيقات REST



سأقوم بإنشاء REST API باستخدام Oak. البلوط مثير للاهتمام لأنه مستوحى من Koa ، البرنامج الوسيط الشهير لـ NOde.js ، وله تركيب مماثل.



ستكون واجهة برمجة التطبيقات الخاصة بنا بسيطة للغاية.



سيخزن خادمنا في الذاكرة قائمة بالكلاب وأسمائهم وأعمارهم.



نريد الحصول على الوظائف التالية:



  • إضافة كلاب جديدة إلى القائمة
  • احصل على قائمة بكل الكلاب
  • الحصول على معلومات حول كلب معين
  • إزالة كلب من القائمة
  • تحديث عمر الكلب


سنقوم بكتابة الكود في Typescript ، لكن لا شيء يمنعك من القيام بذلك في JavaScript - فقط لا تحدد أنواع البيانات.



نقوم بإنشاء ملف app.ts.



لنبدأ باستيراد العناصر من Applicationوإلى :RouterOak



import { Application, Router } from 'https://deno.land/x/oak/mod.ts'


نحصل على متغيرات البيئة PORT و HOST:



const env = Deno.env.toObject()
const PORT = env.PORT || 4000
const HOST = env.HOST || '127.0.0.1'


بشكل افتراضي ، سيتم تشغيل تطبيقنا على المضيف المحلي: 4000.



قم بإنشاء تطبيق Oak وقم بتشغيله:



const router = new Router()

const app = new Application()

app.use(router.routes())
app.use(router.allowedMethods())

console.log(`Listening on port ${PORT}...`)

await app.listen(`${HOST}:${PORT}`)


يجب أن يعمل التطبيق الآن.



نحن نفحص:



deno run --allow-env --allow-net app.ts


يقوم Deno بتنزيل التبعيات:







ويبدأ الاستماع على المنفذ 4000.



عند إعادة التشغيل ، سيتم تخطي خطوة التثبيت بفضل التخزين المؤقت:







حدد واجهة للكلب ، ثم حدد مصفوفة dogتحتوي على الكائنات Dog:



interface Dog {
  name: string
  age: number
}

let dogs: Array<Dog> = [
  {
    name: 'Roger',
    age: 8,
  },
  {
    name: 'Syd',
    age: 7,
  },
]


لنبدأ في تنفيذ API.



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



const router = new Router()

router
    .get('/dogs', getDogs)
    .get('/dogs/:name', getDog)
    .post('/dogs', addDog)
    .put('/dogs/:name', updateDog)
    .delete('/dogs/:name', removeDog)


لقد حددنا ما يلي:



  • GET /dogs
  • GET /dogs/:name
  • POST /dogs
  • PUT /dogs/:name
  • DELETE /dogs/:name




دعونا ننفذ هذه المسارات واحدة تلو الأخرى.



لنبدأ GET /dogs، الذي يعرض قائمة بكل الكلاب:



export const getDogs = ({ response }: { response: any }) => {
    response.body = dogs
}






إليك كيفية الحصول على كلب معين بالاسم:



export const getDog = ({
  params,
  response,
}: {
    params: {
        name: string
    },
    response: any
}) => {
    const dog = dogs.filter(dog => dog.name === params.name)
    if (dog.length) {
        response.status = 200
        response.body = dog[0]
        return
    }

    response.status = 400
    response.body = { msg: `Cannot find dog ${params.name}` }
}






إليك كيفية إضافة كلب جديد إلى القائمة:



export const addDog = async ({
    request,
    response,
}: {
    request: any
    response: any
}) => {
    const body = await request.body()
    const dog: Dog = await body.value
    dogs.push(dog)

    response.body = { msg: 'OK' }
    response.status = 200
}






إليك كيفية تحديث عمر كلبك:



export const updateDog = async ({
    params,
    request,
    response,
}: {
    params: {
        name: string
    },
    request: any
    response: any
}) => {
    const temp = dogs.filter((existingDog) => existingDog.name === params.name)
    const body = await request.body()
    const { age }: { age: number } = await body.value

    if (temp.length) {
        temp[0].age = age
        response.status = 200
        response.body = { msg: 'OK' }
        return
    }

    response.status = 400
    response.body = { msg: `Cannot find dog ${params.name}` }
}






وإليك طريقة إزالة كلب من القائمة:



export const removeDog = ({
    params,
    response,
}: {
    params: {
        name: string
    },
    response: any
}) => {
    const lengthBefore = dogs.length
    dogs = dogs.filter((dog) => dog.name !== params.name)

    if (dogs.length === lengthBefore) {
        response.status = 400
        response.body = { msg: `Cannot find dog ${params.name}` }
        return
    }

    response.body = { msg: 'OK' }
    response.status = 200
}






كود التطبيق الكامل:



import { Application, Router } from 'https://deno.land/x/oak/mod.ts'

const env = Deno.env.toObject()
const PORT = env.PORT || 4000
const HOST = env.HOST || '127.0.0.1'

interface Dog {
  name: string
  age: number
}

let dogs: Array<Dog> = [
  {
    name: 'Roger',
    age: 8,
  },
  {
    name: 'Syd',
    age: 7,
  },
]

export const getDogs = ({ response }: { response: any }) => {
  response.body = dogs
}

export const getDog = ({
  params,
  response,
}: {
  params: {
    name: string
  },
  response: any
}) => {
  const dog = dogs.filter(dog => dog.name === params.name)
  if (dog.length) {
    response.status = 200
    response.body = dog[0]
    return
  }

  response.status = 400
  response.body = { msg: `Cannot find dog ${params.name}` }
}

export const addDog = async ({
  request,
  response,
}: {
  request: any
  response: any
}) => {
  const body = await request.body()
  const { name, age }: { name: string; age: number } = await body.value
  dogs.push({
    name: name,
    age: age,
  })

  response.body = { msg: 'OK' }
  response.status = 200
}

export const updateDog = async ({
  params,
  request,
  response,
}: {
  params: {
    name: string
  },
  request: any
  response: any
}) => {
  const temp = dogs.filter((existingDog) => existingDog.name === params.name)
  const body = await request.body()
  const { age }: { age: number } = await body.value

  if (temp.length) {
    temp[0].age = age
    response.status = 200
    response.body = { msg: 'OK' }
    return
  }

  response.status = 400
  response.body = { msg: `Cannot find dog ${params.name}` }
}

export const removeDog = ({
  params,
  response,
}: {
  params: {
    name: string
  },
  response: any
}) => {
  const lengthBefore = dogs.length
  dogs = dogs.filter(dog => dog.name !== params.name)

  if (dogs.length === lengthBefore) {
    response.status = 400
    response.body = { msg: `Cannot find dog ${params.name}` }
    return
  }

  response.body = { msg: 'OK' }
  response.status = 200
}

const router = new Router()
router
  .get('/dogs', getDogs)
  .get('/dogs/:name', getDog)
  .post('/dogs', addDog)
  .put('/dogs/:name', updateDog)
  .delete('/dogs/:name', removeDog)

const app = new Application()

app.use(router.routes())
app.use(router.allowedMethods())

console.log(`Listening on port ${PORT}...`)

await app.listen(`${HOST}:${PORT}`)


شكرآ لك على أهتمامك.