برنامه نویسی

نوشتن یک سرویس میکرو با پشتیبانی از پایگاه داده با Raku و Humming-Bird

در اوایل سال جاری، من یک چارچوب برنامه وب برای Raku به نام Humming-Bird ساختم، از آغاز فروتنانه آن راه درازی پیموده است. در این پست می‌خواهم نحوه استفاده از Humming-Bird را برای ایجاد سرویس‌های سریع، قابل اعتماد و بومی ابری توضیح دهم.

در حال راه اندازی

برای شروع، باید مطمئن شوید که Raku را نصب کرده اید، توصیه می کنم از Rakubrew استفاده کنید. سپس می‌خواهیم Zef را نصب کنیم، اگر در Raku تازه کار هستید، Zef اساساً فقط NPM یا CPAN برای Raku است، توسط Ugexe شگفت‌انگیز نوشته شده است و مدیر بسته پیش‌فرض است که مردم با Raku استفاده می‌کنند. اگر Raku را با Rakubrew نصب کرده اید، می توانید به سادگی اجرا کنید rakubrew build-zef و تمام تنظیمات را برای شما انجام می دهد.

در نهایت، ما می خواهیم Humming-Bird را نصب کنیم، می توانیم این کار را به سادگی با اجرای:

zef install Humming-Bird
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با این کار آخرین نسخه پایدار Humming-Bird ارائه می شود.

سلام دنیا

اکنون که همه پیش نیازها را نصب کرده ایم، بیایید یک برنامه وب ساده “Hello World” بنویسیم. Humming-Bird واقعا ساده است، بنابراین چیز زیادی برای آن وجود ندارد!

use Humming-Bird::Core;

get("https://dev.to/", -> $request, $response {
    $response.html('<h1>Hello World!</h1>');
});

listen(8080);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حال اگر این اسکریپت را به عنوان ذخیره کنیم app.raku سپس آن را با:

raku app.raku
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما می توانیم به http://localhost:8080 و باید ببینیم:

سلام دنیا

بیایید آنچه را که اینجا در حال رخ دادن است تجزیه و تحلیل کنیم.

use Humming-Bird::Core;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کلیه اعضای صادراتی Humming-Bird را وارد می کند. این شامل قابلیت ایجاد مسیرها و راه اندازی سرور است.

get("https://dev.to/", -> $request, $response {
    $response.html('<h1>Hello World!</h1>');
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما یک مسیر GET را در “https://dev.to/” ثبت می کنیم و یک بلوک، تابع ناشناس AKA، AKA lambda را برای مدیریت آن متصل می کنیم. این لامبدا باید یک درخواست، و یک پاسخ، و یک پاسخ را دریافت کند. تمام روش های ارائه شده توسط شی پاسخ به طور ضمنی خود را برمی گرداند، بنابراین زنجیره زدن و بازگشت آن را آسان می کند. همچنین، آخرین عبارت ارزیابی شده، بازگشت لامبدا خواهد بود.

listen(8080);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

شروع می کند a Humming-Bird::HTTPServer در پورت 8080

طراحی سرویس ما

اکنون که همه چیز راه اندازی شده و کار می کند. بیایید به طراحی سرویس خود بپردازیم. الزامات ما طراحی سرویسی است که نکات نهایی زیر را ارائه دهد:

  • گرفتن ‘/users’: همه کاربران موجود در پایگاه داده را برمی گرداند
  • پست ‘/users’: در صورت معتبر بودن یک کاربر جدید در پایگاه داده ایجاد می کند
  • گرفتن ‘/users/:id’: یک کاربر با شناسه آنها دریافت کنید
  • حذف ‘/users/:id’: یک کاربر را با شناسه خود حذف کنید

راه اندازی پایگاه داده

ما همچنین یک پایگاه داده برای این کار می خواهیم، ​​بنابراین ماژول قابل اعتماد DBIish را که توسط جامعه Raku نگهداری می شود را وارد می کنیم.

zef install DBIish
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما از SQLite3 برای این کار استفاده خواهیم کرد، بنابراین مطمئن شوید که lib های لازم را روی دستگاه خود نصب کرده اید. در جعبه اوبونتو که به شکل زیر است:

sudo apt-get install sqlite3 libsqlite3-dev
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا بیایید وصل کنیم DBIish به کد موجود ما. ما به سادگی همیشه اسکریپت ایجاد را برای جدول خود هر زمان که سرور شروع می شود اجرا می کنیم، فقط برای اینکه آن را نسبتاً ساده نگه داریم.

use DBIish;

my $db = DBIish.connect('SQLite', :database<user-db.sqlite3>);

$db.execute(q:to/SQL/);
CREATE TABLE IF NOT EXISTS user (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(20),
    age INTEGER,
    email VARCHAR
)
SQL
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این کد نسبتاً مستقیم است، اما من آن را برای افرادی که استفاده نکرده‌اند، کمی توضیح می‌دهم DBIish قبل از.

use DBIish;

my $db = DBIish.connect('SQLite', :database<user-db.sqlite3>);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ابتدا وارد می کنیم DBIish سپس یک متغیر جدید اختصاص می دهیم $db برای نگه داشتن اتصال ما، که یک اتصال SQLite3 است، با نام فایل user-db.sqlite3.

$db.execute(q:to/SQL/);
CREATE TABLE IF NOT EXISTS user (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(20),
    age INTEGER,
    email VARCHAR
)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس، ما سعی می کنیم جدول خود را ایجاد کنیم، توجه داشته باشید که هر بار که این اسکریپت را اجرا می کنیم این کار اجرا می شود. تمام q:to/SQL/ چیزی که اساسا می گوید: خطوط زیر را به عنوان یک رشته بخوانید تا زمانی که دنباله پایانی مشخص شده در بین / را بخوانید.

به طور کلی کل فایل ما به صورت زیر است:

use Humming-Bird::Core;
use DBIish;

my $db = DBIish.connect('SQLite', :database<user-db.sqlite3>);

$db.execute(q:to/SQL/);
CREATE TABLE IF NOT EXISTS user (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(20),
    age INTEGER,
    email VARCHAR
)
SQL

get("https://dev.to/", -> $request, $response {
    $response.html('<h1>Hello World!</h1>')
});

listen(8080);
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

راه اندازی نقاط پایانی ما

اکنون که پایگاه داده ما آماده است، اجازه دهید کار روی نقاط پایانی خود را شروع کنیم، ابتدا اجازه دهید یک نقطه پایانی برای دریافت همه کاربران ایجاد کنیم.

ما می توانیم این را به سادگی به عنوان بازگرداندن محتویات “jsonified” پایگاه داده خود بیان کنیم. Humming-Bird به ماژولی به نام بستگی دارد JSON::Fast، ما باید آن را هم وارد کنیم. اضافه کردن:

use JSON::Fast;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به بالای پروژه خود می رویم تا آن را به داخل بکشیم. این به ما امکان دسترسی به آن را می دهد to-json و from-json روال های فرعی

دریافت همه کاربران

get('/users', -> $request, $response {
    my @user-rows = $db.execute('SELECT * FROM user').allrows(:array-of-hash);
    my $json = to-json(@user-rows);
    $response.json($json);
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با این کار، همه کاربران از پایگاه داده به عنوان آرایه‌ای از هش انتخاب می‌شوند، سپس آن را به JSON تبدیل می‌کنند JSON::Fast‘s to-json، سپس آن را با JSON نوع محتوا از طریق ارسال کنید $response.json.

توجه داشته باشید: Humming-Bird واقعا هیچ جادویی نمی کند .json و .html روش‌ها فقط بسته‌بندی‌هایی هستند برای: .write($body, 'application/json') و .write($body, 'text/html') به ترتیب. نوشتن فقط یک می نویسد Buf یا Str به بدنه پاسخ.

ایجاد کاربر

حالا بیایید یک کاربر با a ایجاد کنیم POST درخواست. استفاده از این واقعاً ساده است $request.content، که JSON درخواست را به Raku تبدیل می کند Hash برای شما.

sub validate-user(%user) {
    # I'll leave this up to you :^)
    %user<age> > 18;
}

post('/users', -> $request, $response {
    my %user = $request.content;
    if validate-user(%user) {
        $db.execute('INSERT INTO user (name, age, email) VALUES (?, ?, ?)', %user<name>, %user<age>, %user<email>);
        $response.status(201).json(to-json(%user));
    } else {
        $response.status(400).write('Bad Request :(');
    }
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

من به شما اجازه می‌دهم اعتبارسنجی خودتان را پیاده‌سازی کنید، بنابراین فعلاً فرض می‌کنیم که کاربر معتبر است مگر اینکه سن او کمتر از 18 سال باشد. سپس ما خود را ثبت می‌کنیم. POST مسیر، سپس ما دریافت می کنیم .content (که یک هش تبدیل شده از بدنه JSON است)، سپس اعتبار سنجی می کنیم، سپس اگر معتبر است، پاسخی را با وضعیت ارسال کنید. 201 Created و JSON را که برای ما ارسال شده است بازنویسی کنید. در غیر این صورت یک پاسخ درخواست بد ارسال کنید.

ما می توانیم این نقطه پایانی را با استفاده از:

curl -X POST -H "Content-Type: application/json" -d '{ "name": "bob", "age": 32, "email": "bob@gmail.com" }' http://localhost:8080/users
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

حالا اگر سن را به 14 تغییر دهیم، باید a را ببینید 400 Bad Request واکنش:

curl -X POST -H "Content-Type: application/json" -d '{ "name": "bob", "age": 14, "email": "bob@gmail.com" }' http://localhost:8080/users
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و در نهایت اگر پایگاه داده خود را با مرور به بررسی کنیم http://localhost:8080/users ما باید کاربری را که ایجاد کرده ایم ببینیم. در مورد من چند بار اینسرت را اجرا کردم.

کاربران نتایج درخواست را دریافت می کنند

گرفتن یک کاربر فردی

این یک نقطه پایانی واقعا ساده است، تنها تفاوت بین این و جذب همه کاربران این است که باید از پارامترهای درخواست یک شناسه دریافت کنیم.

get('/users/:id', -> $request, $response {
    my $id = $request.param('id');
    my @users = $db.execute('SELECT * FROM user WHERE id = ?', $id).allrows(:array-of-hash);

    return $response.status(404).html("User with id $id not found.") unless @users.elems == 1;

    $response.json(to-json(@users[0]));
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در اینجا ما دریافت می کنیم id از پارامترهای درخواست، مشخص شده در اعلان مسیر، سپس یک پرس و جو DB را در تلاش برای یافتن کاربری با آن شناسه اجرا می کنیم. اگر دقیقاً یک کاربر را برگردانیم، a را برمی گردانیم 404 Not Found وضعیت، در غیر این صورت یک پاسخ JSON از کاربری که پیدا کردیم را برمی گردانیم.

اگر شما به http://localhost:8080/users/1 شما باید کاربری را که وارد کرده اید ببینید (اگر نه باید تعدادی را وارد کنید!)

حذف یک کاربر

یک نقطه پایانی ساده دیگر، این یکی بسیار شبیه به دریافت یک کاربر واحد خواهد بود، اما در عوض ما یک DB Delete را اجرا می کنیم و چیزی جز 204 No Content واکنش.

delete('/users/:id', -> $request, $response {
    my $id = $request.param('id');

    try {
        CATCH { default { return $response.status(404).html("User with id $id not found.") } }
        $db.execute('DELETE FROM user WHERE id = ?', $id);
        $response.status(204);
    }
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تفاوت عمده در اینجا این است که ما از بلوک try/catch استفاده می کنیم، شما نیازی به این کار ندارید. از آنجایی که Humming-Bird کاربردی است، در واقع فکر می کنم بهتر است از یک نوع Monad برای رسیدگی به خطاها استفاده کنید، چیزی مانند Monad::Result،
اما این بخش زیبای Humming-Bird است، ترجیحات همه را در خود جای می دهد.

میان افزار

خوب، مدیر شما آنقدر تحت تأثیر قرار گرفت که شما این سرویس را در یک روز تمام کردید که تصمیم گرفتند یک ویژگی جدید را بخواهند! شما فقط باید بتوانید به آن دسترسی داشته باشید DELETE و POST اگر رمز عبور جادویی را دارید، مسیرها foobar در X-AUTH سربرگ درخواست شما

Humming-Bird با استفاده از عملکردهایی که حدس زدید، از توسعه میان افزار غنی پشتیبانی می کند. بنابراین بیایید به سرعت آخرین نیاز میان افزار خود را بنویسیم.

sub auth-middleware($request, $response, &next) {
    without $request.header('X-AUTH') {
        return $response.status(401).write('unauthorized')
    }

    my $request-header = $request.header('X-AUTH');

    if $request-header ne 'foobar' {
        return $response.status(401).write('unauthorized');
    }

    &next();
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

میان افزار به عنوان تابعی توصیف می شود که یک درخواست، و یک پاسخ، و در نهایت اشاره گر به تابع بعدی در زنجیره میان افزار می گیرد.

برای ثبت این میان افزار با یک مسیر، تنها کاری که باید انجام دهیم این است که آن را به دم تعیین مسیر به صورت زیر اضافه کنیم:

delete('/users/:id', -> $request, $response {
    my $id = $request.param('id');

    try {
        CATCH { default { return $response.status(404).html("User with id $id not found.") } }
        $db.execute('DELETE FROM user WHERE id = ?', $id);
        $response.status(204);
    }
}, [ &auth-middleware ]); # Added auth middleware
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد نهایی

کد نهایی را می توانید در github پیدا کنید!

نتیجه

Humming-Bird چرخاندن انواع برنامه های کاربردی وب با استفاده از اکوسیستم پر جنب و جوش و خوشایند Raku را بسیار آسان می کند. اگر علاقه مند به استقرار سرویسی مانند این برای تولید هستید، حتماً نمونه docker را در github بررسی کنید. درست مانند هر چارچوب لایه کاربردی، Humming-Bird نیز چنین است نه طراحی شده برای مواجهه مستقیم با اینترنت، لطفاً آن را با NGiNX یا Apache2 معکوس کنید. اگر سؤالی دارید، یا مشکلی در مورد Humming-Bird پیدا کردید، لطفاً به بخش مشکل در github مراجعه کنید.

با تشکر از خواندن، Raku rocks!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا