زمانی که شما در مسیر شغلی توسعه وب قرار میگیرید، دیر یا زود نیاز پیدا میکنید که با API (Application Programming Interface) های خارجی سر و کار داشته باشید. هدف من در این مقاله، ارائه لیست کاملی از راه های استفاده از RESTful API ها در پروژه های #C و نحوه کار کردن با آنها با ذکر چند مثال ساده است. بعد از خواندن این مقاله، شما به این درک میرسید زمانیکه نیاز داشتید تا از یک RESTful API استفاده کنید، چه گزینه هایی وجود دارند و چطور گزینه مناسب را برای خودتان انتخاب کنید.
یک RESTful API چیست؟
قبل از شروع، شاید برای شما جای سوال باشد که API چیست و در کل RESTful به چه چیز مربوط میشود؟
به بیان ساده، API ها لایه هایی بین اپلیکیشن های نرم افزاری به حساب می آیند. شما میتوانید request رو به سمت API بفرستید و در برگشت، پاسخی را از آن دریافت کنید. API ها تمام جزیات پیاده سازی یک برنامه نرم افزاری را پنهان میکنند و رابطی را که برای برقراری ارتباط با آن برنامه باید استفاده کنید را در اختیار شما قرار میدهد.
کل اینترنت یک شبکه بزرگی از API ها است که به شما خدمات میدهد. ما از این API ها برای برقراری ارتباط و اطلاعات مرتبط بین اپلیکیشن ها استفاده میکنیم. برای هرچیزی معمولا API وجود دارد. اکثر سرویسهایی که شما روزانه استفاده میکنید API های مخصوص به خودشان را دارند (گوگل مپ، فیس بوک، توییتر، اینستاگرام، پورتالهای آب و هوا و …)
RESTful به این معنیست که API طبق اصول و قوانین REST (Representational State Transfer) که تحت اصول معماری وب است پیاده سازی شده است. RESTful API ها در اکثر موارد یک متن ساده، JSON یا XML را به عنوان پاسخ برمیگردانند. توضیح در مورد REST با جزئیات بیشتر از حوزه این مقاله خارج است، اما میتوانید در مقاله بهترین شیوه های پیاده سازی REST API بیشتر در این مورد بدانید.
نحوه استفاده از RESTful API ها
اجازه بدید وارد موضوع اصلی این مقاله بشیم.
چند شیوه برای استفاده از RESTful API در #C وجود دارد:
- کلاس HttpWebRequest/Response
- کلاس WebClient
- کلاس HttpClient
- RestSharp NuGet Package
- ServiceStack Http Utils
- Flurl
- DalSoft.RestClient
هریک از این شیوه ها، مزایا و معایب به خصوص خودشان را دارند. پس اجازه بدید به سراغ آنها برویم و ببینیم که هریک چه چیزی را به ما پیشنهاد میدهند.
به عنوان یک مثال، ما اطلاعات مربوط به ورژنهای RestSharp و تاریخ انتشارشان را از طریق GitHub API جمع آوری میکنیم. این اطلاعات به صورت Public موجود است و شما میتوانید نحوه دریافت پاسخ آن را با فرمت JSON در RestSharp releases ببینید.
ما قصد داریم از کتابخانه Json.NET برای deserialize کردن Response که دریافت میکنیم استفاده نماییم. همچنین در برخی از مثالها، از مکانیسم های deserialization توکار در کتابخانه ها استفاده میکنیم. این کاملا به شما بستگی دارد که کدامیک را ترجیح میدهید زیرا هیچ کدام مناسب ترین شیوه به حساب نمی آیند.
چیزی را که من به عنوان نتیجه در مثالها قصد دارم دریافت کنم یک آرایه ای از Json به صورت deserialize شده است که شامل اطلاعات انتشارات مربوط به RestSharp میباشد. سپس ما میتوانیم با پیمایش بر روی آنها، نتایج را به صورت زیر دریافت کنیم.
کلاس HttpWebRequest/Response
این کلاس، پیاده سازی بر اساس HTTP از کلاس WebRequest است که در اصل برای handle کردن درخواست های HTTP به کار برده میشد. اما منسوخ شده است و با کلاس WebClient جایگزین شده است.
کلاس HttpWebRequest
کنترل دقیقی بر روی تمام جنبه های فرایند ایجاد request ارائه میدهد. همانطور که می توانید حدس بزنید، این می تواند مانند یک شمشیر دو لبه باشد و باعث میشود به راحتی زمان زیادی را برای تنظیم دقیق درخواست هایتان از دست بدهید. از طرفی دیگر، این میتواند برای مورد خاصی اگر نیاز داشته باشید مورد استفاده قرار گیرد.
کلاس HttpWebRequest
رابط کاربر را مسدود نمیکند و من مطمئن هستم که شما با این موضوع که این یک ویژگی خیلی مهم است موافق هستید.
کلاس HttpWebResponse
، یک container برای پاسخهای ورودی ارائه میدهد.
این یک مثال ساده از نحوه استفاده از API با استفاده از این کلاسها است:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class HttpWebRequestHandler : IRequestHandler { public string GetReleases(string url) { var request = (HttpWebRequest)WebRequest.Create(url); request.Method = "GET"; request.UserAgent = RequestConstants.UserAgentValue; request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip; var content = string.Empty; using (var response = (HttpWebResponse)request.GetResponse()) { using (var stream = response.GetResponseStream()) { using (var sr = new StreamReader(stream)) { content = sr.ReadToEnd(); } } } return content; } } |
اگرچه این یک مثال سادست، اما اگر با سناریوهای پیچیده تر مانند ارسال اطلاعات فرم، مجوز دسترسی و غیره سروکار داشته باشید در نتیجه کد پیچیده تر خواهد شد.
کلاس WebClient
این کلاس یک wrapper برای HttpWebRequest است. این کلاس، فرایند را با خلاصه کردن جزییات HttpWebRequest برای توسعه دهنده، ساده میکند. نوشتن کد برای این کلاس آسانتر است و شما در آن احتمالا کمتر مرتکب اشتباه خواهید شد. اگر شما قصد دارید که کمتر کد بنویسید و همچنین نگرانی در مورد جزییات نداشته باشید و سرعت اجرا نیز براتون ملاک مهمی نیست، در نتیجه میتوانید استفاده از کلاس WebClient
را مدنظر قرار دهید.
این مثال باید دید منصفانه ای رو در مورد اینکه چقدر استفاده از WebClient در مقایسه با رویکرد HttpWebRequest
/HttpWebResponse
آسانتر است را به شما بدهد:
1 2 3 4 5 6 7 |
public string GetReleases(string url) { var client = new WebClient(); client.Headers.Add(RequestConstants.UserAgent, RequestConstants.UserAgentValue); var response = client.DownloadString(url); return response; } |
خیلی آسانتر است. درست نیست؟!
علارغم متد DownloadString
، کلاس WebClient
متدهای مفید دیگری نیز ارائه میدهد که کار را برای ما
خیلی راحت تر میسازد. ما به قیمت چند میلی ثانیه سرعت کمتر نسبت به رویکرد HttpWebRequest
/HttpWebResponse
، در عوض به راحتی میتوانیم رشته ها، فایلها و آزایه ای از بایت ها را با استفاده از این کلاس WebClient
دستکاری نماییم.
هردوی این کلاسهای HttpWebRequest
/HttpWebResponse
و WebClient
در نسخه های قدیمیتر دات نت موجود هستند و اگر علاقه مند هستید تا بدانید که WebClient
دیگر چه چیزهایی را برای استفاده ارائه میدهد میتوانید MSDN را بررسی نمایید.
کلاس HttpClient
کلاس HttpClient
رویکرد جدیدی است و تعدادی عملکردهای مدرن دات نت را ارائه میدهد که کتابخانه های قدیمیتر فاقد آن بودند. برای مثال، شما میتوانید چند Request را با یک نمونه از HttpClient بفرستید. به سرور یا هاست HTTP خاصی متصل نیست و از مکانیسم async/await استفاده میکند.
شما میتوانید 5 دلیل خوب برای استفاده از HttpClient
را در این ویدئو ببینید:
- Strongly typed header ها
- کش ها، کوکی ها و گواهینامه های مشترک
- دسترسی به کوکی ها و کوکی های مشترک
- کنترل کامل روی caching و cache مشترک
- inject کردن ماژول کدتان به پایپ لاین Asp.net. کدنویسی تمیز و ماژولار.
این هم نمونه ای از HttpClient
مربوط به مثال ما:
1 2 3 4 5 6 7 8 9 10 11 |
public string GetReleases(string url) { using (var httpClient = new HttpClient()) { httpClient.DefaultRequestHeaders.Add(RequestConstants.UserAgent, RequestConstants.UserAgentValue); var response = httpClient.GetStringAsync(new Uri(url)).Result; return response; } } |
به دلیل سادگی، آن را به صورت synchronous پیاده سازی کردم. هر متد HttpClient
به معنی استفاده به صورت asynchronous است که باید به همین صورت استفاده شود.
همچنین من باید مورد دیگری را نیز ذکر کنم. اینکه HttpClient
آیا باید درون یک بلاک using مورد استفاده قرار گیرد یا به صورت استاتیک در سطح برنامه. اگرچه آن IDisposable
را پیاده سازی میکند، به نظر میرسد که با قرار دادن آن درون بلاک using، شما میتوانید اختلال در برنامه ایجاد کنید و socketException رو دریافت کنید و طبق نتایج تست عملکرد بلاگ های Ankit، نتایج بیشتر حاکی از مقدار دهی استاتیک HttpClient
دارد. حتماً این پست های وبلاگ را بخوانید زیرا این امر می تواند به شما کمک کند تا در مورد استفاده صحیح از کتابخانه HttpClient اطلاعات بیشتری کسب کنید.
در ضمن فراموش نکنید که HttpClient منحصر به دات نت 4.5 است و بنابراین ممکن است برای استفاده از آن در پروژه های قدیمی مشکل داشته باشید.
RestSharp
RestSharp یک کتابخانه استاندارد برای دات نت است که جایگزین OpenSource است و یکی از عالیترین کتابخانه های دات نت میباشد. این کتابخانه به عنوان یک NuGet package در دسترس است و چند دلیل جهت استفاده از این کتابخانه وجود دارد که شما بهتر است استفاده از آن را لحاظ نمایید.
مانند RestSharp ،HttpClient یک کتابخانه جامع و مدرن و استفاده از آن آسان و رضایت بخش است در حالیکه هنوز از ورژن های قدیمی دات نت فریم ورک نیز پشتیبانی میکند. این کتابخانه، مکانیسمهای Authentication و Serialization/Deserialization توکار را هم در خودش دارد، اما این امکان را هم به شما میدهد که بتوانید به صورت سفارشی آنها را override نیز نمایید. آن بین تمام پلت فرمها موجود است و از NTLM ،Basic ،OAuth1، OAuth2 و Authentication مبتنی بر پارامتر پشتیبانی میکند. شما میتوانید با هر دو رویکرد synchronouse یا asynchronouse در این کتابخانه کار کنید. جزییات بیشتری در مورد این کتابخانه وجود دارد و یک سری مزایای عالی جهت استفاده به شما ارائه میدهد. جهت دریافت اطلاعات بیشتر جهت استفاده و قابلیتهای آن، میتوانید صفحه مربوط به RestSharp در GitHub را مشاهده نمایید.
اکنون اجازه بدید لیستی از ورژنهای انتشار RestSharp را با استفاده از RestSharp دریافت کنیم:
1 2 3 4 5 6 7 8 |
public string GetReleases(string url) { var client = new RestClient(url); var response = client.Execute(new RestRequest()); return response.Content; } |
اگرچه ساده به نظر میرسد اما فریب نخورید، چرا که RestSharp خیلی انعطاف پذیراست و تمام ابزارهایی که شما جهت کار با RESTful API نیاز دارید را در دربردارد.
نکته ای که باید در این مثال ذکر شود این است که به دلیل حفظ ثبات مثال مورد نظر، من از مکانیسم deserialization این کتابخانه استفاده نکردم که کمی باعث اتلاف وقت میشود اما از آنجایی که استفاده از آن واقعا آسان و راحت است به شما توصیه میکنم که از آن استفاده نمایید. بنابراین شما به راحتی میتوانید یک container مانند این ایجاد نمایید:
1 2 3 4 5 6 7 |
public class GitHubRelease { [JsonProperty(PropertyName = "name")] public string Name { get; set; } [JsonProperty(PropertyName = "published_at")] public string PublishedAt { get; set; } } |
و بعد از آن از متد Execute
استفاده کنید و به صورت مستقیم، response را به این deserialize ،container نمایید. شما میتوانید فقط خصوصیتهایی را که نیاز دارید را اضافه نمایید و از ویژگی JsonProperty
برای مپ کردن آنها به خصوصیت های #C استفاده نمایید. از آنجایی که ما لیستی از ورژنها را میگیریم از List<GitHubRelease> به عنوان نوع container اطلاعات استفاده مینماییم:
1 2 3 4 5 6 7 8 |
public List<GitHubRelease> GetDeserializedReleases(string url) { var client = new RestClient(url); var response = client.Execute<List<GitHubRelease>>(new RestRequest()); return response.Data; } |
روشی بسیار ساده و عالی برای دریافت اطلاعات.
این کتابخانه چیزی بیش از ارسال درخواست های GET
است که خودتان میتوانید در موردش تحقیق کنید و از مزایای عالی آن مطلع شوید.
نکته آخر در مورد RestSharp این است که repository آن به حمایت کنندگان نیاز دارد. اگر میخواهید که بیشتر در مورد این کتابخانه عالی یاد بگیرید به شما توصیه میکنم که سری به RestSharp repo بزنید و کمک کنید تا این پروژه پابرجا بماند و حتی به کتابخانه بهتری نیز تبدیل شود.
ServiceStack Http Utils
این کتابخانه دیگری است که برخلاف RestSharp ، به نظر میرسد که به درستی مورد حمایت قرار گرفته و همگام با رویکردهای مدرن API پیش میرود. لیست ویژگی های ServiceStack، چشمگیر است و قطعا کاربردهای مختلفی دارد.
چیزی که خیلی اینجا برای ما مفید است این است که چطور از یک RESTful API خارجی استفاده کنیم. ServiceStack یک شیوه خاص برای سروکار داشتن با قسمت ثالث HTTP API ها به نام Http Utils دارد.
اکنون اجازه بدید تا ببینیم دریافت اطلاعات نسخه های مربوط به RestSharp با استفاده از ServiceStack Http Utils با استفاده از تجزیه کننده Json.NET ، چطور به نظر میرسد:
1 2 3 4 5 6 7 8 9 |
public string GetReleases(string url) { var response = url.GetJsonFromUrl(webReq => { webReq.UserAgent = RequestConstants.UserAgentValue; }); return response; } |
همچنین میتوانید به جای Json.NET، از تجزیه کننده خود ServiceStack استفاده نمایید. ما میتوانیم مجددا از کلاس GitHubRelease
که بالاتر تعریف کردیم استفاده نماییم:
1 2 3 4 5 6 7 8 9 |
public List<GitHubRelease> GetDeserializedReleases(string url) { var releases = url.GetJsonFromUrl(webReq => { webReq.UserAgent = RequestConstants.UserAgentValue; }).FromJson<List<GitHubRelease>>(); return releases; } |
همانطور که مشاهده میکنید هر دو روش به درستی کار میکند و شما میتوانید انتخاب کنید که آیا response را به صورت string دریافت میکنید یا اینکه فورا آن را deserialize میکنید.
اگرچه ServiceStack آخرین کتابخانه ای است که ما آن را کشف کردیم، اما به طور شگفت انگیزی از نحوه استفاده آسان آن به طور خوشایندی شگفت زده شدم و فکر میکنم این کتابخانه در آینده، ابزار اصلی جهت کار با API ها و سرویس ها برای من باشد.
Flurl
یکی از کتابخانه هایی که بسیاری از افراد در بخش نظرات درخواست کرده اند و مورد علاقه بسیاری در سراسر اینترنت است و همچنان مورد توجه قرار گرفته است.
Flurl معرف Fluent Url Builder است که شیوه ای است که کتابخانه، کوئری های خود را میسازد. برای کسانی که با روش کار fluent آشنا نیستید ، fluent به این معنی است که کتابخانه به گونه ای ساخته شده است که متدها برای دستیابی به خوانایی بیشتر ، شبیه به زبان انسان ، به یکدیگر زنجیر شده اند.
با ذکر چند مثال، میتوانیم نحوه کار این کتابخانه را بهتر درک کنیم (این یک نمونه، از اسناد رسمی برگرفته شده است):
1 2 3 4 5 6 7 8 9 10 11 |
// Flurl will use 1 HttpClient instance per host var person = await "https://api.com" .AppendPathSegment("person") .SetQueryParams(new { a = 1, b = 2 }) .WithOAuthBearerToken("my_oauth_token") .PostJsonAsync(new { first_name = "Claire", last_name = "Underwood" }) .ReceiveJson<Person>(); |
شما اینجا میبینید که متدها چطور برای تکمیل هدف به یکدیگر زنجیر شده اند.
در پس زمینه، Flurl از HttpClient استفاده میکند یا بهتر بگوییم که Flurl استفاده از کتابخانه HttpClient را با استفاده از سینتکس جذاب خود، جالبتر میکند. به این معنی که Flurl یک کتابخانه async است و خوب است که آن را به خاطر بسپارید.
همچون دیگر کتابخانه های پیشرفته، ما میتوانیم این را به دو روش متفاوت انجام دهیم:
1 2 3 4 5 6 7 8 9 |
public string GetReleases(string url) { var result = url .WithHeader(RequestConstants.UserAgent, RequestConstants.UserAgentValue) .GetJsonAsync<List<GitHubRelease>>() .Result; return JsonConvert.SerializeObject(result); } |
این روش تقریبا روش بسیار بدی است چرا که ما در حال serialize کردن نتیجه هستیم تا اینکه بعدا آن را deserialize کنیم. اگر شما در حال استفاده از کتابخانه ای مانند Flurl هستید بهتر است از این روش استفاده نکنید.
بهترین روش برای انجام این کار با این کتابخانه به این صورت است:
1 2 3 4 5 6 7 8 9 |
public List<GitHubRelease> GetDeserializedReleases(string url) { var result = url .WithHeader(RequestConstants.UserAgent, RequestConstants.UserAgentValue) .GetJsonAsync<List<GitHubRelease>>() .Result; return result; } |
با Result. ما داریم رفتار synchronous را در کد اعمال میکنیم. روش واقعی و توصیه شده برای استفاده از Flurl بدین صورت است:
1 2 3 4 5 6 7 8 |
public async Task<List<GitHubRelease>> GetDeserializedReleases(string url) { var result = await url .WithHeader(RequestConstants.UserAgent, RequestConstants.UserAgentValue) .GetJsonAsync<List<GitHubRelease>>(); return result; } |
که پتانسیل کامل کتابخانه Flurl را به نمایش می گذارد.
به طور خلاصه، دلایل استفاده از این کتابخانه مثل تبلیغات به نظر میرسد: استفاده آسان، مدرن، خوانا و قابل آزمایش. چه چیز دیگری را از یک کتابخانه انتظار دارید؟ open source باشد؟ بررسی کنید: Flurl repo و در صورت علاقه در آن مشارکت کنید.
DalSoft.RestClient
حالا این یکی کمی با هر چیزی که در این لیست تا الان آورده شده بود متفاوت است و کمی متفاوت عمل می کند.
اول از همه، شما میتوانید DalSoft.RestClient را یا از طریق NuGet Package Manager با تایپ: Install-Package DalSoft.RestClient
یا از طریق add package DalSoft.RestClient :NET Core CLIdotnet نصب نمایید.
هر دو روش خوب کار میکند.
پس از دانلود، ما میتوانیم مانند مثال زیر، کارمان را انجام دهیم:
1 2 3 4 5 6 7 8 9 |
public string GetReleases(string url) { dynamic client = new RestClient(RequestConstants.BaseUrl, new Headers { { RequestConstants.UserAgent, RequestConstants.UserAgentValue } }); var response = client.repos.restsharp.restsharp.releases.Get().Result.ToString(); return response; } |
یا ترجیحا، در حین اینکه این کتابخانه از قدرت کامل خود بهره میبرد با استفاده از DalSoft.RestClient بلافاصله response را deserialize نماییم:
1 2 3 4 5 6 7 8 9 |
public async Task<List<GitHubRelease>> GetDeserializedReleases(string url) { dynamic client = new RestClient(RequestConstants.BaseUrl, new Headers { { RequestConstants.UserAgent, RequestConstants.UserAgentValue } }); var response = await client.repos.restsharp.restsharp.releases.Get(); return response; } |
حلا کمی در مورد این مثالها صحبت کنیم.
در نگاه اول، آن خیلی ساده تر از دیگر کتابخانه های مدرنی که تا الان استفاده کردیم به نظر نمیرسد.
اما آن به شیوه request های ما برمیگردد و شیوه ای است که ماهیتی داینامیک از RestClient را به کار میبرد. برای مثال، BaseUrl ما https://api.github.com است و ما نیاز داریم که https://api.github.com/repos/restsharp/restsharp/releases را get کنیم. ما میتوانیم این کار را با ایجاد کلاینت به صورت داینامیک انجام دهیم و سپس با متصل کردن قسمتهای url به یکدیگر، آن را شکل دهیم و نتیجه را دریافت نماییم:
1 |
await client.repos.restsharp.restsharp.releases.Get(); |
این یک راه کاملا منحصر به فرد برای فرم دادن به یک request و یک راه کاملا انعطاف پذیر میباشد.
بنابراین، زمانیکه ما base Url مان را set کردیم میتوانیم با تمام endpoint های مختلف، به راحتی بازی کنیم.
همچنین لازم به ذکر است که JSON response که ما دریافت میکنیم به صورت خودکار به نوع داده ای مورد نظر cast میشود. همانطور که شما در مثال دوم میتوانید ببینید که مقدار بازگشتی متد ما، Task<List<GitHubReleases>> است. بنابراین این کتابخانه به اندازه کافی باهوش است که response را به نوع مورد نظر ما (متکی به Json.Net) قالب بندی کند.
علاوه بر اینکه فهم و استفاده از آن آسان است ، DalSoft.RestClient همه چیزهایی را که یک کتابخانه مدرن باید داشته باشد را دارد. آن قابل تنظیم، asynchronous، قابل توسعه و قابل تست است و از چند پلت فرم پشتیبانی میکند.
ما فقط قسمت کوچکی از ویژگی های DalSoft.RestClient را نشان داده ایم. گر این موضوع شما را به استفاده از DalSoft.RestClient علاقه مند کرده است به official GitHub repo یا مستندات مربوطه مراجعه کنید.
گزینه های دیگر
گزینه های زیاد دیگری برای موردهای خاص شما وجود دارد. شما میتوانید از هرکدام از این کتابخانه ها برای استفاده از یک RESTful API خاص استفاده کنید. برای مثال، octokit.net به طور ویژه برای کار با GitHub API و Facebook SDK برای استفاده از Facebook API مورد استفاده قرار گرفته است و تقریبا برای هرچیزی، کتابخانه ای وجود دارد.
در حالی که این کتابخانه ها به طور خاص برای API ها خاصی ساخته شده اند و ممکن است در انجام کار خود عالی باشند ، اما مفید بودن آنها محدود است زیرا شما اغلب در برنامه های خود باید به بیش از یک API متصل شوید. این ممکن است منجر به پیاده سازیهای مختلف و dependency های بیشتر برای هر یک از آنها شود که به طور بالقوه منجر به تکرار می شود و مستعد خطا است. کتابخانه هرچه بیشتر متمرکز برای یک هدف خاص باشد در نتیجه انعطاف پذیری آن کمتر است.
برای دانلود سورس مثالها اینجا کلیک نمایید.
نتیجه گیری
به طور خلاصه، ما در مورد ابزارهایی که میتوانید برای یک RESTful API استفاده کنید صحبت کردیم.ما بعضی کتابخانه های دات نت مانند HttpWebRequest، WebClient و HttpClient و همچنین بعضی ابزارهای جالب میانی مانند RestSharp و ServiceStack را برای کار با RESTful API ها ذکر کردیم. همچنین توضیحات کوتاهی را در مورد این ابزارها ارائه دادیم و مثالهای بسیار ساده ای از نحوه استفاده از این ابزارها را به شما نشان دادیم.
به نظر من، شما حداقل 95% آمادگی استفاده از این ابزارها را در حال حاضر دارید. حال فراتر بروید و روشهای جالب دیگری را نیز برای استفاده و اتصال به API های مختلف کشف کنید. حال با خیال راحت استراحت کنید چرا که راه حل را میدانید.