Buat backend graphql di Golang

Hari ini kita akan mengembangkan aplikasi di Golang + GraphQL.

Kami sering menggunakan GraphQL pada proyek kami dan tahu banyak tentang itu, menggunakannya bersama dengan berbagai bahasa pemrograman: Javascript, Ruby, dan sekarang tangan kami telah mencapai titik mencoba bundel Graphang Golang.

Banyak yang telah dikatakan tentang keunggulan bahasa query GraphQL di Internet, banyak yang memuji karena kesederhanaan, fleksibilitas, dan kenyamanannya, baik ketika digunakan di sisi server maupun pada klien.

Untuk pengembangan yang nyaman menggunakan GraphQL, GraphiQL atau GraphQL Playground sering dikonfigurasi - antarmuka untuk mengirim permintaan dan melihat dokumentasi API.
Untuk menggunakan Playground semacam itu secara lokal, cukup menggunakan solusi open source ini - Golang HTTP.Handler untuk graphl-go.

graphql playground golang

Sepertinya taman bermain berjalan.

Mari kita lanjutkan dengan menulis aplikasi kecil, contoh yang akan mencari cara untuk bekerja dengan GraphQL dan Go. Kode aplikasi lengkap dapat ditemukan pada tautan di Github .

Pertama-tama, kita akan memulai server dan taman bermain.

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)
  }
}

Tak satu pun dari backend graphql dapat melakukan tanpa deskripsi skema, sekarang kami akan menganalisis deskripsinya.

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,
                 },
              },
           },
        },
     })}
}

Di atas, kami menggambarkan tipe Pengguna dengan bidang _id, nama depan, nama belakang dan email, yang akan kami gunakan sebagai jenis respons terhadap permintaan. Bidang _id adalah tipe ObjectID, yang merupakan tipe kustom, karena itu perlu untuk membuat serialisasi jenis asli ObjectID tipe MongoDB, yang merupakan struktur dari jenis ini.

type InsertOneResult struct {
  InsertedID interface{}
}

Untuk menjelaskan parameter input ke mutasi untuk menambahkan pengguna, tipe UserInput dibuat berisi 3 bidang opsional yang menggambarkan pengguna kami. Bidang _id tidak ada dalam tipe ini, karena akan dihasilkan di resolver.

Untuk terhubung ke mongodb, proyek ini menggunakan driver 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
}

Di sini kami memproses permintaan untuk akuisisi dan mutasi pengguna, menggunakan mongodb sebagai tempat untuk menyimpan data pengguna. Alih-alih database ini, Anda bisa menggunakan yang lain tanpa masalah, baik non-relasional dan relasional, karena GraphQL tidak membatasi kami dalam memilih database.

Saya menggunakan buruh pelabuhan menulis untuk bundel golang dan mongodb. Untuk ini, saya menggambarkan file pengaturan kecil. Semuanya sudah siap. Sepasang teknologi golang mongo memungkinkan kita untuk menyimpan data pengguna dalam bentuk yang nyaman untuk pengembalian lebih lanjut dari permintaan 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





Tentu saja, aplikasi ini ternyata cukup sederhana dan ringkas. Dan itu dapat diambil sebagai dasar untuk proyek Anda berikutnya dan dilengkapi dengan tipe baru, permintaan dan mutasi, dan fungsi lainnya. Kali ini kami tidak mempertimbangkan contoh penerapan beberapa fitur GraphQL yang lebih menarik, misalnya, berlangganan. Mungkin saya akan melanjutkan contoh ini di masa depan, jadi tinggalkan komentar jika ada sesuatu yang tidak cukup untuk Anda di artikel ini dan di bagian selanjutnya kita pasti akan mempertimbangkan ini.

All Articles