إنشاء خلفية الرسم البياني على Golang

اليوم سنقوم بتطوير تطبيق في Golang + GraphQL.

غالبًا ما نستخدم GraphQL في مشاريعنا ونعرف الكثير عنه ، ونستخدمه مع لغات برمجة مختلفة: Javascript و Ruby والآن وصلت أيدينا إلى نقطة تجربة حزمة Golang GraphQL.

لقد قيل الكثير عن مزايا لغة الاستعلام GraphQL على الإنترنت ، ويثني عليها كثيرون بسبب بساطتها ومرونتها وراحتها ، سواء عند استخدامها على جانب الخادم أو على العميل.

للتطوير المريح باستخدام GraphQL أو GraphiQL أو GraphQL Playground غالبًا ما يتم تكوينها - واجهة لإرسال الطلبات وعرض وثائق API.
لنشر مثل هذا الملعب محليًا ، يكفي استخدام هذا الحل المفتوح المصدر - Golang HTTP.Handler for graphl-go.

ملعب الرسم البياني

يبدو وكأنه ملعب للجري.

دعنا ننتقل إلى كتابة تطبيق صغير ، مثال سيحدد كيفية العمل مع GraphQL و Go. يمكن العثور على رمز التطبيق الكامل على الرابط في Github .

بادئ ذي بدء ، سنبدأ الخادم والملعب.

func main() {
  schema, err := graphql.NewSchema(defineSchema()) //      
  if err != nil {
     log.Panic("Error when creating the graphQL schema", err)
  }

  h := handler.New(&handler.Config{
     Schema:     &schema,
     Pretty:     true,
     GraphiQL:   false,
     Playground: true,
  }) //      FormatErrorFn -    

  http.Handle("/graphql", h) //      playground    
  err = http.ListenAndServe(":8080", nil)
  if err != nil {
     log.Panic("Error when starting the http server", err)
  }
}

لا يمكن لأي من الواجهة الخلفية Graphql الاستغناء عن وصف المخطط ، الآن سنقوم بتحليل وصفه.

var User = graphql.NewObject(
  graphql.ObjectConfig{
     Name: "User",
     Fields: graphql.Fields{
        "_id": &graphql.Field{
           Type: ObjectID,
        },
        "firstName": &graphql.Field{
           Type: graphql.String,
        },
        "lastName": &graphql.Field{
           Type: graphql.String,
        },
        "email": &graphql.Field{
           Type: graphql.String,
        },
     },
  },
)

var UserInput = graphql.NewInputObject(
  graphql.InputObjectConfig{
     Name: "UserInput",
     Fields: graphql.InputObjectConfigFieldMap{
        "firstName": &graphql.InputObjectFieldConfig{
           Type: graphql.String,
        },
        "lastName": &graphql.InputObjectFieldConfig{
           Type: graphql.Int,
        },
        "email": &graphql.InputObjectFieldConfig{
           Type: graphql.String,
        },
     },
  },
)

func defineSchema() graphql.SchemaConfig {
  return graphql.SchemaConfig{
     Query: graphql.NewObject(graphql.ObjectConfig{
        Name: "Query",
        Fields: graphql.Fields{
           "users": &graphql.Field{
              Name:    "users",
              Type:    graphql.NewList(User),
              Resolve: usersResolver,
           },
        },
     }),
     Mutation: graphql.NewObject(graphql.ObjectConfig{
        Name: "Mutation",
        Fields: graphql.Fields{
           "addUser": &graphql.Field{
              Name:    "addUser",
              Type:    User,
              Resolve: addUserResolver,
              Args: graphql.FieldConfigArgument{
                 "input": &graphql.ArgumentConfig{
                    Type: UserInput,
                 },
              },
           },
        },
     })}
}

أعلاه ، وصفنا نوع المستخدم مع الحقول _id و firstName و lastName والبريد الإلكتروني ، والتي سنستخدمها كنوع الاستجابة للطلبات. الحقل _id من نوع ObjectID ، وهو نوع مخصص ، حيث كان من الضروري إجراء تسلسل لنوع ObjectIDD MongoDB الأصلي ، وهو هيكل من هذا النوع.

type InsertOneResult struct {
  InsertedID interface{}
}

لوصف معلمات الإدخال للطفرة لإضافة مستخدم ، تم إنشاء نوع UserInput يحتوي على 3 حقول اختيارية تصف مستخدمنا. حقل _id غير موجود في هذا النوع ، حيث سيتم إنشاؤه في المحلل.

للتواصل مع mongodb ، يستخدم هذا المشروع برنامج تشغيل golang mongodb.

func usersCollection() *mongo.Collection { // ,   users    
  ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
  client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://mongo:27017"))
  if err != nil {
     log.Panic("Error when creating mongodb connection client", err)
  }
  collection := client.Database("testing").Collection("users")
  err = client.Connect(ctx)
  if err != nil {
     log.Panic("Error when connecting to mongodb", err)
  }

  return collection
}


//      
func usersResolver(_ graphql.ResolveParams) (interface{}, error) {
  ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
  collection := usersCollection()
  result, err := collection.Find(ctx, bson.D{})
  if err != nil {
     log.Print("Error when finding user", err)
     return nil, err
  }

  defer result.Close(ctx)

  var r []bson.M
  err = result.All(ctx, &r)
  if err != nil {
     log.Print("Error when reading users from cursor", err)
  }

  return r, nil
}


//     
func addUserResolver(p graphql.ResolveParams) (interface{}, error) {
  ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
  collection := usersCollection()
  //         ,   _id
  id, err := collection.InsertOne(ctx, p.Args["input"])
  if err != nil {
     log.Print("Error when inserting user", err)
     return nil, err
  }

  var result bson.M
  //       _id
  err = collection.FindOne(ctx, bson.M{"_id": id.InsertedID}).Decode(&result)
  if err != nil {
     log.Print("Error when finding the inserted user by its id", err)
     return nil, err
  }

  return result, nil
}

هنا قمنا بمعالجة طلب اكتساب المستخدم وتغييره باستخدام mongodb كمكان لتخزين بيانات المستخدم. بدلاً من قاعدة البيانات هذه ، يمكنك استخدام أي دولة أخرى دون أي مشاكل ، سواء غير العلائقية أو العلائقية ، لأن GraphQL لا يحدنا في اختيار قاعدة البيانات.

استخدمت رصيف يؤلف لحزم golang و mongodb. لهذا ، وصفت ملف الإعدادات الصغيرة. كل شيء جاهز. تسمح لنا بعض تقنيات golang mongo بتخزين بيانات المستخدم في شكل مناسب للعودة مرة أخرى من استعلامات GraphQL.

version: '3'
services:
graphql:
image: golang
volumes:
- .:/go/src
command: /bin/bash -c "cd src && go run *.go"
ports:
- 8080:8080
mongo:
image: mongo





بالطبع ، تبين أن هذا التطبيق بسيط للغاية ومضغوط. ويمكن أن تؤخذ كأساس لمشروعك المقبل وتكملها بأنواع جديدة وطلبات وتحولات ووظائف أخرى. هذه المرة لم نفكر في أمثلة على تنفيذ بعض ميزات GraphQL الأكثر إثارة للاهتمام ، على سبيل المثال ، الاشتراك. ربما سأستمر في هذا المثال في المستقبل ، لذا اترك تعليقات إذا كان هناك شيء مفقود بالنسبة لك في هذه المقالة وفي الجزء التالي سننظر بالتأكيد في ذلك.

All Articles