30 Validasi Input di Mutation graphql-go
Pada era perkembangan aplikasi modern yang serba cepat dan terhubung, GraphQL telah menjadi pilihan utama dalam membangun API karena fleksibilitas dan efisiensinya. Namun, sering kali developer terlalu fokus pada desain schema dan resolver, lalu agak lalai pada aspek penting lainnya: validasi input, terutama pada operasi mutation.
Artikel ini akan membahas bagaimana menambahkan dan mengelola 30 validasi input pada mutation menggunakan library graphql-go
di bahasa pemrograman Go. Kita juga akan membahas contoh kode, simulasi, tabel validasi, dan blueprint arsitektur penyusunan validasi secara clean.
Mengapa Perlu Validasi di Layer Mutation?
Validasi input adalah proses memastikan data yang diterima oleh API telah sesuai dengan aturan, logika bisnis, maupun tipe data yang diharapkan. Dalam context mutation GraphQL, validasi input menjadi pintu gerbang agar data corrupt tidak menembus lebih dalam ke database, serta menjaga integrity sistem.
Tanpa validasi yang baik, masalah seperti data inconsistency, runtime error hingga security vulnerability seringkali muncul.
Sekilas Tentang graphql-go
graphql-go
adalah salah satu library populer di Go untuk membangun GraphQL server. Di sini, developer mendefinisikan schema dan resolver, namun urusan validasi tetap menjadi tanggung jawab kita.
Sebagai ilustrasi, definisi mutation sederhana di graphql-go:
var createUserMutation = &graphql.Field{
Type: userType,
Args: graphql.FieldConfigArgument{
"name": &graphql.ArgumentConfig{Type: graphql.NewNonNull(graphql.String)},
"email": &graphql.ArgumentConfig{Type: graphql.NewNonNull(graphql.String)},
"age": &graphql.ArgumentConfig{Type: graphql.Int},
"website": &graphql.ArgumentConfig{Type: graphql.String},
},
Resolve: createUserResolver,
}
Namun, validasi input tidak otomatis dilakukan library ini—semua tetap di-resolver.
30 Jenis Validasi Input untuk Mutation
Berikut adalah daftar 30 validasi input umum yang sering dan penting diterapkan pada mutation GraphQL:
No | Jenis Validasi | Contoh Aturan |
---|---|---|
1 | Required / Tidak Boleh Kosong | name, email wajib diisi |
2 | Panjang Minimum | Password min. 8 karakter |
3 | Panjang Maksimum | Username max. 30 karakter |
4 | Format Email | Validasi email RFC5322 |
5 | Format URL | Validasi website URL |
6 | Regex Custom | Nomor telepon sesuai regex |
7 | Nilai Unik | Email tidak boleh duplikat |
8 | Numeric Only | Hanya angka (kode pos, dsb) |
9 | Range Angka | Age: antara 18 dan 75 |
10 | Nilai Pilihan Enum | Status: ‘active’, ‘inactive’ |
11 | Tanggal Valid | Format ‘YYYY-MM-DD’ |
12 | Tidak Boleh Negatif | Nominal, jumlah |
13 | Nilai Default | Jika field tidak dikirim |
14 | Field Nested Wajib | data.profile.address wajib |
15 | Nested Array Validate | Minimal 1 item, dsb |
16 | Format UUID | id: uuid4 valid |
17 | No Special Character | Validasi username |
18 | Kondisional | Jika field A ada, field B wajib |
19 | Array Length Min/Max | Minimal/maksimal item array |
20 | CAPTCHA/Code Valid | Validasi kode eksternal |
21 | Required With | Field A wajib kalau field B ada |
22 | JSON Structure Format | Nested JSON sesuai schema |
23 | Nested Object Validate | Validasi setiap object dalam array |
24 | Existence in DB | id user harus exist di DB |
25 | File Upload Type | Hanya .jpg, .png |
26 | File Upload Size | Maksimal 2MB |
27 | RELATION Constraint | Foreign key exist |
28 | Unique Combination | username+email kombinasi unik |
29 | List Contains Value | Harus mengandung item X |
30 | Field Tidak Boleh Nilai Default | Tidak boleh ’test’, ‘dummy’ |
Pengelolaan Validasi: Clean dan Maintainable
Agar validasi 30 aturan di atas tidak menyebabkan resolver penuh if-else dan nested code, pattern clean architecture sangat diperlukan.
Saya biasanya membuat satu package khusus, contoh: validation
, lalu setiap validasi dijadikan fungsi reusable.
package validation
import (
"errors"
"regexp"
)
func RequiredString(s, field string) error {
if s == "" {
return errors.New(field + " wajib diisi")
}
return nil
}
func ValidateEmail(email string) error {
regex := `^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}$`
if !regexp.MustCompile(regex).MatchString(email) {
return errors.New("Email tidak valid")
}
return nil
}
Kemudian di resolver, validasi di-compose:
func createUserResolver(p graphql.ResolveParams) (interface{}, error) {
name, _ := p.Args["name"].(string)
email, _ := p.Args["email"].(string)
age, _ := p.Args["age"].(int)
website, _ := p.Args["website"].(string)
// 1. Required
if err := validation.RequiredString(name, "name"); err != nil {
return nil, err
}
// 2. Email format
if err := validation.ValidateEmail(email); err != nil {
return nil, err
}
// 3. Age range
if age < 18 || age > 75 {
return nil, errors.New("Umur harus 18-75 tahun")
}
// 4. Website format
if website != "" {
if err := validation.ValidateURL(website); err != nil {
return nil, err
}
}
// ... dan seterusnya (hingga 30 validasi)
return User{...}, nil
}
Simulasi: Satu Payload, Banyak Validasi
Kalau aplikasi besar, satu mutation bisa mengandung beberapa level validasi. Simulasi payload di bawah ini akan menunjukkan validasi di berbagai level.
Contoh Payload:
{
"name": "John Doe",
"email": "john_doe@email.com",
"age": 17,
"website": "not-a-url",
"roles": ["admin", "super_user"],
"profile": {
"bio": "",
"address": "Jl. Sudirman"
}
}
Layer Validasi
name
: Required, length max 50email
: Required, email format, unique in DBage
: Required, range 18-65website
: Optional, jika ada harus URL yang validroles
: Array min 1, harus enum valid (‘admin’, ‘user’, ’editor’)profile.bio
: Panjang max 160profile.address
: Required
Diagram Alur Validasi (Kode Mermaid)
flowchart TD Start --> CekName[Validasi name] CekName -- OK --> CekEmail[Validasi email] CekEmail -- OK --> CekAge[Validasi age] CekAge -- OK --> CekWebsite[Validasi website] CekWebsite -- OK --> CekRoles[Validasi roles] CekRoles -- OK --> CekProfileBio[Validasi profile.bio] CekProfileBio -- OK --> CekProfileAddress[Validasi profile.address] CekProfileAddress -- OK --> Sukses CekName -- ERROR --> Error["Return error"] CekEmail -- ERROR --> Error CekAge -- ERROR --> Error CekWebsite -- ERROR --> Error CekRoles -- ERROR --> Error CekProfileBio -- ERROR --> Error CekProfileAddress -- ERROR --> Error
Pattern: Validasi Aggregator
Agar setiap error tersebar, pattern error aggregator sangat membantu. Kita bisa menyimpan semua pesan error validasi, lalu di akhir hanya return jika error tidak kosong.
var validationErrs []string
if err := validation.RequiredString(name, "name"); err != nil {
validationErrs = append(validationErrs, err.Error())
}
// ... semua validasi
if len(validationErrs) > 0 {
return nil, errors.New(strings.Join(validationErrs, "; "))
}
Testing: Simulasikan Request
Untuk memastikan validasi bekerja, buatlah test dengan table driven test untuk setiap aturan.
func TestValidateCreateUserInput(t *testing.T) {
tests := []struct{
payload map[string]interface{}
wantErr bool
}{
{
payload: map[string]interface{}{"name": "", "email": "salah@", "age": 10},
wantErr: true,
},
{
payload: map[string]interface{}{"name": "Budi", "email": "budi@mail.com", "age": 20},
wantErr: false,
},
// dst, sesuai checklist 30 validasi
}
}
Kesimpulan
Menanamkan 30 validasi input mutation di graphql-go—dan scalable validasi untuk puluhan field—menuntut disiplin arsitektur clean serta kreatifitas dalam compose fungsi validasi. Validasi bukan hanya tegas pada sisi data type, namun juga pada custom rule, kondisional, maupun relasi DB.
Dengan pendekatan reusable validation function, error aggregator, dan error yang user-friendly, keamanan serta reliability API akan jauh meningkat.
Penutup:
Jangan anggap enteng validasi input mutation. Investasi waktu di awal akan menghindarkan deretan bug, serangan, hingga downtime di masa depan.
Referensi
Semoga artikel ini membantumu, dan—seperti biasa—jaga codebase-mu tetap robust dan clean! 🚀
Artikel Terhangat
30 Validasi Input di Mutation graphql-go
07 Jul 2025
51. Menggunakan TLS di gRPC Server
07 Jul 2025
50 Protobuf JSON Marshal dan Unmarshal
07 Jul 2025
27 Menulis Skema Mutation di GraphQL
07 Jul 2025
49 Serialisasi dan Deserialisasi Manual
07 Jul 2025

30 Validasi Input di Mutation graphql-go

51. Menggunakan TLS di gRPC Server

50 Protobuf JSON Marshal dan Unmarshal

27 Menulis Skema Mutation di GraphQL
