مرحبا يا هبر! أقدم لكم ترجمة المقال " إنشاء بوابة API بسيطة في ASP.NET Core ".
10 دقائق للقراءة
في مقالتي السابقة ، مصادقة JWT للخدمات الصغيرة في .NET ، نظرت في عملية إنشاء خدمة صغيرة لمصادقة المستخدم. يمكن استخدام هذا للتحقق من هوية المستخدم قبل تنفيذ أي إجراءات في مكونات النظام الأخرى.

مكون حيوي آخر للمنتج للعمل هو بوابة API - نظام بين التطبيق والواجهة الخلفية ، والذي ، أولاً ، يوجه الطلبات الواردة إلى الخدمات الصغيرة المقابلة ، وثانياً ، يخول المستخدم.
هناك العديد من الإطارات التي يمكن استخدامها لإنشاء بوابة API ، على سبيل المثال ، Ocelot في .NET core أو Netflix Zuul في Java. ومع ذلك ، في هذه المقالة سأصف عملية إنشاء بوابة API بسيطة من نقطة الصفر في .NET Core.
إنشاء المشروع
أولاً ، قم بإنشاء تطبيق جديد بتحديد ASP.NET Core Web Application في نافذة إنشاء المشروع وإفراغ كقالب.


سيحتوي المشروع على فئتي بدء التشغيل والبرنامج . بالنسبة لنا ، الجزء الأكثر أهمية هو طريقة تكوين فئة بدء التشغيل . هنا يمكننا معالجة طلب HTTP الوارد والاستجابة له. ربما يكون الرمز التالي في طريقة التكوين :
app.Run(async (context) => { await context.Response.WriteAsync("Hello, World!"); });
تهجئة جهاز التوجيه
نظرًا لأنه في أسلوب التهيئة سنقوم بمعالجة الطلبات ، سنكتب المنطق الضروري:
Router router = new Router("routes.json"); app.Run(async (context) => { var content = await router.RouteRequest(context.Request); await context.Response.WriteAsync(await content.Content.ReadAsStringAsync()); });
أولاً نقوم بإنشاء كائن من نوع جهاز التوجيه . تتضمن مهامه تخزين المسارات الموجودة والتحقق من صحة وإرسال الطلبات وفقًا للطرق. لجعل الشفرة أكثر نظافة ، سنقوم بتحميل المسارات من ملف JSON.
والنتيجة هي المنطق التالي: بعد وصول الطلب إلى البوابة ، سيتم إعادة توجيهه إلى جهاز التوجيه ، والذي بدوره سيرسله إلى الخدمة المصغرة المقابلة.
قبل كتابة فئة جهاز التوجيه ، قم بإنشاء ملف route.json . في هذا الملف ، نشير إلى قائمة من المسارات ، سيحتوي كل منها على عنوان خارجي (نقطة نهاية) وعنوان وجهة (وجهة). أيضًا ، سنضيف علامة تشير إلى الحاجة إلى تخويل المستخدم قبل إعادة التوجيه.
إليك ما قد يبدو عليه الملف:
{ "routes": [ { "endpoint": "/movies", "destination": { "uri": "http://localhost:8090/movies/", "requiresAuthentication": "true" } }, { "endpoint": "/songs", "destination": { "uri": "http://localhost:8091/songs/", "requiresAuthentication": "false" } } ], "authenticationService": { "uri": "http://localhost:8080/api/auth/" } }
قم بإنشاء فئة وجهة
نحن نعلم الآن أن كل مسار يجب أن يكون له endpoint
destination
، ويجب أن يكون لكل وجهة وجهة uri
requiresAuthentication
حقول uri
.
الآن دعونا نكتب فئة الوجهة ، وتذكر ذلك. سأضيف حقلين ، منشئين ومنشئ خاص بدون معلمات لإلغاء تسلسل JSON.
public class Destination { public string Uri { get; set; } public bool RequiresAuthentication { get; set; } public Destination(string uri, bool requiresAuthentication) { Uri = path; RequiresAuthentication = requiresAuthentication; } public Destination(string uri) :this(uri, false) { } private Destination() { Uri = "/"; RequiresAuthentication = false; } }
أيضا ، سيكون من الصحيح لكتابة الأسلوب SendRequest
في هذه الفئة. سيظهر ذلك أن كل كائن من فئة الوجهة سيكون مسؤولاً عن إرسال الطلب. ستأخذ هذه الطريقة كائنًا من نوع HttpRequest
، الذي يصف الطلب الوارد ، ويأخذ جميع المعلومات اللازمة من هناك ، ويرسل الطلب إلى عنوان URI الهدف. للقيام بذلك ، نكتب طريقة مساعدة CreateDestinationUri
، والتي ستربط السطور بالعنوان والمعلمات من سطر العنوان (سلسلة الاستعلام) من العميل.
private string CreateDestinationUri(HttpRequest request) { string requestPath = request.Path.ToString(); string queryString = request.QueryString.ToString(); string endpoint = ""; string[] endpointSplit = requestPath.Substring(1).Split('/'); if (endpointSplit.Length > 1) endpoint = endpointSplit[1]; return Uri + endpoint + queryString; }
يمكننا الآن كتابة طريقة SendRequest
التي سترسل طلبًا للحصول على خدمة متناهية الصغر وستتلقى ردًا مرة أخرى.
public async Task<HttpResponseMessage> SendRequest(HttpRequest request) { string requestContent; using (Stream receiveStream = request.Body) { using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8)) { requestContent = readStream.ReadToEnd(); } } HttpClient client = new HttpClient(); HttpRequestMessage newRequest = new HttpRequestMessage(new HttpMethod(request.Method), CreateDestinationUri(request)); HttpResponseMessage response = await client.SendAsync(newRequest); return response; }
أنشئ محلل JSON.
قبل كتابة فئة جهاز التوجيه ، نحتاج إلى إنشاء منطق لإلغاء تسلسل ملف JSON مع المسارات. سأقوم بإنشاء فئة مساعدة لهذا ، حيث ستكون هناك طريقتان: واحدة لإنشاء كائن من ملف JSON ، والأخرى لإلغاء التسلسل.
public class JsonLoader { public static T LoadFromFile<T>(string filePath) { using (StreamReader reader = new StreamReader(filePath)) { string json = reader.ReadToEnd(); T result = JsonConvert.DeserializeObject<T>(json); return result; } } public static T Deserialize<T>(object jsonObject) { return JsonConvert.DeserializeObject<T>(Convert.ToString(jsonObject)); } }
موجه Class.
آخر شيء سنفعله قبل كتابة جهاز التوجيه هو وصف نموذج المسار:
public class Route { public string Endpoint { get; set; } public Destination Destination { get; set; } }
الآن دعنا نكتب فئة جهاز التوجيه بإضافة حقول ومنشئ هناك.
public class Router { public List<Route> Routes { get; set; } public Destination AuthenticationService { get; set; } public Router(string routeConfigFilePath) { dynamic router = JsonLoader.LoadFromFile<dynamic>(routeConfigFilePath); Routes = JsonLoader.Deserialize<List<Route>>( Convert.ToString(router.routes) ); AuthenticationService = JsonLoader.Deserialize<Destination>( Convert.ToString(router.authenticationService) ); } }
أستخدم نوعًا ديناميكيًا للقراءة من JSON وكتابة خصائص الكائن إليه.
الآن كل شيء جاهز لوصف الوظيفة الرئيسية لبوابة API: التوجيه وتفويض المستخدم ، والذي سيحدث في طريقة RouteRequest
. نحتاج إلى فك الجزء الأساسي من العنوان الخارجي (نقطة النهاية الأساسية) من كائن الطلب. على سبيل المثال ، بالنسبة للعنوان /movies/add
ستكون القاعدة /movies/
. بعد ذلك ، نحتاج إلى التحقق مما إذا كان هناك وصف لهذا المسار. إذا كان الأمر كذلك ، فقم بتفويض المستخدم وإرسال الطلب ، وإلا فإننا نعرض خطأ. لقد أنشأت أيضًا فئة ConstructErrorMessage للراحة.
للحصول على التفويض ، فضلت الطريقة التالية: نستخرج الرمز المميز من رأس الطلب ونرسله كمعلمة طلب. هناك خيار آخر ممكن: اترك الرمز المميز في الرأس ، ثم يجب أن تقوم الخدمة الدقيقة التي يقصد بها الطلب باستخراجها بالفعل.
public async Task<HttpResponseMessage> RouteRequest(HttpRequest request) { string path = request.Path.ToString(); string basePath = '/' + path.Split('/')[1]; Destination destination; try { destination = Routes.First(r => r.Endpoint.Equals(basePath)).Destination; } catch { return ConstructErrorMessage("The path could not be found."); } if (destination.RequiresAuthentication) { string token = request.Headers["token"]; request.Query.Append(new KeyValuePair<string, StringValues>("token", new StringValues(token))); HttpResponseMessage authResponse = await AuthenticationService.SendRequest(request); if (!authResponse.IsSuccessStatusCode) return ConstructErrorMessage("Authentication failed."); } return await destination.SendRequest(request); } private HttpResponseMessage ConstructErrorMessage(string error) { HttpResponseMessage errorMessage = new HttpResponseMessage { StatusCode = HttpStatusCode.NotFound, Content = new StringContent(error) }; return errorMessage; }
الخلاصة
لا يتطلب إنشاء بوابة API أساسية الكثير من الجهد ، ولكنه لا يوفر وظائف مناسبة. إذا كنت بحاجة إلى موازن تحميل ، يمكنك إلقاء نظرة على الأطر أو الأنظمة الأساسية الموجودة التي تقدم مكتبات لطلبات التوجيه.
كل الكود الموجود في هذه المقالة متاح في مستودع GitHub.