في الجزء الثاني من سلسلة مقالاتنا "كتابة مدونة على Microservices" وصفنا
بوابة API .
نحن هنا وصف تنفيذ microservice المستخدم.
يجب أن تكون خدماتنا المصغرة قادرة على:
- مكالمات خدمة السجل والحالات الوسيطة التي تشير إلى TraceId (نفس المكالمات الصادرة عن api-gw ، راجع الجزء 2 "بوابة API" )
- تنفيذ وظائف تسجيل الدخول (SignIN) والتسجيل (SignUp)
- تنفيذ وظائف CRUD (إنشاء ، قراءة ، تحرير ، حذف السجلات في قاعدة البيانات). استخدم MongoDB كقاعدة البيانات.
أولاً ، نصف خدمتنا في ملف proto (./services/user/protobuf/user.proto).
حدد بناء الجملة المستخدم - proto3. نشير إلى اسم حزمة protobuf ، في هذه الحزمة سيتم تنفيذ الكود الذي تم إنشاؤه تلقائيًا للخادم وقطع العميل.
نحن نستورد google / api / annotations.proto مكتبة التعليقات التوضيحية ، وستكون هناك حاجة لوصف التوجيهات لإنشاء واجهة برمجة تطبيقات REST.
syntax = "proto3"; package protobuf; import "google/api/annotations.proto";
وصف خدمة المستخدم ، مباشرة واجهات (الطرق) التي ينبغي أن يكون. على سبيل المثال ، واجهة SignUp (التسجيل): تتلقى رسالة SignUpRequest تحتوي على سمات اسم المستخدم وكلمة المرور والاسم الأول واسم العائلة وتستجيب برسالة SignUpResponse التي تحتوي على سمات Slug (UserID) واسم المستخدم والدور. أيضًا في وصف الواجهة ، في قسم الخيارات ، حدد توجيه المنشور: "/ api / v1 / user / signup. بناءً عليه ، سينشئ منشئ الكود واجهة REST التي ستتلقى طلبات POST على http: {{api_gw_host}} / api / v1 / user / الاشتراك.
ويتوقع الهيكل التالي في نص الطلب:
{ Username: 'username_value', Password: 'password_value', FirstName: 'firstname_value', LastName: 'lastname_value', }
وبناءً على ذلك ، إذا نجح ، فسوف يعطي الهيكل:
{ Slug: 'user_id_value', Username: 'username_value', Role: 'role_value', }
أو خطأ. سنخبرك أكثر بالأخطاء في وقت لاحق في القسم الذي يصف الوظائف التي تنفذ الواجهات الموضحة في ملف التعريف.
يتم الإعلان عن واجهات أخرى (تسجيل الدخول ، إنشاء ، تحديث ، حذف ، الحصول ، البحث) بالطريقة نفسها.
الآن أن لدينا ملف تعريف جاهز. نذهب إلى الدليل الجذر للمشروع وننفذ الأمر sh ./bin/protogen.sh. سيقوم هذا البرنامج النصي بإنشاء الرمز الرئيسي.
بعد ذلك ، انتقل إلى دليل ./services/user وفي ملف jobs.go ، اكتب تنفيذ الواجهات المعلنة.
أولاً ، نطبق الوسيطة. عند كل طلب للخدمة ، نسحب معلمات TraceId و UserId و UserRole من سياق الطلب ونكتبها في ملف السجل. هنا يمكنك تنفيذ تفويض الطلب.
في طريقة SignUp ، نحدد بنية الاستجابة.
بعد ذلك ، تحقق من معلمات الطلب.
وإذا كان كل شيء على ما يرام ، فاملأ هيكل المستخدم ، واكتب إلى قاعدة البيانات وأرجع الإجابة.
user:=&User{ Username:in.Username, FirstName:in.FirstName, LastName:in.LastName, Password:getMD5(in.Password), } var slug string collection:= o.DbClient.Database("blog").Collection("users") insertResult, err := collection.InsertOne(context.TODO(), user) if err != nil { return out,err } if oid, ok := insertResult.InsertedID.(primitive.ObjectID); ok { slug=fmt.Sprintf("%s",oid.Hex()) }else { err:=app.ErrInsert return out,err } out.Slug=slug out.Username=in.Username out.Role=app.ROLE_USER return out,nil
بشكل منفصل ، ننتبه إلى عودة الخطأ ، على سبيل المثال:
err:=app.ErrInsert
نظرًا لأن هذا الخطأ سيعود في النهاية إلى api-wg (في جزء REST الخاص به) وسيكون من الجيد تحويله إلى رمز استجابة HTTP قياسي. من أجل عدم كتابة مجموعة من التعليمات البرمجية الإضافية ، يجب ألا تستخدم خطأ go القياسي ، ولكن status.error من google.golang.org/grpc/status package.
يتم توضيح جميع الأخطاء النموذجية لخدمة المستخدم الصغيرة وكيفية تحويلها إلى رموز استجابة HTTP في الملف. / Services / user / app / errors.go.
package app import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" )
وآخر شيء أود أن أخبره عن خدمة المستخدم الصغيرة هو كيفية بدء تشغيله والاتصال بقاعدة البيانات. يتم تنفيذ هذه العمليات في الملف ./services/user/main.go.
إطلاق الخدمة:
lis,err:= net.Listen("tcp", fmt.Sprintf(":%s", Port)) if err != nil { log.Fatalf("failed to listen: %v", err) } grpcServer:= grpc.NewServer( grpc.UnaryInterceptor(protobuf.AccessLogInterceptor), ) s:=&protobuf.Server{} …
الاتصال بقاعدة البيانات (main.go):
تنفيذ وظيفة DbConnect (./services/user/functions.go):