Bismillah
Saat membuat sebuah API, terkadang tidak hanya satu jenis platform yang meng-consume api tersebut. Di era sekarang ini, saat men-develop sebuah aplikasi berbasis website, maka juga akan diiringi dengan aplikasi mobile-nya baik Android maupun IOS. Jika jenis dan jumlah data yang dikirim oleh backend disamakan antara platform website dan mobile tadi, maka akan menjadi kurang efektif karena belum tentu data yang dibutuhkan oleh aplikasi website sama dengan data yang dibutuhkan oleh mobile, baik dari jenis dan jumlah datanya. Mungkin saja di website membutuhkan data dengan 5 atau seluruh field akan ditampilkan, tetapi di mobile mungkin hanya beberapa field saja dan jumlah barisnya pun terbatas.
Untuk menangani jenis permintaan yang berbeda tersebut, biasanya seorang backend developer membuat dua buah api yang berbeda, dimana satu api untuk di consume oleh website, sedangkan satunya lagi untuk mobile. Tidak ada yang salah dengan cara seperti ini, hanya saja jika aplikasi yang dibuat sudah sangat besar akan tetapi jumlah backend developer yang sedikit, maka imbasnya adalah aplikasi yang dibuat semakin lama untuk dirilis ke client karena harus membuat api tersendiri untuk masing-masing platform. Nah, jika hal semacam ini terjadi maka solusinya adalah dengan menggunakan GraphQL. Apa itu GraphQL? Kita bahas lebih detail.
GraphQL adalah bahasa query (query language) untuk sebuah API yang dibuat oleh Facebook. Bahasa query yang dimaksudkan disini bukanlah seperti query database yang sering anda jumpai di SQL maupun NoSQL. Query yang dimaksudkan disini adalah data dari API server backend, bisa dilakukan filterisasi langsung oleh client (web browser ataupun mobile) sesuai yang diinginkan oleh client melalui sebuah query yang dikirimkan ke server. Inilah yang merupakan kelebihan dari GraphQL jika dibandingkan dengan REST yang sering kita gunakan.
Supaya lebih mantap pemahaman mengenai GraphQL ini, maka kita akan langsung praktekkan bagaimana pengkodeannya di sisi backend. Disini saya akan mencontohkan membuat GraphQL server menggunakan bahasa golang dengan echo framework sebagai webserver dan gorm sebagai library database.
Membuat Database
Pertama kita buat sebuah database baru `nama terserah anda` kemudian buat tabel dengan script sql dibawah ini :
CREATE TABLE `level_user` (
`id_level` int(2) NOT NULL AUTO_INCREMENT,
`nama` varchar(100) NOT NULL,
PRIMARY KEY (`id_level`)
);
CREATE TABLE `users` (
`email` varchar(100) NOT NULL,
`nama` varchar(50) NOT NULL,
`no_handphone` varchar(15) DEFAULT NULL,
`alamat` text DEFAULT NULL,
`ktp` varchar(255) DEFAULT NULL,
`id_level` int(2) NOT NULL,
PRIMARY KEY (`email`) USING BTREE
);
INSERT INTO `level_user` (`id_level`, `nama`) VALUES
(1, 'Super Admin'),
(2, 'Admin');
INSERT INTO `users` (`email`, `nama`, `no_handphone`, `alamat`, `ktp`, `id_level`) VALUES
(fulan@gmail.com', 'Ahmad Zainuddin', '0853xxxxx', 'Jalan Kemana', '', 1),
('siapa@gmail.com', Zubayr, '08xxxx', 'Jalan - ', 'ktp.jpg', 2),
(saya@gmail.com', Zakaria, '08xxxx', 'Jalan - ', 'ktp.jpg', 2);
Setup Project Baru Golang
Buat sebuah project baru di golang dan jalankan perintah berikut di terminal :
go mod init mygraphql
Setelah itu tambahkan modul dibawah ini :
go get github.com/labstack/echo/v4
go get gorm.io/gorm
go get gorm.io/driver/mysql
go get github.com/graphql-go/graphql
go get github.com/graphql-go/handler
Didalam project yang sudah dibuat tadi, buat beberapa direktori baru dengan nama seperti dibawah ini :
Konfigurasi Database
Setelah selesai membuat project golang. Kemudian kita buat konfigurasi database didalam direktori config, buat sebuah file dengan nama database.go. Kemudian isi dengan code dibawah ini :
package config
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func ConnectDB() {
host := "localhost"
port := "3306"
dbname := "blogspot"
username := "root"
password := ""
dsn := username + ":" + password + "@tcp(" + host + ":" + port + ")/" + dbname + "?charset=utf8&parseTime=true&loc=Local"
var err error
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{SkipDefaultTransaction: true})
if err != nil {
panic("Cannot connect database")
}
DB.AutoMigrate()
}
Sesuaikan konfigurasi diatas dengan server MySQL yang berjalan di komputer anda.
Membuat Model
Di direktori model yang sudah dibuat tadi, buat 2 buah file baru yaitu `level.go` dan `users.go`. Isi masing-masing file dengan code dibawah ini :
level.go
package model
import (
"mygraphql/config"
"gorm.io/gorm"
)
type LevelUser struct {
IdLevel int `json:"id_level"`
Nama string `json:"nama"`
}
func (LevelUser) TableName() string {
return "level_user"
}
func GetLevel(idLevel int) ([]LevelUser, error) {
levels := new([]LevelUser)
var result *gorm.DB
if idLevel != 0 {
result = config.DB.Where("id_level = ? ", idLevel).Find(levels)
} else {
result = config.DB.Find(levels)
}
return *levels, result.Error
}
users.go
package model
import "mygraphql/config"
type Users struct {
Email string `json:"email" form:"email" gorm:"primaryKey"`
Nama string `json:"nama" form:"nama"`
NoHandphone string `json:"no_handphone" form:"no_handphone"`
Alamat string `json:"alamat" form:"alamat"`
Ktp string `json:"ktp" form:"ktp"`
}
func GetUsers(keywords string) ([]Users, error) {
var users []Users
result := config.DB.Where("email LIKE ? OR nama LIKE ?", "%"+keywords+"%", "%"+keywords+"%").Find(&users)
return users, result.Error
}
Kedua file diatas kita gunakan untuk mendefinisikan fungsi yang akan mengambil data dari database yang sudah kita buat sebelumnya. Untuk penjelasan mengenai ini lebih jelasnya bisa anda baca dipostingan saya mengenai Crud API di Golang Menggunakan Echo Framework dan GORM.
Setup GraphQL
Nah, sekarang kita masuk ke bagian inti dari postingan ini, yaitu berkaitan dengan graphql itu tadi. Di direktori `graphql` buat dua buah file baru yaitu `query.go` dan `handler.go`.
query.go
package graphql
import (
"mygraphql/model"
"github.com/graphql-go/graphql"
)
var (
level = graphql.NewObject(
graphql.ObjectConfig{
Name: "Level",
Fields: graphql.Fields{
"id_level": &graphql.Field{Type: graphql.ID},
"nama": &graphql.Field{Type: graphql.String},
},
Description: "Data level",
},
)
user = graphql.NewObject(
graphql.ObjectConfig{
Name: "User",
Fields: graphql.Fields{
"email": &graphql.Field{Type: graphql.ID},
"nama": &graphql.Field{Type: graphql.String},
"no_handphone": &graphql.Field{Type: graphql.String},
"alamat": &graphql.Field{Type: graphql.String},
"ktp": &graphql.Field{Type: graphql.String},
},
Description: "Data users",
},
)
)
func levelData() *graphql.Field {
return &graphql.Field{
Type: graphql.NewList(level),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
idLevel, _ := p.Args["id_level"].(int)
listLevel, err := model.GetLevel(idLevel)
return listLevel, err
},
Description: "List Level",
Args: graphql.FieldConfigArgument{
"id_level": &graphql.ArgumentConfig{Type: graphql.Int},
},
}
}
func usersData() *graphql.Field {
return &graphql.Field{
Type: graphql.NewList(user),
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
keywords, _ := p.Args["keywords"].(string)
listUser, err := model.GetUsers(keywords)
return listUser, err
},
Description: "List User",
Args: graphql.FieldConfigArgument{
"keywords": &graphql.ArgumentConfig{Type: graphql.String},
},
}
}
func newQuery() *graphql.Object {
return graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{
"users": usersData(),
"level": levelData(),
},
})
}
Penjelasan :
- Di file ini pertama kita deklarasikan terlebih dahulu variabel level dan user. Dimana di variabel tersebut diisi dengan fungsi NewObject dari graphql. Di variabel ini kita juga mendefinisikan field apa saja yang tersedia.
- Beralih ke fungsi levelData dan usersData dimana fungsi ini memiliki return type berupa struct *graphql.Field.
Type: graphql.NewList(ofType graphql.Type) kita masukkan variabel `level` ataupun `users` yang sudah dibuat sebelumnya.
Resolve: func(p graphql.ResolveParams) (interface{}, error) {}. Berisi data dari database tadi yang akan kita kembalikan ke client. Sebenarnya data yang di return disini bebas tidak hanya terbatas dari database saja, melainkan dari sumber lainnya pun boleh dilakukan.
Args: graphql.FieldConfigArgument{}. Jika data membutuhkan filter di client, maka kita bisa mendifinisikannya dibagian ini.
- Terakhir pada fungsi newQuery dimana pada fungsi ini kita jabarkan query yang bisa di panggil oleh client nantinya. Seperti yang terlihat di source code, kita mendaftarkan dua buah field data yang bisa di panggil oleh client. Yang pertama users dan yang kedua adalah level. Jadi dengan menggunakan field tersebutlah kita akan melakukan query data di client.
handler.go
package graphql
import (
"github.com/graphql-go/graphql"
"github.com/graphql-go/handler"
"gorm.io/gorm"
)
func NewHandler() (*handler.Handler, error) {
schema, err := graphql.NewSchema(
graphql.SchemaConfig{
Query: newQuery(),
},
)
if err != nil {
return nil, err
}
return handler.New(&handler.Config{
Schema: &schema,
Pretty: true,
GraphiQL: true,
}), nil
}
Penjelasan :
- Dibagian handler kita buat sebuah fungsi NewHandler, dimana fungsi ini nantinya akan terhubung ke web server atau router dari echo. Terlihat dari baris selanjutnya kita definisikan schema yang sudah dibuat tadi dimana isinya adalah fungsi newQuery yang sudah dibuat sebelumnya di file `query.go` tadi.
- Setelah selesai membuat file handler.go, selanjutnya yang terakhir adalah mendaftarkan handler tersebut ke router echo yang akan kita buat di file `server.go`. Isi dari file server.go adalah seperti dibawah ini :
server.go
package main
import (
"fmt"
"mygraphql/config"
"mygraphql/graphql"
"github.com/labstack/echo/v4"
)
func main() {
config.ConnectDB()
route := echo.New()
h, err := graphql.NewHandler()
if err != nil {
fmt.Println(err)
}
route.POST("/graphql", echo.WrapHandler(h))
route.Start(":9000")
}
type Response struct {
ErrorCode int `json:"error_code" form:"error_code"`
Message string `json:"message" form:"message"`
Data interface{} `json:"data"`
}
Jika anda mengikuti postingan saya mengenai
Rest API di Golang Menggunakan Echo Framework, disana sebagian besar sudah saya jelaskan mengenai penggunaan echo sebagai web server. Pada postingan ini yang perlu anda perhatikan hanya pada bagian :
h, err := graphql.NewHandler()
if err != nil {
fmt.Println(err)
}
route.POST("/graphql", echo.WrapHandler(h))
Di bagian ini kita melakukan pemanggilan fungsi
NewHandler yang sebelumnya sudah dibuat pada file `handler.go`. Kemudian pada baris akhir kita buat sebuah route dimana route tersebut adalah method post dengan url
/graphql.
Setelah selesai, terakhir kita akan melakukan uji coba terhadap api graphql yang sudah dibuat. Disini saya menggunakan postman, atau anda boleh menggunakan tools lain yang biasa anda gunakan. Berikut adalah hasil pengujiannya :
- Pengujian dengan memanggil seluruh field yang tersedia di api graphql
- Pengujian dengan menggunakan memasukkan field yang spesifik
- Pengujian dengan menggunakan filter dan field yang spesifik
Catatan :
Yang perlu anda perhatikan pada saat melakukan request data ke api graphql adalah query yang dikirim. Di postman sendiri sudah terdapat fitur graphql yang bisa anda gunakan. Output dari fitur graphql postman sendiri jika dilihat dalam bentuk curl contohnya adalah seperti dibawah ini :
curl --location --request POST 'http://localhost:9000/graphql' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"query{\r\n users (keywords:\"Ahmad\") {\r\n email\r\n nama\r\n no_handphone\r\n }\r\n level (id_level:1){\r\n id_level\r\n nama\r\n }\r\n}","variables":{}}'
Demikian postingan saya mengenai
Belajar GraphQL, Serta Contoh Implementasinya di Golang, Jika ada pertanyaan silahkan ditanyakan dikolom komentar dibawah. Source code dari project ini sendiri bisa diakses melalui github di
https://github.com/sardiabuzubayr/graphql-golang.
Demikian, semoga bermanfaat wassalamualaikum warahmatullah wabarakaatuh.