در این مقاله در خصوص پیادهسازی API Versioning در ASP.NET Core خواهیم آموخت.
اولین سؤال اینجا مطرح می شود که چرا ما باید API های خود را نسخه بندی کنیم؟
اگر قرار به توسعه ویژگی جدید باشد معمولا API کنونی خود را بروز رسانی میکنیم، اما این تغییرات گاهی میتواند مشکلات زیادی را همراه داشته باشند.
نسخه بندی API استراتژی است برای نگه داشتن وضعیت کنونی API شما به همراه ارائه ویژگی های جدید تر.
یکی از ویژگی های مهم API Versioning قابلیت بازگشت پذیری (backward compatibility) است، بدین معنا که شما با کمترین هزینه این امکان را فراهم میکنید تا در نزدیک ترین زمان ممکن به نسخه قبل API خود بازگردید.
یکی دیگر از مزایا استفاده از این ویژگی این است که شما به کاربران برنامه خود این اجازه را میدهید تا با مرور زمان به نسخه جدید مهاجرت کنند.
در این مقاله قصد دارم 4 راه متفاوت پیادهسازی API Versioning را شرح دهم، و شما بنا به برنامه خود میتوانید از آن استفاده کنید.
برای API Versioning نیاز به یک ASP.NET Core web API داریم،
باید کتابخانه مربوط به آن را نصب کنیم.
Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer
باید تنظیمات مربوط به سرویس Api versioning را در program.cs ثبت کنیم.
builder.Services.AddApiVersioning(o => { o.AssumeDefaultVersionWhenUnspecified = true; o.DefaultApiVersion = new Microsoft.AspNetCore.Mvc.ApiVersion(1, 0); o.ReportApiVersions = true; o.ApiVersionReader = ApiVersionReader.Combine( new QueryStringApiVersionReader("api-version"), new HeaderApiVersionReader("X-Version"), new MediaTypeApiVersionReader("ver") ); });
همانطور که بالا اشاره کردم راههای متفاوتی برای استفاده از نسخه بندی API شما وجود دارد.
با استفاده از پراپرتی های AssumeDefaultVersionWhenUnspecified و DefaultApiVersion
اگر کلاینت، نسخه مورد نظر را در درخواست خود ارسال نکرد، به صورت پیشفرض نسخه آن را 1 در نظر میگیریم.
با پراپرتیReportApiVersions
این اجازه را میدهیم تا از نسخه های مختلف مورد پشتیبانیAPI استفاده کنیم، که این ویژگی امکان های api-supported-versions و api-deprecated-versions
را فراهم میکند.
در نهایت، به این دلیل که قرار است برنامه ما نسخه های مختلف را پشتیبانی کند، با استفاده از ApiVersionReader این امکان را فراهم میکنیم تا با راههای مختلف امکان ارسال درخواست خود را داشته باشیم.
اولین روشی که میتوانیم استفاده کنیم استفاده از Query String است، برای این منظور کنترلر زیر را پیادهسازی میکنیم:
[ApiController] [Route("[controller]")] [ApiController] [Route("[controller]")] [ApiVersion("1.0")] public class EmployeeController:ControllerBase { private readonly IMediator _mediator; public EmployeeController(IMediator mediator) { _mediator = mediator; } [HttpGet] [Route("GetEmployeeById")] public async Task<IActionResult> GetEmployeeById( long id) { var employee =await _mediator.Send(new GetEmployeeByIdQuery(id)); return Ok(employee); } [HttpGet] [Route("GetEmployeeByEmail")] [ApiVersion("2.0")] public async Task<IActionResult> GetEmployeeByEmail( string email) { var employee =await _mediator.Send(new GetEmployeeByEmailQuery(email)); return Ok(employee); } }
در این کنترلر با استفاده از [ApiVersion("1.0")] مشخص کردیم که کنترلر ما از نسخه یک پشتیبانی خواهد کرد، همچنین در endpoint خود با اسفاده از کتابخانه mediatR اطلاعات مربوط به کارمند را دریافت میکنیم.
برای آشنایی بیشتر با الگوی mediator میتوانید به این مقاله و ویدیو مراجعه کنید.
با اجرای برنامه خود میتوانیم با ارائه api-version در query string به endpoint دسترسی داشته باشیم.
این روش به ما این اجازه را میدهد تا URI خود را تمیز نگه داریم، بدین صورت که ما فقط مقادیر header را اضافه خواهیم کرد. بدین ترتیب مقدار X-Version را برابر 1 قرار میدهیم و آن را در Header ایجاد میکنیم.
اگر نسخه Endpoint با نسخه ارسالی client یکسان نباشد پیام خطا دریافت خواهیم کرد، به عنوان مثال اجازه دهید نسخه endpoint بالا را به 2.0 تغییر دهیم.
روش سوم استفاده از پارامتر Accept میباشد، بدین صورت میتوان مقدار آن را به روز رسانی کرد و نسخه 2 مربوط به دریافت اطالاعات کارمند (GetEmployeeByEmail) را دریافت کرد.
مقدار accept باید برابر با application/json;ver=2.0 باشد.
استفاده از URI versionion یکی از متداولترین روش ها برای پیادهسازی میباشد، به این دلیل که به سادگی قابل خواندن است.
بدین صورت باید کنترلر خود را بهصورت زیر پیادهسازی کنیم، برای این منظور تنها کافی است که route مربوط به کنترلر را تغییر دهیم.
[ApiController] [Route("api/v{version:apiVersion}")] [ApiVersion("1.0")] public class EmployeeController:ControllerBase { private readonly IMediator _mediator; public EmployeeController(IMediator mediator) { _mediator = mediator; } [HttpPost] public async Task<IActionResult> AddEmployee(AddEmployeeInput employee) { var id =await _mediator.Send(new AddEmployeeCommand(employee.FirstName,employee.LastName,employee.Email)); return Ok(id); } [HttpGet] [Route("GetEmployeeById")] public async Task<IActionResult> GetEmployeeById( long id) { var employee =await _mediator.Send(new GetEmployeeByIdQuery(id)); return Ok(employee); } [HttpGet] [Route("GetEmployeeByEmail")] [ApiVersion("2.0")] public async Task<IActionResult> GetEmployeeByEmail( string email) { var employee =await _mediator.Send(new GetEmployeeByEmailQuery(email)); return Ok(employee); } }
همانطور که می بینید ما تنها route را تغییر دادیم، برای ارسال درخواست از client کافیست تا نسخه مورد نیاز را در URI ارسال کنیم.
در آدرس بالا ما تنها نسخه مربوط به API را مشخص کردیم، اما برای درخواست GetEmployeeById که از نسخه 1 استفاده میکند باید URI خود را به نسخه 1 تغییر دهیم.
در این مقاله توانستیم از نسخه بندی API استفاده کنیم، مزایای مربوط به این ویژگی را مطالعه کردیم و از روش های متفاوت برای پیادهسازی استفاده کردیم.
ممنونم بابت لایک، کامنت و دنبال کردن من، باعث میشه با قدرت بیشتری ادامه بدم :)