چطور یک API ساده بسازیم؟

آموزش نوشتن یک API ساده با Node.jsاز سال ۲۰۰۹ تا به امروز Node.js همواره در حال توسعه و پیشرفت بوده است و توسعه‌دهنده‌ها در سراسر دنیا کتابخانه‌ها و پکیج‌های ثالث زیادی را برای آن توسعه داده‌اند. به دلیل وجود قابلیت اجرای دستورات سمت سرور، Node.js به طور گسترده‌ای برای پیاده‌سازی REST APIها مورد استفاده قرار می‌گیرد.در این پست قرار است با یکدیگر یک API ساده را با استفاده از Node.js بسازیم.توسعه رابط کاربری REST APIتوسعه رابط کاربری API شامل نوشتن یک منطق در سمت بک‌اند برای رسیدی به درخواست‌های API می‌شود. این فرایند شبیه چرخه توسعه نرم‌افزار است. در این چرخه طراحی در سطوح بالا شروع شده و پیاده‌سازی کد در سطوح پایین صورت می‌گیرد. در طی مسیر توسعه، باید به نکاتی نظیر انتخاب بهترین الگوریتم، ابزارهای ثالث، پایگاه داده و کتابخانه‌ها توجه کنیم.از این اینجا به بعد کار را در قالب یک مثال ادامه می‌دهیم تا درک مسئله راحت‌تر باشد.یک سرویس نظارت بر IP (مانیتورینگ IP) را در نظر بگیرید. وظیفه این سرویس رهگیری گروهی از IPها بر اساس موقعیت جغرافیایی آن‌ها است. REST APIهای مورد استفاده در این سرویس حول مدیریت آدرس‌های IP طراحی شده‌اند. بنابراین ما می‌توانیم رابط‌های کاربری برای سرویس نظارت بر IP را به شکل زیر تعریف کنیم:رابط‌های کاربری برای IPMonانتخاب اجزای بک‌اند APIبرای هر IP که توسط سرویس رهگیری می‌شود، باید محلی برای ذخیره اطلاعات آن وجود داشته باشد. انتخاب یک پایگاه داده مناسب برای سرویس بسیار مهم است. در صورتی که در این زمینه اطلاعات کافی ندارید (هرچند که خیلی بعید به نظر می‌رسد)، حتما از کمک یک متخصص بهره ببرید. در قسمت‌های بعدی که مراحل توسعه را شرح می‌دهیم، درباره این موضوع بیشتر صحبت می‌کنیم.از سوی دیگر برای دریافت اطلاعات مربوط به یک IP باید از یک سرویس ثالث استفاده کنیم. IPها به طور عمومی توسط سازمان‌های بزرگ تخصیص داده شده و پیگیری می‌شوند، و به همین دلیل بهتر است از سرویس‌های آن‌ها برای دریافت این اطلاعات بهره ببریم. این سرویس‌ها را می‌توانیم از طریق یک API در بک‌اند در سرویس خودمان پیاده‌سازی کنیم.برای این مثال، ما از IP Geolocation API که به صورت رایگان در وبسایت RapidAPI قرار دارد، استفاده می‌کنیم. برای این کار کافی است یک اکانت رایگان RapidAPI بسازید و این API را دریافت کنید.پیاده‌سازی رابط کاربری API با استفاده از Node.jsحالا به قسمت قشنگ این پست رسیده‌ایم، نوشتن کد API. قبل از شروع به نوشتن کد از داشتن پیش‌نیازهای لازم برای نوشتن و تست محلی API اطمینان حاصل کنید:Node.js Runtime: این ران‌تایم را می‌توانید از سایت Node.js دانلود و نصب کنید. پیشنهاد ما نسخه LTS است.cURL: ابزار curl را می‌توانید در وبسایت آن پیدا کنید. این ابزار برای تست رابط کاربری API استفاده می‌شود.مراحل توسعه APIویرایشگر کد خودتان را اجرا کرده و مراحل زیر را برای توسعه API انجام دهید. برای راحتی کار، ما اسم این API را IPMon گذاشته‌ایم، اما شما می‌توانید از هر اسمی که دوست دارید استفاده کنید. (دقت داشته باشید اسم انتخابی خود را در کد به کار ببرید).مرحله اول: ایجاد یک پروژه Node.jsیک دایرکتوری سطح بالا بسازید:mkdir node-apiدر اینجا node-api دایرکتوری سطح بالای شماست که همه فایل‌های پروژه را در خود نگه می‌دارد. به این پوشه بروید و یک پروژه Node.js ایجاد کنید:cd node-api npm init -yدر ادامه یک فایل جدید با نام server.js بسازید:touch server.jsمرحله دوم: اضافه کردن اندپوینت‌های HTTPفایل server.js حاوی کد اصلی رابط کاربری API ما است. در ابتدا باید ماژول‌های اصلی را اضافه کنید:const http = require ('http'); // برای ایجاد سرور const url = require('url'); const https = require('https');// https برای ارسال درخواست‌های var ip_table = new Map();//در قسمت بعد شما باید اندپوینت‌های سرور HTTP را برای رسیدگی به درخواست‌های API ایجاد کنید:// create basic server and implement handling different requests const app = http.createServer( async (req, res) => { // parse the incoming url const parsedURL = url.parse(req.url, true); //check for POST /api/ipmon/ip if ( parsedURL.pathname === '/api/ipmon/ip' && req.method === 'POST') { // check if ip is prsent in query else send error if(!parsedURL.query.ip) { res.statusCode = 400; res.end(&quotIP address is required, please add IP address in the query&quot); } else { handleCreate(parsedURL.query.ip,res); } } //check for GET /api/ipmon/ip/show else if (parsedURL.pathname === '/api/ipmon/ip/show' && req.method === 'GET'){ handleShow(res); } //check for PUT /api/ipmon/ip/{ip_address} else if (parsedURL.pathname.startsWith('/api/ipmon/ip') && req.method === 'PUT'){ var ipAddr = extractIPAddress(parsedURL.pathname) if(!ipAddr.length) { res.statusCode = 400; res.end(&quotInvalid IP Address&quot); } else { handleUpdate(ipAddr,res); } } //check for DELETE /api/ipmon/ip/{ip_address} else if (parsedURL.pathname.startsWith('/api/ipmon/ip') && req.method === 'DELETE'){ var ipAddr = extractIPAddress(parsedURL.pathname) if(!ipAddr.length) { res.statusCode = 400; res.end(&quotInvalid IP Address&quot); } else { handleDelete(ipAddr,res); } } //check for GET /api/ipmon/ip/{ip_address} else if (parsedURL.pathname.startsWith('/api/ipmon/ip') && req.method === 'GET'){ var ipAddr = extractIPAddress(parsedURL.pathname) if(!ipAddr.length) { res.statusCode = 400; res.end(&quotInvalid IP Address&quot); } else { handleRead(ipAddr,res); } } // if url doent match any send error else { res.statusCode = 400; res.end(&quotAPI Endpoint Not Supported&quot); } });//End of create server. app.listen(4000);این کد به Node.js می‌گوید که به درخواست‌ها روی پورت ۴۰۰۰ گوش کند. اندپوینت‌های API مطابق جدول بالا تعیین شده‌اند.مرحله سوم: اضافه کردن هندلرهای اندپوینت APIفانکشن‌های هندلر منطق‌های کسب‌‌و‌کاری را پیاده‌سازی می‌کنند. در ادامه هندلرها را یک‌به‌یک پیاده‌سازی می‌کنیم. در فایل server.js فانکشن ( )handleCreate را برای رسیدگی به درخواست‌های /api/ipmon/ip ایجاد می‌کنیم./* function to handle create */ function handleCreate( ip,res) { // call geolocation api and get the details getGeolocation( ip ).then( response => { // update the database - map in this case updateTable(response); // set the header and status code success and return the details of the ip res.setHeader('content-type', 'Application/json'); res.statusCode = 200; res.end(JSON.stringify(ip_table.get(ip))); }, error => { res.statusCode = 400; res.end(error); } ) }//End of handle createبا اجرا شدن این ایندپوینت، سرویس ما شروع به مکان‌یابی آدرس‌های IP جدید می‌کند. از آنجایی که ما از یک سرویس ثالث (IP Geolocation API) استفاده می‌کنیم، این هندلر در واقع آن سرویس را اجرا می‌کند.در گام بعدی نوبت به هندلر ( )handleShow می‌رسد.function handleShow(res){ // set the header and status res.setHeader('content-type', 'Application/json'); res.statusCode = 200; // create an array from the map array = Array.from(ip_table, ([name, value]) => ({ name, value })); // send the response array res.end(JSON.stringify(array)); }این کد تمام IPهای در حال رهگیری را نمایش می‌دهد. حالا نوبت هندلر ( )handleRead است.// function to handle read request function handleRead(ip,res){ // check if the ip is present in table if(ip_table.has(ip)){ // set header, status code and send the entry res.setHeader('content-type', 'Application/json'); res.statusCode = 200; res.end(JSON.stringify(ip_table.get(ip))); } else { // ip not found send error res.statusCode = 404; res.end(&quotRead: IP &quot+ip+&quot not found&quot); } }این کد اطلاعات IP خواسته شده را از آبجکت Map باز می‌گرداند. در قدم بعد باید هندلر ( )handleDelete را بنویسیم.// function to handle delete request function handleDelete(ip,res){ // check if ip is in the table if(ip_table.has(ip)){ // delete and send the success response ip_table.delete(ip); res.statusCode = 200; res.end(&quotDelete: &quot+ip+&quot deleted&quot); } else { // ip not found send error res.statusCode = 404; res.end(&quotDelete: IP &quot+ip+&quot not found&quot); } }این کد نیز IP خواسته شده را از Map پاک می‌کند. در آخر، نوبت نوشتن هندلر ( )handleUpdate است.// function to handle update request function handleUpdate(ip,res){ // check if the ip is present in table if(ip_table.has(ip)){ // update the details by calling geoplocation api getGeolocation( ip ).then( response => { // set header, status code, update table and send response res.setHeader('content-type', 'Application/json'); res.statusCode = 200; updateTable(response); res.end(JSON.stringify(ip_table.get(ip))); }, error => { // send error res.statusCode = 400; res.end(error); } ); } else { // ip not found in table so send error res.statusCode = 404; res.end(&quotUpdate: IP &quot+ip+&quot not tracked&quot) } }هر بار که اپلیکیشن مشتری قصد بررسی وضعیت جغرافیایی فعلی یک IP موجود را داشته باشد، درخواست به‌روزرسانی می‌شود.مرحله چهارم: اضافه کردن فانکشن‌های داخلیدو فانکشن ( )getGeolocation و ( )updateTable توسط هندلرها استفاده می‌شوند که باید آن‌ها را اضافه کنیم.const rapidAPIBaseUrl = &quothttps://rapidapi.p.rapidapi.com/json/?ip=&quot function getGeolocation( ipAddress ) { // initilize http.rquest object var req = https.request; // initialize header with the required information to call geolocation api. var header = { &quotx-rapidapi-host&quot: &quotip-geolocation-ipwhois-io.p.rapidapi.com&quot, &quotx-rapidapi-key&quot: &quot<YOUR_RAPIDAPI_KEY>&quot, &quotuseQueryString&quot: true }; // add the query string including the IP address var query_string = { &quotip&quot : ipAddress }; // set the options parameter var options = { headers: header, query: query_string }; // form the url const url = rapidAPIBaseUrl + ipAddress ; return new Promise ( ( resolve, reject) => { https.get( url, options, res => { let data = &quot&quot //data is received in chunks, so uppend data as and when received res.on( 'data', function(response) { data = data + response; }); // handle error if any res.on( 'error', function(err) { console.log(&quotError&quot); console.log(err); }) // if end of data return the final chunk res.on( 'end', () => { resolve( JSON.parse(data) ); }); });//Endn of http }); //end of return promise }//End of getGeolocationاین فانکشن تعامل و تبادل داده با IP Geolocation API را مدیریت می‌کند. در نظر داشته باشید به جای YOUR_RAPIDAPI_KEY باید کلیدی که در هنگام ثبت‌نام در RapidAPI را دریافت کرده‌اید، جایگزین کنید.در ادامه کد زیر را در server.js وارد کنید:function updateTable(entry){ // get current date to update last update the time var time = new Date(); // add the entry to table ip is the key and country, city and last updated time are stored ip_table.set(entry.ip, {&quotip&quot:entry.ip,&quotcountry&quot:entry.country,&quotcity&quot:entry.city,&quotlastUpdated&quot:time}); }این فانشکن اطلاعات را در آبجکت Map وارد می‌کند.جدا از موارد گفته شده، فانکشن داخلی ( )extractIPAddress آخرین فانکشنی است که باید اضافه شود. این فانکشن IPها را اندپوینت‌های API را استخراج و تایید می‌کند.function extractIPAddress(path){ var ipAddress = path.substring(path.lastIndexOf(&quot/&quot)+1,path.length); if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipAddress)) { return ipAddress; } else { console.log(&quotinvalid IP Address&quot) return &quot&quot } } // End of extractIPAddressبا نوشتن این کد، شما رابط کاربری یک API را به طور کامل نوشته‌اید. یادتان نرود فایل را ذخیره کنید.مرحه پنجم: اجرای سروربا استفاده از دستور زیر فایل server.js را اجرا کنید:node server.jsاگر خطایی وجود نداشته باشد، این برنامه سرویس IPMon را به عنوان یک API در آدرس http://localhost:4000 اجرا می‌کند.API خودتان را تست کنیدحالا نوبت به تست API می‌رسد. یک ترمینال جدید باز و کد زیر را اجرا کنید:curl -X POST http://localhost:4000/api/ipmon/ip?ip=64.23.14.10C:\>curl -X POST http://localhost:4000/api/ipmon/ip?ip=64.23.14.10 {&quotip&quot:&quot64.23.14.10″,&quotcountry&quot:&quotUnited States&quot,&quotcity&quot:&quotChicago&quot,&quotlastUpdated&quot:&quot2020-11-03T18:08:44.265Z&quot}این کد 64.23.14.10 و اطلاعات آن را به پایگاه داده IPها برای رهگیری اضافه می‌کند.حالا باید اندپوینت را برای بررسی وجود IP اجرا کنید.curl -X GET http://localhost:4000/api/ipmon/ip/showC:\>curl -X GET http://localhost:4000/api/ipmon/ip/show [{&quotname&quot:&quot64.23.14.10″,&quotvalue&quot:{&quotip&quot:&quot64.23.14.10″,&quotcountry&quot:&quotUnited States&quot,&quotcity&quot:&quotChicago&quot,&quotlastUpdated&quot:&quot2020-11-03T18:08:44.265Z&quot}}]شما همین‌طور می‌توانید اطلاعات یک IP خاص را دریافت کنید:curl -X GET http://localhost:4000/api/ipmon/ip/64.23.14.10C:\>curl -X GET http://localhost:4000/api/ipmon/ip/64.23.14.10 {&quotip&quot:&quot64.23.14.10″,&quotcountry&quot:&quotUnited States&quot,&quotcity&quot:&quotChicago&quot,&quotlastUpdated&quot:&quot2020-11-03T18:08:44.265Z&quot}همچنین شما می‌توانید یک آدرس IP را به‌روز کنید:curl -X PUT http://localhost:4000/api/ipmon/ip/64.23.14.10C:\>curl -X PUT http://localhost:4000/api/ipmon/ip/64.23.14.10 {&quotip&quot:&quot64.23.14.10″,&quotcountry&quot:&quotUnited States&quot,&quotcity&quot:&quotChicago&quot,&quotlastUpdated&quot:&quot2020-11-03T18:16:10.168Z&quot}و در آخر، نوبت به حذف یک IP می‌رسد:curl -X DELETE http://localhost:4000/api/ipmon/ip/64.23.14.10C:\>curl -X DELETE http://localhost:4000/api/ipmon/ip/64.23.14.10 Delete: 64.23.14.10 deletedحالا چون IP حذف شده است، هر درخواست دیگری برای فراخوانی اطلاعات آن خطا برمی‌گرداند:C:\>curl -X GET http://localhost:4000/api/ipmon/ip/64.23.14.10 Read: IP 64.23.14.10 not foundاگر همه چیز بدون مشکل اجرا شده است، تبریک می‌گوییم، شما با موفقیت یک API ساده نوشته‌اید.