فارغ التحصیل علوم کامپیوتر، نویسنده محتوا، مسحور داستان سرایی، آشنا با سئو، علاقهمند به دیجیتال مارکتینگ، مشغول در فناپ
چطور یک API ساده بسازیم؟
از سال ۲۰۰۹ تا به امروز Node.js همواره در حال توسعه و پیشرفت بوده است و توسعهدهندهها در سراسر دنیا کتابخانهها و پکیجهای ثالث زیادی را برای آن توسعه دادهاند. به دلیل وجود قابلیت اجرای دستورات سمت سرور، Node.js به طور گستردهای برای پیادهسازی REST APIها مورد استفاده قرار میگیرد.
در این پست قرار است با یکدیگر یک API ساده را با استفاده از Node.js بسازیم.
توسعه رابط کاربری REST API
توسعه رابط کاربری API شامل نوشتن یک منطق در سمت بکاند برای رسیدی به درخواستهای API میشود. این فرایند شبیه چرخه توسعه نرمافزار است. در این چرخه طراحی در سطوح بالا شروع شده و پیادهسازی کد در سطوح پایین صورت میگیرد. در طی مسیر توسعه، باید به نکاتی نظیر انتخاب بهترین الگوریتم، ابزارهای ثالث، پایگاه داده و کتابخانهها توجه کنیم.
از این اینجا به بعد کار را در قالب یک مثال ادامه میدهیم تا درک مسئله راحتتر باشد.
یک سرویس نظارت بر IP (مانیتورینگ IP) را در نظر بگیرید. وظیفه این سرویس رهگیری گروهی از IPها بر اساس موقعیت جغرافیایی آنها است. REST APIهای مورد استفاده در این سرویس حول مدیریت آدرسهای IP طراحی شدهاند. بنابراین ما میتوانیم رابطهای کاربری برای سرویس نظارت بر IP را به شکل زیر تعریف کنیم:
انتخاب اجزای بکاند 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("IP address is required, please add IP address in the query");
} 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("Invalid IP Address");
} 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("Invalid IP Address");
} 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("Invalid IP Address");
} else {
handleRead(ipAddr,res);
}
}
// if url doent match any send error
else {
res.statusCode = 400;
res.end("API Endpoint Not Supported");
}
});//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("Read: IP "+ip+" not found");
}
}
این کد اطلاعات 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("Delete: "+ip+" deleted");
} else {
// ip not found send error
res.statusCode = 404;
res.end("Delete: IP "+ip+" not found");
}
}
این کد نیز 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("Update: IP "+ip+" not tracked")
}
}
هر بار که اپلیکیشن مشتری قصد بررسی وضعیت جغرافیایی فعلی یک IP موجود را داشته باشد، درخواست بهروزرسانی میشود.
مرحله چهارم: اضافه کردن فانکشنهای داخلی
دو فانکشن ( )getGeolocation و ( )updateTable توسط هندلرها استفاده میشوند که باید آنها را اضافه کنیم.
const rapidAPIBaseUrl = "https://rapidapi.p.rapidapi.com/json/?ip="
function getGeolocation( ipAddress ) {
// initilize http.rquest object
var req = https.request;
// initialize header with the required information to call geolocation api.
var header = {
"x-rapidapi-host": "ip-geolocation-ipwhois-io.p.rapidapi.com",
"x-rapidapi-key": "<YOUR_RAPIDAPI_KEY>",
"useQueryString": true
};
// add the query string including the IP address
var query_string = { "ip" : 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 = ""
//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("Error");
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, {"ip":entry.ip,"country":entry.country,"city":entry.city,"lastUpdated":time});
}
این فانشکن اطلاعات را در آبجکت Map وارد میکند.
جدا از موارد گفته شده، فانکشن داخلی ( )extractIPAddress آخرین فانکشنی است که باید اضافه شود. این فانکشن IPها را اندپوینتهای API را استخراج و تایید میکند.
function extractIPAddress(path){
var ipAddress = path.substring(path.lastIndexOf("/")+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("invalid IP Address")
return ""
}
} // 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.10
C:\>curl -X POST http://localhost:4000/api/ipmon/ip?ip=64.23.14.10
{"ip":"64.23.14.10″,"country":"United States","city":"Chicago","lastUpdated":"2020-11-03T18:08:44.265Z"}
این کد 64.23.14.10 و اطلاعات آن را به پایگاه داده IPها برای رهگیری اضافه میکند.
حالا باید اندپوینت را برای بررسی وجود IP اجرا کنید.
curl -X GET http://localhost:4000/api/ipmon/ip/show
C:\>curl -X GET http://localhost:4000/api/ipmon/ip/show
[{"name":"64.23.14.10″,"value":{"ip":"64.23.14.10″,"country":"United States","city":"Chicago","lastUpdated":"2020-11-03T18:08:44.265Z"}}]
شما همینطور میتوانید اطلاعات یک IP خاص را دریافت کنید:
curl -X GET http://localhost:4000/api/ipmon/ip/64.23.14.10
C:\>curl -X GET http://localhost:4000/api/ipmon/ip/64.23.14.10
{"ip":"64.23.14.10″,"country":"United States","city":"Chicago","lastUpdated":"2020-11-03T18:08:44.265Z"}
همچنین شما میتوانید یک آدرس IP را بهروز کنید:
curl -X PUT http://localhost:4000/api/ipmon/ip/64.23.14.10
C:\>curl -X PUT http://localhost:4000/api/ipmon/ip/64.23.14.10
{"ip":"64.23.14.10″,"country":"United States","city":"Chicago","lastUpdated":"2020-11-03T18:16:10.168Z"}
و در آخر، نوبت به حذف یک IP میرسد:
curl -X DELETE http://localhost:4000/api/ipmon/ip/64.23.14.10
C:\>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 ساده نوشتهاید.
مطلبی دیگر از این انتشارات
در دل GraphQL چه میگذرد؟
مطلبی دیگر از این انتشارات
اپیزود هفتم پادکست هگزاگون | سواگر و پستمن: ابزارهای مستندسازی
مطلبی دیگر از این انتشارات
جزئیات سامانههای پرداخت و تسویه حساب آنی بین بانکی