tutorial

20 Mengelola Query dengan Parameter di graphql-go


title: 20 Mengelola Query dengan Parameter di graphql-go date: 2024-06-26 author: Faris Azhar tags: [Go, GraphQL, Back-End, API, Tutorial]

GraphQL menawarkan fleksibilitas yang luar biasa dalam membangun API modern—termasuk pada pengelolaan query dengan parameter. Bagi backend engineer yang menggunakan Go, package graphql-go menjadi salah satu pilihan utama. Namun, manajemen parameter pada query GraphQL kadang menjadi stumbling block tersendiri, baik dari segi desain schema maupun implementasi resolver.

Dalam tulisan ini, saya akan mengupas tuntas perihal pengelolaan query dengan parameter menggunakan graphql-go, dilengkapi 20 best practices dan trik penting. Kita akan bahas baik secara konseptual, praktik kode, hingga contoh real-world yang berkaitan dengan filtering, pagination, validasi, dan error handling.


1. Menentukan Parameter di Skema Schema

Hal pertama adalah memahami letak parameter dalam schema GraphQL. Parameter disematkan sebagai argument pada field:

userType := graphql.NewObject(graphql.ObjectConfig{
    Name: "User",
    Fields: graphql.Fields{
        "id": &graphql.Field{Type: graphql.String},
        "name": &graphql.Field{Type: graphql.String},
    },
})

queryType := graphql.NewObject(graphql.ObjectConfig{
    Name: "Query",
    Fields: graphql.Fields{
        "user": &graphql.Field{
            Type: userType,
            Args: graphql.FieldConfigArgument{
                "id": &graphql.ArgumentConfig{
                    Type: graphql.NewNonNull(graphql.String),
                },
            },
            Resolve: userResolver,
        },
    },
})

Dengan skema di atas, klien dapat melakukan query seperti:

{
  user(id: "1") {
    name
  }
}

2. Penggunaan Default Value pada Argument

Argument bisa diberikan default value, sehingga tidak wajib selalu diberikan oleh klien:

"status": &graphql.ArgumentConfig{
    Type:         graphql.String,
    DefaultValue: "active",
},

3. Mendefinisikan Argument Kompleks (Input Object)

Untuk parameter lebih kompleks, gunakan Object Input Type:

userFilterInput := graphql.NewInputObject(graphql.InputObjectConfig{
    Name: "UserFilter",
    Fields: graphql.InputObjectConfigFieldMap{
        "name": &graphql.InputObjectFieldConfig{Type: graphql.String},
        "age":  &graphql.InputObjectFieldConfig{Type: graphql.Int},
    },
})

"users": &graphql.Field{
    Type: graphql.NewList(userType),
    Args: graphql.FieldConfigArgument{
        "filter": &graphql.ArgumentConfig{Type: userFilterInput},
    },
    Resolve: usersResolver,
}

4. Mengambil Parameter di Resolver

Argument didapatkan lewat params.Args dalam resolver:

func userResolver(p graphql.ResolveParams) (interface{}, error) {
    id, ok := p.Args["id"].(string)
    if !ok {
        return nil, errors.New("ID is required")
    }
    // Query ke database
}

5. Validasi Argument

Selalu lakukan validasi sebelum meneruskan param ke proses selanjutnya.

if len(id) != 36 {
    return nil, errors.New("Invalid ID format")
}

6. Parameter Optional dan Nullables

Kesalahan umum terjadi ketika parameter optional tidak dicek nilainya (ada di params.Args atau tidak).

var name string
if n, exists := p.Args["name"]; exists {
    name = n.(string)
}

7. Filtering Multi-Field

Izinkan filter dengan array/daftar pada argument.

"tags": &graphql.ArgumentConfig{
    Type: graphql.NewList(graphql.String),
},

8. Implementasi Pagination

Pagination sangat umum. Manfaatkan parameter limit dan offset:

"users": &graphql.Field{
    Type: graphql.NewList(userType),
    Args: graphql.FieldConfigArgument{
        "limit":  &graphql.ArgumentConfig{Type: graphql.Int, DefaultValue: 10},
        "offset": &graphql.ArgumentConfig{Type: graphql.Int, DefaultValue: 0},
    },
    Resolve: usersResolver,
}

9. Parameter Enum

Definisikan tipe Enum agar pemanggil hanya bisa memilih nilai valid.

statusEnum := graphql.NewEnum(graphql.EnumConfig{
    Name: "Status",
    Values: graphql.EnumValueConfigMap{
        "ACTIVE": &graphql.EnumValueConfig{Value: "active"},
        "INACTIVE": &graphql.EnumValueConfig{Value: "inactive"},
    },
})

10. Parameter Nested

Buat input type dalam input type untuk query nested, misal filter dalam filter.


11. Array Parameter

Argument bertipe list, misal multi ID.

"ids": &graphql.ArgumentConfig{
    Type: graphql.NewList(graphql.String),
}

12. Input Validation di Resolver

Selain di schema, tambahkan validasi di resolver. Misal cek uniqueness, relasi foreign key, dsb.


13. Simulasi Query dengan Parameter

Mari bandingkan query dengan/ tanpa parameter:

QueryResponse
users(limit: 2)[{"id":"1"}, {"id":"2"}]
user(id: "xyz"){"id": "xyz", "name": "Dewi"}
users(filter: {...})[{"id":"a"}, {"id":"b"}]

14. Penanganan Kesalahan (Error Handling)

Selalu kirim error yang “clear” di resolver ketika validasi gagal.


15. Query Variables

Gunakan query variables alih-alih hard-coded parameter di klien:

query getUser($id: String!) {
  user(id: $id) {
    name
  }
}

16. Dokumentasi Parameter Schema

Manfaatkan deskripsi pada schema, agar dev frontend mudah mengerti argumen yang tersedia.


17. Parameter Query Dinamis

Jika parameter bisa satu dari banyak field (misal filter by email atau username):

Args: graphql.FieldConfigArgument{
    "email":    &graphql.ArgumentConfig{Type: graphql.String},
    "username": &graphql.ArgumentConfig{Type: graphql.String},
}

Di resolver, cek mana argumen terisi.


18. Diagram Alur Proses Parameter Query

Untuk gambaran lebih jelas, berikut flow resolver dalam query dengan parameter di graphql-go:

graph TD
    A[Klien Mengirim Query dgn Parameter] --> B[GraphQL Handler Receive]
    B --> C[Schema Validate Param]
    C --> D[Resolver Ambil Params]
    D --> E[Validasi & Filtering di Go]
    E --> F[Query ke DB]
    F --> G[Return Response]

19. Response Field Terbatas oleh Parameter

Bisa juga batasi field yang di-query pakai parameter, mirip projection pada SQL/MongoDB.


20. Separation of Concerns

Pisahkan logic handler GraphQL, validasi parameter, data access, dan error handling dalam kode Go Anda.


Kesimpulan

Mengelola query dengan parameter di graphql-go adalah hal fundamental jika Anda ingin membangun API GraphQL robust, scalable, dan maintainable di Go. Sebagai penutup, berikut tabel ringkasan best practices:

NoBest PracticeImplementation Example
1Parameter di SchemaArgs: FieldConfigArgument{...}
4Param di Resolverp.Args["param_name"]
8PaginationArg limit, offset & validate di Go
13Simulasi QueryCek hasil berbeda tergantung argumen
20Separation of ConcernPisahkan handler, validasi, data, error

Mulailah mengoptimalkan reflectivity implementation Anda, bahkan untuk query-query yang kelihatan trivial sekalipun. Keamanan, efisiensi, dan kemudahan debugging adalah investasi yang sepadan untuk proyek Go Anda berikutnya!

Punya tips lain yang belum dibahas? Tulis di kolom komentar, mari diskusi! 🚀

comments powered by Disqus