نوشتن یک سرویس میکرو با پشتیبانی از پایگاه داده با 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!