در این مقاله سعی می کنیم توضیح دهیم که RESTful API چیست ما در این مقاله خواهیم فهمید که منظور از API چیست، HTTP چیست، در مورد REST یاد می گیریم، نحوه عملکرد آن را می بینیم، و در آخر در قالب یک مثال عملی دانسته های خود را تقویت کرده و بهبود می بخشیم.
API (رابط برنامه نویسی برنامه یا Application Programming Interface) مجموعه ای از قوانین و مکانیسم هایی است که به وسیله آن یک برنامه یا بخشی از برنامه با دیگری تعامل می کند. API میتواند دادههایی را که برای برنامهتان نیاز دارید در فرمتی مناسب (مانند JSON یا XML) برگرداند. در این آموزش RESTful API ما فقط بر روی JSON تمرکز خواهیم کرد.
Representational State Transfer (REST) یک معماری نرم افزاری است که شرایطی را بر نحوه عملکرد یک API تحمیل می کند. REST در ابتدا به عنوان یک دستورالعمل برای مدیریت ارتباطات در یک شبکه پیچیده مانند اینترنت ایجاد شد. می توانید از معماری مبتنی بر REST برای پشتیبانی از ارتباطات با کارایی بالا و قابل اعتماد در مقیاس استفاده کنید. شما به راحتی می توانید آن را پیاده سازی و اصلاح کنید، و قابلیت مشاهده و قابلیت ارتباط بین پلتفرم با پلتفرم های دیگر را بر اساس API به ارمغان بیاورید.
توسعه دهندگان API می توانند API ها را با استفاده از چندین معماری مختلف طراحی کنند. APIهایی که از سبک معماری REST پیروی می کنند، REST API نامیده می شوند. وب سرویس هایی که معماری REST را پیاده سازی می کنند، وب سرویس های RESTful نامیده می شوند. اصطلاح RESTful API به طور کلی به API های وب RESTful اشاره دارد. با این حال، میتوانید از عبارت REST API و RESTful API به جای یکدیگر استفاده کنید.
بیایید به یک مثال نگاه کنیم. احتمالا با وب اپلیکیشن Github آشنا هستید. این وب اپلیکیشن، API مخصوص به خود را دارد که با کمک آن می توانید اطلاعاتی در مورد کاربران، ریپازیتوری آنها و موارد بسیار مفیدتر هنگام توسعه برنامه خود به دست آورید. شما می توانید از این داده ها در پروژه خود استفاده کنید.
مثال درخواست استاندارد به API به شکل زیر است:
درخواست با کمک CURL که یک ابزار کنسول است انجام می شود. همچنین ابزارهای مرورگر مانند Postman، REST Client و غیره وجود دارد.
چیزی که در زیر می بینید پاسخی است که دریافت کردیم:
حالا بیایید کمی با REST آشنا شویم. این REST مخفف "Representational State Transfer" است.
این تعریف را می توان با کلمات ساده تر بیان کرد:
ارائه داده برای کلاینت در فرمتی که برای او مناسب باشد
یک نکته اصلی که باید به آن توجه کنید این است: REST یک استاندارد یا پروتکل نیست، بلکه یک رویکرد یا سبک معماری برای نوشتن API است.
سرویسهای وب RESTful از حافظه نهان یا Cache پشتیبانی میکنند، که فرآیند ذخیره برخی از پاسخها بر روی کلاینت یا یک واسطه برای بهبود زمان پاسخ سرور می باشد. به عنوان مثال، فرض کنید از وب سایتی بازدید می کنید که در هر صفحه دارای تصاویر مشترک هدر و فوتر است. هر بار که از یک صفحه وب سایت جدید بازدید می کنید، سرور باید همان تصاویر را دوباره ارسال کند. برای جلوگیری از این امر، کلاینت این تصاویر را پس از اولین پاسخ ذخیره می کند و سپس از تصاویر به طور مستقیم از کش استفاده می کند. خدمات وب RESTful با استفاده از پاسخهای API که خود را بهعنوان cacheable یا noncacheable تعریف میکنند، کش را کنترل میکنند.
در سبک معماری REST، سرورها می توانند با انتقال کد برنامه نویسی نرم افزار به کلاینت، به طور موقت عملکرد کلاینت را گسترش دهند یا سفارشی کنند. به عنوان مثال، هنگامی که یک فرم ثبت نام را در هر وب سایتی پر می کنید، مرورگر شما بلافاصله هر اشتباهی را که مرتکب می شوید، مانند شماره تلفن های نادرست، برجسته می کند. این خطا به دلیل کد ارسال شده توسط سرور ایجاد می شود.
یک تعریف ساده از RESTful API می تواند به راحتی این مفهوم را توضیح دهد. REST یک سبک معماری است و RESTful تفسیر آن است. یعنی اگر سرور بکاند شما REST API دارد و درخواستهای سمت کلاینت (از یک وبسایت/برنامه) را به این API می فرستید، کلاینت شما RESTful است.
عملکرد اصلی RESTful API مانند مرور اینترنت است. کلاینت با استفاده از API زمانی که به منبعی نیاز دارد با سرور ارتباط برقرار میکند. توسعه دهندگان API توضیح می دهند که چگونه کلاینت باید از REST API در مستندات API برنامه سرور استفاده کند. این مراحل کلی برای هر ارسال درخواست به REST API ضروری است:
جزئیات درخواست و پاسخ REST API با توجه به نحوه طراحی API توسط توسعه دهندگان API کمی متفاوت است.
مهترین کارهای RESTful API به چهار عملیات ضروری زیر خلاصه می شود:
REST به شدت به HTTP متکی است. در مورد ویژگی های این پروتکل توضیح نمی دهیم زیرا می توانید با بررسی مقاله تفاوت متدهای HTTP به راحتی به درک این موضوع پی ببرید.
هر عملیات از متد HTTP خود استفاده می کند:
همه این متدها (عملیات) معمولا CRUD نامیده می شوند. آنها داده ها را مدیریت می کنند یا همانطور که ویکی پدیا می گوید "ایجاد، خواندن، به روز رسانی و حذف" را برای داده ها انجام می دهند.
این واقعیت که REST حاوی یک رابط مشترک واحد برای درخواست ها و پایگاه های داده است، در واقع مزیت بزرگ آن است. جدول زیر را مشاهده کنید.
همه درخواستهایی که ایجاد می کنید دارای کد وضعیت HTTP هستند. تعداد آنها زیاد است و به 5 کلاس تقسیم می شوند. عدد اول این کدها نمایانگر وضعیت آن یا بحرانی بودن خروجی است.
جزئیات بیشتر در مورد لیست را می توان در اینجا یافت: فهرست کدهای وضعیت HTTP.
API های RESTful دارای مزایای زیر هستند:
سیستمهایی که APIهای REST را پیادهسازی میکنند، میتوانند به طور موثر مقیاس شوند، زیرا REST تعاملات کلاینت و سرور را بهینه میکند. قابلیت «بدون حالت بودن RESTful APIها» بار سرور را حذف می کند زیرا سرور مجبور نیست هر بار درخواست کلاینت قبلی را نگه دارد. حافظه نهان یا Cache با مدیریت خوب تا حدی یا به طور کامل برخی از تعاملات کلاینت و سرور را حذف می کند.
در طراحی API ها به صورت RESTful شما می توانید به راحتی یک سرویس را جایگزین سرویس دیگری کنید بدون اینکه آسیبی به اصل خروجی وارد شود. یعنی چی؟ فرض کنید قبلا اطلاعات کاربران را از دیتابیس شماره ۱ دریافت می کرده اید، حالا به هر دلیلی (مثلا از بین رفتن دیتابیس شماره ۱) آن اطلاعات را از دیتابیس شماره ۲ بگیرید. این کار به راحتی صورت می گیرد ولی خروجی شما در RESTful برای کلاینت کاملا ثابت است. بنابراین با انعطاف پذیری خیلی بالا می توانید این تغییرات را روی سرویس های REST بدهید.
API های REST مستقل از فناوری مورد استفاده هستند. یعنی شما می توانید نرم افزارهای کلاینت و سرور را به زبانهای برنامهنویسی مختلف بدون تاثیر بر طراحی API بنویسید. همچنین میتوانید فناوری اصلی را در هر دو طرف تغییر دهید بدون اینکه تاثیری بر نتیجه خروجی داشته باشید.
شما همیشه باید API های REST خود را ورژنبندی کنید. به عنوان مثال، اگر API در آدرس http://example dot com/api باشد، لازم است تغییراتی در آن مانند http://example dot com/api/v1 ایجاد کنید. یعنی عبارت v1 باعث می شود کلاینت در جریان باشد که نسخه شماره ۱ این API را استفاده می کنید.
امروزه معمولا بکاند نه تنها برای پلتفرمهای وب، بلکه برای برنامههای موبایل نیز توسعه مییابد. بنابراین، اگر یک API بدون ورژن ایجاد کنید و چیزی را در سرور تغییر دهید، سمت کلاینت موبایل یا وب ممکن است متوجه نشود که چه تغییراتی روی سیستم شما رخ داده است. حتی اگر تغییراتی ایجاد کنید، هیچ تضمینی وجود ندارد که کلاینت این تغییرات را سمت خود از قبل پیاده سازی کرده باشد.
دو گزینه برای تعیین ورژن وجود دارد. اولین مورد، که آنها را در URL نشان می دهد، قبلا توضیح داده شده است. گزینه دوم در مورد گنجاندن یک ورژن در هدر درخواست است. به طور کلی، راه حل سابق به طور گسترده مورد انتقاد قرار می گیرد. استدلال های زیادی مانند "این روش بدی است!!!" وجود دارد، اما قانع کننده به نظر نمی رسند.
در واقع، هر کس گزینه ای را انتخاب می کند که بهترین کارکرد را برای او دارد. میخواهیم به کسانی که میخواهند ورژنها را در هدرها مشخص کنند، توصیهای کوچک بدهیم.
این کار را به روش زیر انجام ندهید:
Accept: application/vnd.redkavasyl-v2+json
شما به راحتی می توانید بیش از یک پارامتر را در یک هدر وارد کنید. بنابراین، بر اساس تجربه ما، روش زیر را امتحان کنید:
Accept: application/vnd.redkavasyl+json; version=2.0
اما توصیه من به شما این است که از نسخه بندی (ورژن بندی) روی URL (مشابه آنچه در ابتدا گفتیم) استفاده کنید.
همه منابع در REST یک موحودیتی هستند که می توانند مستقل باشند. به نمونههای زیر توجه کنید:
همچنین موجودیت های وابسته ای وجود دارند که به مدل های پرنت یا والد خود متکی هستند:
درخواست GET به این صورت هست که شما با تغییر id می تواند یک موجودیت یا کاربر دیگه را دریافت کنید.
مثالهای بالا نشان میدهند که GET به معنای دریافت موجودیت درخواستی شما است. یک درخواست موفق، یک خروجی موفق با کد وضعیت 200 را برمی گرداند. اگر خطایی وجود داشته باشد، کد 404 (یافت نشد)، 400 (درخواست بد) یا 5xx (خطای سرور) را دریافت خواهید کرد.
بیایید متد POST (ایجاد یک موجودیت جدید) را بررسی کنیم:
هنگام ایجاد یک موجودیت جدید، پارامترهایی را در باید body درخواست تنظیم می کنید. مثل:
{{ '{' }} “first_name”: “Vasyl”, “last_name”: “Redka” {{'}'}}
پس از آن شما نتیجه را دریافت خواهید کرد که برای مثال ممکن است کد وضعیت 200 باشد. سپس پاسخ حاوی داده های یک موجودیت ذخیره شده خواهد بود. مثلا:
{{ '{' }} “id”: “1”, “first_name”: “Vasyl”, “last_name”: “Redka” {{'}'}}
همچنین می تواند وضعیت 201 (ایجاد شده) را بازگرداند که در نتیجه یک موجودیت جدید ایجاد می شود. سرور می تواند آدرس خود را در body پاسخ داده شده مشخص کند. توصیه می شود آن را در هدر "Location" قرار دهید.
درخواست بعدی PUT است. برای به روز رسانی موجودیت ها استفاده می شود. هنگامی که آن را ارسال می کنید، body درخواست باید حاوی داده های موجودیت به روز شده باشد که به آن اشاره می کند.
تغییرات باید در پارامترها مشخص شود. اگر با موفقیت به روز شود، درخواست کد 200 و موجودیت به روز شده را برمی گرداند.
آخرین درخواست DELETE است. درک آن ساده است و برای حذف یک موجودیت خاص با توجه به یک id استفاده می شود.
اگر حذف موفقیت آمیز باشد، 200 را همراه با body پاسخ که حاوی اطلاعاتی در مورد وضعیت موجودیت است، برمی گرداند. به عنوان مثال، هنگامی که موجودیت را از پایگاه داده حذف نمی کنید بلکه فقط آن را به عنوان حذف شده علامت گذاری می کنید، درخواست های تکراری، body را به عنوان پاسخ با یک کد وضعیت 200 برمی گردانند. DELETE می تواند کد 204 (بدون محتوا) را بدون body به عنوان پاسخ بازگرداند.
اگر موجودیت را به طور کامل از پایگاه داده حذف و مجددا درخواست DELETE را برای همان id ارسال کنید باید 404 (یافت نشد) را دریافت کنید زیرا آن موجودیت قبلا حذف شده است و دیگر در دسترس نیست.
یک فریم ورک متن باز عالی به نام Swagger.io وجود دارد. این فریم ورک کار توسعه دهندگان را هنگام برخورد با مستندات و توضیحات آسان تر می کند و حتی تست اولیه نرم افزار را پوشش می دهد.
شما می توانید تمام درخواست های کاربر را در آنجا مشاهده کنید:
همچنین فرصتی برای مشاهده توضیحات هر مدل درخواست فراهم می کند. می توانید فیلدها را با داده ها پر کنید، آن را ارسال کنید و نتایج واقعی دریافت کنید.
در این قسمت قصد داریم همه چیزهایی که تا کنون از این مقاله یاد گرفتیم را با استفاده از یک مثال عملی پیاده سازی کنیم. در این مثال از node.js و javascript استفاده خواهیم کرد. اگر node.js در سیستم شما نصب نشده است از این لینک آن را دانلود کنید. برنامه ای که با هم خواهیم نوشت، درباره ایجاد یک RESTful برای یک فروشگاه آنلاین کتاب است.
ابتدا یک پوشه با نام دلخواه ایجاد می کنیم. من نام آن را NODE-RESTFULAPI گذاشته ام. شما هر نامی که می خواهید بگذارید. این پوشه را با استفاده از VS code کرده و سپس ترمینال VS code را باز می کنیم و با دستور npm init -y
یک package.json
در آن ایجاد می کنیم.
نکته: می توانید از هر ویرایشگر کد که خواستید استفاده کنید.
ما در این مثال ساده از دیتابیس استفاده نمی کنیم. بلکه به جای آن از یک فایل users.json
که اطلاعات کاربران را ذخیره می کند بکار میگیریم.
{ "user1" : { "name" : "mahesh", "password" : "password1", "profession" : "teacher", "id": 1 }, "user2" : { "name" : "suresh", "password" : "password2", "profession" : "librarian", "id": 2 }, "user3" : { "name" : "ramesh", "password" : "password3", "profession" : "clerk", "id": 3 } }
سپس برای کار با node.js نیاز داریم که کتابخانه express را نصب کنیم. این کار را با دستور npm install express
در ترمینال انجام می دهیم.
نکته: توجه داشته باشید که برای نصب express حتما به اینترنت متصل باشید.
پس از نصب express یک پوشه node_modules
به پروژه شما افزوده میشود.
بر اساس اطلاعات داده شده، ما قصد داریم API های RESTful زیر را بسازیم.
Sr.No. | URI | HTTP Method | POST body | Result |
1 | listUsers | GET | empty | تمام کاربران را نمایش بده |
2 | addUser | POST | JSON String | یک کاربر جدید بساز |
3 | deleteUser | DELETE | JSON String | کاربر موجود را پاک کن |
4 | :id | GET | empty | اطلاعات یک کاربر خاص را نمایش بده |
من بیشتر قسمتها را کدنویسی خواهم کرد با این فرض که شما از قبل میدانید که چگونه مقادیر را با استفاده از Ajax یا فرم بفرستید و یا دریافت کنید و سپس چگونه آنها را با استفاده از شی Request از Express پردازش کنید.
بیایید اولین RESTful API listUsers خود را بسازیم. برای اینکار یک فایل به نام index.js ایجاد کنید و کدهای زیر را به آن بیافزایید:
var express = require('express'); var app = express(); var fs = require("fs"); app.get('/listUsers', function (req, res) { fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) { console.log( data ); res.end( data ); }); }) var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("Example app listening at http://%s:%s", host, port) })
برای اجرای برنامه به یک پکیج دیگر نیاز داریم. نام این پکیج nodemon
است. آن را با دستور npm install nodemon
نصب میکنیم.
برای این که پس از هر تغییر سرور خود دوباره راه اندازی نکنیم از این پکیج استفاده میکنیم.برای استفاده از آن یک گام دیگر مانده است. باید در اینجا script زیر را به فایل package.json اضافه کنیم:
اکنون برای اجرای برنامه کافی است دستور npm start
را در ترمینال بنویسیم و سپس enter را بزنیم. پس از این باید با تصویر زیر مواجه شوید:
اکنون اگر به آدرس http://localhost:8081/listUsers
بروید باید با چنین صفحه ای مواجه شوید:
من برای بهتر نمایش داده شدن نتایج از اکستنشن JSON Viewer استفاده کرده ام.
API زیر به شما نشان می دهد که چگونه کاربر جدید را به لیست اضافه کنید. در زیر جزئیات کاربر جدید آمده است:
user = { "user4" : { "name" : "mohit", "password" : "password4", "profession" : "teacher", "id": 4 } }
شما می توانید این ورودی را با فرمت JSON با استفاده از فراخوانی Ajax دریافت کنید، اما برای درک بهتر، ما آن را در اینجا خودمان مینویسم. در زیر addUser API برای ساخت یک کاربر جدید آمده است. در فایل index.js داریم:
var express = require('express'); var app = express(); var fs = require("fs"); var user = { "user4" : { "name" : "mohit", "password" : "password4", "profession" : "teacher", "id": 4 } } app.post('/addUser', function (req, res) { // First read existing users. fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) { data = JSON.parse( data ); data["user4"] = user["user4"]; console.log( data ); res.end( JSON.stringify(data)); }); }) var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("Example app listening at http://%s:%s", host, port) })
اکنون سعی کنید با استفاده از http://127.0.0.1:8081/addUser
و متد POST به API تعریف شده دسترسی پیدا کنید. برای استفاده از متد post در اینجا از اکستنشن Thunder Client در Vs Code استفاده می کنیم. اگر آن را ندارید، نصب کنید. شما می توانید از Postman هم استفاده کنید. خوبی این اکستنشن این است که حجم کمی دارد.
یک درخواست POST به این http://127.0.0.1:8081/addUs
اگر بدهید باید نتیجه زیر را دریافت کنید:
{ "user1":{"name":"mahesh","password":"password1","profession":"teacher","id":1}, "user2":{"name":"suresh","password":"password2","profession":"librarian","id":2}, "user3":{"name":"ramesh","password":"password3","profession":"clerk","id":3}, "user4":{"name":"mohit","password":"password4","profession":"teacher","id":4} }
همانطور که میبینید اکنون چهار تا user داریم.
اکنون یک API را پیاده سازی می کنیم که با استفاده از id یوزر فراخوانی می شود و جزئیات کاربر مربوطه را نمایش می دهد.
var express = require('express'); var app = express(); var fs = require("fs"); app.get('/:id', function (req, res) { // First read existing users. fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) { var users = JSON.parse( data ); var user = users["user" + req.params.id] console.log( user ); res.end( JSON.stringify(user)); }); }) var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("Example app listening at http://%s:%s", host, port) })
اکنون سعی کنید با استفاده از URL: http://127.0.0.1:8081/2
و متد HTTP: با استفاده از هر کلاینت REST به API تعریف شده دسترسی پیدا کنید. در نهایت باید نتیجه زیر را بدست بیاورید:
{"name":"suresh","password":"password2","profession":"librarian","id":2}
این API بسیار شبیه به addUser API است که در آن داده های ورودی را از طریق req.body دریافت می کنیم و سپس بر اساس id کاربر آن کاربر را از دیتابیس حذف می کنیم. برای ساده نگه داشتن برنامه ما فرض می کنیم که کاربر با ID = 2 را حذف می کنیم.
در فایل index.js داریم:
var express = require('express'); var app = express(); var fs = require("fs"); var id = 2; app.delete('/deleteUser', function (req, res) { // First read existing users. fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) { data = JSON.parse( data ); delete data["user" + 2]; console.log( data ); res.end( JSON.stringify(data)); }); }) var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("Example app listening at http://%s:%s", host, port) })
اکنون سعی کنید با استفاده از URL: http://127.0.0.1:8081/deleteUser
و متد HTTP به API تعریف شده دسترسی پیدا کنید: DELETE باید نتیجه زیر را ایجاد کند:
{"user1":{"name":"mahesh","password":"password1","profession":"teacher","id":1}, "user3":{"name":"ramesh","password":"password3","profession":"clerk","id":3}}
امیدوارم با خواندن این مقاله به سوال RESTful API چیست شما پاسخ داده باشیم و اطمینان حاصل کنید که کار شما با این سبک نوشتن API مطابق با استانداردها و موثر و مطابق با راهکارهای روز برنامهنویسی است و استفاده صحیح از آن باعث صرفه جویی در وقت و تلاش شما می شود.
امیدواریم این راهنمای RESTful API به شما کمک کند تا از تمام ویژگیهای این رویکرد لذت ببرید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.