AdityaDees: Api

Hot

https://publishers.chitika.com/

Contact us for advertising.
Showing posts with label Api. Show all posts
Showing posts with label Api. Show all posts

10 January 2022

Ask Belajar GraphQL, Serta Contoh Implementasinya di Golang AdityaDees

06:33 0
https://adityadees.blogspot.com/2022/01/belajar-graphql-serta-contoh.html


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 :
setup project golang

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 :

  1. Pengujian dengan memanggil seluruh field yang tersedia di api graphql
  2. Pengujian dengan memanggil seluruh field yang tersedia di api graphql
  3. Pengujian dengan menggunakan memasukkan field yang spesifik
  4. Pengujian dengan menggunakan memasukkan field yang spesifik
  5. Pengujian dengan menggunakan filter dan field yang spesifik
  6. 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.
Read More

25 December 2021

Ask Crud API di Golang Menggunakan Echo Framework dan GORM AdityaDees

11:20 0
Crud API di Golang Menggunakan Echo Framework dan GORM

Bismillah...

Walhamdulillah, pada postingan sebelumnya kita sudah membahas mengenai Rest API di Golang Menggunakan Echo Framework. Pada postingan tersebut kita telah membahas tentang dasar-dasar pembuatan rest api di golang menggunakan framework yang diklaim lebih cepat dari Gin. Nah, postingan ini merupakan lanjutan dari postingan tersebut, jika anda belum membacanya sangat disarankan untuk mengikuti tutorial sebelumnya dari awal postingan.

Baiklah, di postingan ini kita akan mencoba membuat fungsi CRUD (Create, Read Update and Delete) sederhana menggunakan salah satu library ORM yang dipakai di golang yakni GORM. Untuk mengakses dokumentasi secara lengkap anda bisa menuju ke laman website resminya di https://gorm.io. Untuk studi kasus, kita akan membuat sebuah fungsi crud untuk tabel users. Dimana tabel tersebut berisi Email, Nama, No Handphone, Alamat dan KTP.

Buatlah sebuah database (nama database bebas) kemudian buat sebuah tabel dengan nama users. Untuk mempermudah anda bisa langsung copas script pembuatan tabel di bawah ini :
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,
PRIMARY KEY (email) USING BTREE
);


Setelah selesai membuat tabel, langsung buka project sebelumnya. Beberapa yang akan kita lakukan adalah sebagai berikut :
  1. Membuat Koneksi Database
  2. Sebelum membuat konesi database, tambahkan terlebih dahulu modul GORM didalam project anda. Caranya adalah dengan memasukkan perintah di terminal/command line dengan :
    go get gorm.io gorm.io/driver/mysql

    Setelah selesai, buat terlebih dahulu sebuah direktori misalnya dengan nama config. Kemudian didalam direktori tersebut buat sebuah file dengan nama database.go. Isi file tersebut dengan kode seperti 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()
    }

    Pada file database.go diatas, kita membuat sebuah variabel global dengan var DB *gorm.io. Variabel inilah yang nantinya akan kita gunakan untuk melakukan query ke database. Namun perlu diketahui bahwa cara penggunaan seperti ini tidak dianjurkan jika project yang dibuat dengan skala besar. Untuk project dengan skala besar disarankan untuk menerapkan clean arcitecture dimana koneksi database tidak di expose secara global, melainkan dibuat di masing-masing repository yang menyimpan database handler.

  3. Membuat Fungsi CRUD
  4. Selanjutnya kita akan membuat fungsi crud menggunakan koneksi database yang sudah dibuat sebelumnya. Supaya lebih teratur, maka fungsi crud tersebut akan saya buat terpisah dari file server.go. Untuk itu buat terlebih dahulu sebuah direktori baru lagi dengan nama model, kemudian buat sebuah file didalamnya dengan nama users.go. Didalam file ini kita akan memindahkan struct Users yang sebelumnya berada di file server.go ke file users.go. Isi dari file users.go adalah seperti dibawah ini :
    package model

    import "restapi/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 (user *Users) CreateUser() error {
        if err := config.DB.Create(user).Error; err != nil {
            return err
        }
        return nil
    }

    func (user *Users) UpdateUser(email string) error {
        if err := config.DB.Model(&Users{}).Where("email = ?", email).Updates(user).Error; err != nil {
            return err
        }
        return nil
    }

    func (user *Users) DeleteUser() error {
        if err := config.DB.Delete(user).Error; err != nil {
            return err
        }
        return nil
    }

    func GetOneByEmail(email string) (Users, error) {
        var user Users
        result := config.DB.Where("email = ?", email).First(&user)
        return user, result.Error
    }

    func GetAll(keywords string) ([]Users, error) {
        var users []Users
        result := config.DB.Where("email LIKE ? OR nama LIKE ?", "%"+keywords+"%", "%"+keywords+"%").Find(&users)

        return users, result.Error
    }

    Penjelasan :
    • CreateUser
    • Method ini adalah method yang kita gunakan untuk melakukan insert ke database. Pada method ini memiliki penerima berupa struct Users. Artinya method CreateUser melekat pada struct Users, dan bisa diakses langsung oleh object struct tersebut. Kemudian method ini juga memiliki nilai balik atau return value berupa interface error. Method yang digunakan untuk insert data ke database melalui gorm adalah method Create, seperti yang terlihat di baris kode config.DB.Create(user). config.DB sendiri merupakan variabel koneksi database yang sebelumnya sudah kita buat di file database.go.
    • UpdateUser
    • Method ini merupakan method yang kita gunakan untuk melakukan update data ke database. Sama seperti method CreateUser, method ini juga memiliki penerima berupa struct Users. Kemudian method ini memiliki parameter berupa primary key dari tabel users yakni email. Jadi nantinya kita akan melakukan update data users berdasarkan email yang dimiliki oleh user tersebut. Yang perlu diperhatikan adalah pada bagian config.DB.Model(&Users), ini menandakan bahwa kita akan melakukan sesuatu di model atau tabel users. Kemudian dilanjutkan dengan method Where(“email = ?”, email) dimana ini merupakan filter user yang memiliki email tersebut yang akan kita update data-nya, dan dilanjutkan dengan method Updates(user) dimana method inilah yang akan melakukan perintah eksekusi update ke database.
    • DeleteUser
    • Kemudian method terakhir yang akan kita buat adalah method UpdateUser. Dimana method ini yang digunakan untuk menghapus data yang ada pada tabel users. Letak eksekusi perintah delete terdapat pada bagian config.DB.Delete(user).
    • GetOneByEmail
    • Fungsi ini digunakan untuk mengambil data di tabel users berdasarkan email. Jadi seperti yang sudah terlihat di baris kode, bahwa fungsi ini menerima parameter berupa string email. Kemudian return dari fungsi ini adalah struct Users dan error. Jika anda belum familiar dengan fungsi yang seperti ini saya kira wajar, karena saya sendiri juga baru menemukan di golang bahwa sebuah method atau fungsi bisa memiliki return value lebih dari 1 object atau nilai. Method yang digunakan gorm untuk melakukan select sendiri adalah method First. Dimana method ini akan melakukan select dengan limit 1 baris.
    • GetAll
    • Kemudian fungsi terakhir adalah fungsi GetAll. Fungsi ini merupakan fungsi yang akan kita gunakan untuk menampilkan data secara keseluruhan atau lebih dari 1 baris. Pada method ini juga saya masukkan sebuah parameter keywords, dimana parameter tersebut digunakan untuk melakukan filter dari query yang kita jalankan. Untuk return sendiri, fungsi ini memiliki 2 buah return value yakni array dari struct Users dan error.

  5. Mengubah Router
  6. Setelah selesai membuat method dan fungsi diatas, selanjutnya adalah mengubah bagian router di file server.go yang telah kita buat sebelumnya dengan kode seperti dibawah ini :
    config.ConnectDB()
    route := echo.New()
    route.POST("user/create_user", func(c echo.Context) error {
    user := new(model.Users)
    c.Bind(user)
    contentType := c.Request().Header.Get("Content-type")
    if contentType == "application/json" {
    fmt.Println("Request dari json")
    } else if strings.Contains(contentType, "multipart/form-data") || contentType == "application/x-www-form-urlencoded" {
    file, err := c.FormFile("ktp")
    if err != nil {
    fmt.Println("Ktp kosong")
    } else {
    src, err := file.Open()
    if err != nil {
    return err
    }
    defer src.Close()
    dst, err := os.Create(file.Filename)
    if err != nil {
    return err
    }
    defer dst.Close()
    if _, err = io.Copy(dst, src); err != nil {
    return err
    }

    user.Ktp = file.Filename
    fmt.Println("Ada file, akan disimpan")
    }
    }
    response := new(Response)
    if user.CreateUser() != nil { // method create user
    response.ErrorCode = 10
    response.Message = "Gagal create data user"
    } else {
    response.ErrorCode = 0
    response.Message = "Sukses create data user"
    response.Data = *user
    }
    return c.JSON(http.StatusOK, response)
    })

    route.PUT("user/update_user/:email", func(c echo.Context) error {
    user := new(model.Users)
    c.Bind(user)
    response := new(Response)
    if user.UpdateUser(c.Param("email")) != nil { // method update user
    response.ErrorCode = 10
    response.Message = "Gagal update data user"
    } else {
    response.ErrorCode = 0
    response.Message = "Sukses update data user"
    response.Data = *user
    }
    return c.JSON(http.StatusOK, response)
    })

    route.DELETE("user/delete_user/:email", func(c echo.Context) error {
    user, _ := model.GetOneByEmail(c.Param("email")) // method get by email
    response := new(Response)

    if user.DeleteUser() != nil { // method update user
    response.ErrorCode = 10
    response.Message = "Gagal menghapus data user"
    } else {
    response.ErrorCode = 0
    response.Message = "Sukses menghapus data user"
    }
    return c.JSON(http.StatusOK, response)
    })

    route.GET("user/search_user", func(c echo.Context) error {
    response := new(Response)
    users, err := model.GetAll(c.QueryParam("keywords")) // method get all
    if err != nil {
    response.ErrorCode = 10
    response.Message = "Gagal melihat data user"
    } else {
    response.ErrorCode = 0
    response.Message = "Sukses melihat data user"
    response.Data = users
    }
    return c.JSON(http.StatusOK, response)
    })

    route.Start(":9000")

    Di baris kode diatas, saya membuat sebuah struct Response. Isinya adalah sebagai berikut :
    type Response struct {
        ErrorCode int         `json:"error_code" form:"error_code"`
        Message   string      `json:"message" form:"message"`
        Data      interface{} `json:"data"`
    }

    Pada kode diatas, yang perlu anda perhatikan adalah pada bagian yang saya beri tanda komentar //. Pada bagian tersebutlah merupakan method dan fungsi yang kita panggil dari file users.go.
    Setelah selesai seluruhnya, sekarang kita lakukan pengujian terhadap api yang sudah dibuat menggunakan postman.
    1. Endpoint (user/create_user) POST
    2. Pengujian Rest Api Golang dengan Request multipart/form-data
      Pengujian menggunakan Content-Type : multipart/form-data
      Pengujian Rest Api Golang dengan Request application/json
      Pengujian menggunakan Content-Type : application/json

    3. Endpoint (user/update_user/:email) PUT
    4. Pengujian Rest Api Golang method PUT

    5. Endpoint (user/delete_user) DELETE
    6. Pengujian Rest Api Golang method DELETE

    7. Endpoint (user/search_user) GET
    8. Pengujian Rest Api Golang method GET tanpa parameter
      Request tanpa query params
      Pengujian Rest Api Golang method GET dengan query parameter
      Request dengan query params

Demikian tutorial Crud API di Golang Menggunakan Echo Framework dan GORM
Read More

20 December 2021

Ask Rest API di Golang Menggunakan Echo Framework AdityaDees

18:57 0
Rest API di Golang Menggunakan Echo Framework
Bismillah...
Perkembangan teknologi dewasa ini sangatlah cepat, dulu kita sering menggunakan Soap sebagai protokol untuk pertukaran data lintas platform, akan tetapi seiiring berjalannya waktu, protokol tersebut pelan-pelan mulai ditinggalkan karena kemunculan protokol baru untuk pertukaran data yakni Rest API yang menawarkan kecepatan yang lebih baik dari pendahulunya.

Pada postingan ini saya akan membuat sebuah contoh penggunaan rest api dengan menggunakan bahasa golang, khususnya dengan menggunakan framework echo. Mengapa saya menggunakan golang untuk membuat rest api ini? Jawabannya karena saya sedang mempelajari bahasa golang, hhhee. Saya tertarik mempelajari bahasa golang karena dari segi kecepatannya sangat luar biasa cepat jika dibandingkan dengan bahasa lain. Sebelumnya saya pernah membandingkan rest api golang dengan php (framework Lumen). Hasilnya sangat beda jauh dari segi kecepatan. Pada simple case, lumen memerlukan 100 - 200 ms untuk merespon sebuah permintaan dan mengembalikan dalam bentuk json. Akan tetapi golang hanya memerlukan waktu 3 - 10 ms untuk untuk merespon permintaan tersebut. Kemudian dengan menggunakan J-Meter untuk test permintaan secara concurent atau request secara bersamaan (1000 - 2000 request secara bersamaan), hasil yang didapat semakin jauh berbeda. Lumen memerlukan 6000 an ms atau 6 second keatas, akan tetapi golang masih dibawah 1 second. Luarrr biasa, hal inilah yang mendorong saya untuk mempelajari lebih lanjut mengenai golang dan tentu harapan kedepannya adalah menggunakan golang ini sebagai bahasa utama saya disisi backend.

Didalam bahasa golang sendiri, secara default sudah menyediakan sebuah package net/http. Didalam package tersebut sudah tersedia untuk  web server, routing, templating dan lainnya. Akan tetapi untuk lebih mempermudah saya menggunakan framework tambahan yaitu echo framework. Dokumentasi dari framework ini secara lengkap bisa diakses di https://echo.labstack.com. Echo sendiri mengklaim bahwa dirinya lebih baik dari Gin framework yang juga merupakan framework untuk develop website di go. Ini bisa dilihat dari github echo framework di https://github.com/labstack/echo.

Baiklah langsung saja, ditulisan ini saya akan memasukkan beberapa hal yang umum kita gunakan di rest api seperti POST, PUT, GET dan DELETE. Disini saya tidak memasukkan data yang dikirim kedalam database. Akan tetapi hanya sekedar mengirim dan membaca data secara statis saja. InsyaAllah pada kesempatan lain saya akan membuat rest api ini lengkap dengan database, yassarallahu li.

Disini saya berasumsi anda sudah menginstal golang, jika belum bisa menginstal langsung dari website resmi golang di https://go.dev . Baiklah jika sudah terinstall di laptop atau pc anda kita akan langsung mulai :
  1. Buat sebuah direktori/folder beri saja namanya restapi misalnya
  2. Kemudian buka terminal atau command line anda dan masukkan perintah go mod init restapi
  3. go mod init restapi
    Dari perintah di atas akan menghasilkan sebuah file go.mod. Didalam file ini seluruh modul yang akan kita gunakan akan di definisikan di file tersebut.
  4. Setelah itu tambahkan modul echo framework dengan perintah :
  5. go get github.com/labstack/echo/v4
    Perintah diatas kita gunakan untuk menambahkan sebuah modul baru yakni modul echo framework tadi.
  6. Selanjutnya buka editor kesayangan anda, disini saya menggunakan Visual Studio Code. Didalam project directory anda, buat sebuah file dengan nama server.go.
  7. Didalam file server.go kita akan membuat sebuah struct yang memuat entitas user seperti email, nama, no_handphone, alamat dan ktp. Berikut adalah isi dari struct tersebut :
  8. type Users struct {
        Email       string `json:"email" form:"email"`
        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"`
    }
    Pada struct diatas, kita sudah mendefinisikan entitas user. Yang perlu anda perhatikan adalah pada keyword json dan form. Keyword diatas berarti kita menentukan nama variabel yang digunakan untuk pertukaran data di rest api nantinya. Dimana keyword json ini akan terbaca pada saat data yang kita kirimkan dengan Content-Type application/json. Kemudian form akan terbaca jika Content-Type yang dikirim berupa multipart/form-data atau application/x-www-form-urlencoded.
  9. Kemudian di file yang sama, kita akan menginisialisasi fungsi dari framework echo yang akan kita gunakan sebagai web server sekaligus routing dari api yang kita buat. Tambahkan baris kode dibawah ini :
  10. func main() {
    route := echo.New()
    route.POST("user/create_user", func(c echo.Context) error {

    })
    route.PUT("user/update_user/:email", func(c echo.Context) error {

    })
    route.DELETE("user/delete_user/:email", func(c echo.Context) error {

    })
    route.GET("user/search_user", func(c echo.Context) error {

    })
    route.Start(":9000")
    }
    Pada source code diatas di function main, kita deklarasikan sebuah variabel route dengan inisialisasi function echo.New(). Function tersebut merupakan instance dari framework echo. Kemudian dilanjutkan kita definisikan method-method seperti POST, PUT, DELETE dan GET yang selanjutnya akan kita tulis kode didalamnya satu persatu.
  11. Selanjutnya dibagian method POST kita akan definisikan bahwa method tersebut akan menerima request dalam bentuk Content-Type application/json ataupun multipart/form-data. Sehingga baris kode pada method tersebut menjadi seperti berikut ini :
  12. 	user := new(Users)
            c.Bind(user)
            contentType := c.Request().Header.Get("Content-type")
            if contentType == "application/json" {
                fmt.Println("Request dari json")
            } else if strings.Contains(contentType, "multipart/form-data") || contentType == "application/x-www-form-urlencoded" {
                file, err := c.FormFile("ktp")
                if err != nil {
                    fmt.Println("Ktp kosong")
                } else {
                    src, err := file.Open()
                    if err != nil {
                        return err
                    }
                    defer src.Close()
                    dst, err := os.Create(file.Filename)
                    if err != nil {
                        return err
                    }
                    defer dst.Close()
                    if _, err = io.Copy(dst, src); err != nil {
                        return err
                    }

                    user.Ktp = file.Filename
                    fmt.Println("Ada file, akan disimpan")
                }
            }
            response := struct {
                Message string
                Data    Users
            }{
                Message: "Sukses melakukan penambahan data",
                Data:    *user,
            }
            return c.JSON(http.StatusOK, response)
    Penjelasan :
    • user := new(Users). Keyword new merupakan instance dari sebuah struct dalam hal ini Users. Variabel user menampung data pointer bertipe struct User.
      c.Bind(user) . Merupakan fungsi yang disediakan oleh framework echo untuk melakukan binding field yang dikirim oleh client kedalam sebuah interface.
      Cara diatas juga bisa diganti dengan kode seperti ini :
      var user Users
      c.Bind(&user)
    • contentType := c.Request().Header.Get("Content-type") digunakan untuk mengetahui jenis Content-Type apa yang dikirim oleh client.
    • Pada bagian selanjutnya hanya berupa pengecekan apa jenis content-type tadi. Kemudian khusus bagian :
      else if strings.Contains(contentType, "multipart/form-data") || contentType == "application/x-www-form-urlencoded" { …. } didalam blok kode tersebut saya mengecek apakah ada file yang dikirim, karena untuk Content-Type json tidak bisa mengirim data dalam bentuk file. Jika ada file yang dikirim, maka akan saya simpan file tersebut. Selanjutnya nama file yang dikirim tadi akan saya masukkan ke variabel ktp.
    • return c.JSON(http.StatusOK, user) merupakan response yang akan dikembalikan ke client yakni dalam bentuk json dari struct user tadi.
      http.StatusOK merupakan response code 200 yang dikembalikan ke client.
  13. Beralih ke method selanjutnya yakni method PUT. Pada method PUT ini umumnya digunakan untuk pengupdatan/perubahan data. Pada method ini masukkan kode berikut :
  14. 	user := new(Users)
            c.Bind(user)
            user.Email = c.Param("email")
            // do something here ....
            response := struct {
                Message string
                Data    Users
            }{
                Message: "Sukses mengupdate data",
                Data:    *user,
            }
            return c.JSON(http.StatusOK, response)
    Penjelasan :
    • c.Param(“email”) digunakan untuk mengambil parameter dari url. Dalam hal ini parameter yang ada di method PUT tersebut adalah email.
  15. Kemudian dibagian method DELETE. Method ini digunakan untuk melakukan penghapusan data. Sama seperti method PUT, biasanya method DELETE juga menyertakan sebuah ID untuk identifikasi data mana yang akan dihapus. Isi dari method DELETE seperti berikut ini :
  16. 	user := new(Users)
            user.Email = c.Param("email")
            // do something here ....
            response := struct {
                Message string
                ID      string
            }{
                Message: "Sukses menghapus data",
                ID:      user.Email,
            }
            return c.JSON(http.StatusOK, response)
  17. Terakhir adalah method GET. Method ini biasanya digunakan untuk melakukan request data ke server. Dan biasanya method ini juga mengirimkan sebuah query parameter. Berikut adalah contohnya :
  18. 	user := new(Users)
            user.Email = c.QueryParam("keywords")
            user.Nama = "AdityaDS"
            user.ALamat = "Jalan Jalan"
            user.Ktp = "file.jpg"
            // do something here ....
            response := struct {
                Message string
                Data    Users
            }{
                Message: "Sukses melihat data",
                Data:    *user,
            }
            return c.JSON(http.StatusOK, response)
  19. Setelah selesai menulis seluruhnya. Saatnya melakukan pengujian menggunakan Postman. Terlebih dahulu, jalankan server anda dengan membuka command line lalu masukkan perintah go run server.go

Hasil pengujian rest api adalah sebagai berikut :

  1. Endpoint (user/create_user) POST
  2. Endpoint (user/create_user) POST json
    - Diatas adalah contoh request post method dengan data yang dikirim dalam bentuk json (Content-Type : application/json). Kemudian jika menggunakan Content-Type : multipart/form atau application/x-www-form-urlencoded, maka request-nya adalah seperti gambar dibawah ini :
    Endpoint (user/create_user) POST form
    - Diatas pada field ktp diisi terisi sebuah file yang dikirim. Untuk pengiriman file sendiri, tidak bisa dilakukan dengan Content-Type : application/json.
  3. Endpoint (user/update_user/:email) PUT
  4. Endpoint (user/update_user/:email) PUT
    - Terlihat di endpoint method diatas terdapat parameter email fulan@gmail.com. Parameter inilah yang dibaca go dengan kode c.Param(“email”).
  5. Endpoint (user/delete_user/:email) DELETE
  6. Endpoint (user/delete_user/:email) DELETE
  7. Endpoint (user/search_user) GET
  8. Endpoint (user/search_user) GET
Demikian, hasil yang didapat dari pengujian api menggunakan postman. Untuk source code full dari aplikasi diatas adalah sebagai berikut :
package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "strings"

    "github.com/labstack/echo/v4"
)

type Users struct {
    Email       string `json:"email" form:"email"`
    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 main() {
    route := echo.New()
    route.POST("user/create_user", func(c echo.Context) error {
        user := new(Users)
        c.Bind(user)
        contentType := c.Request().Header.Get("Content-type")
        if contentType == "application/json" {
            fmt.Println("Request dari json")
        } else if strings.Contains(contentType, "multipart/form-data") || contentType == "application/x-www-form-urlencoded" {
            file, err := c.FormFile("ktp")
            if err != nil {
                fmt.Println("Ktp kosong")
            } else {
                src, err := file.Open()
                if err != nil {
                    return err
                }
                defer src.Close()
                dst, err := os.Create(file.Filename)
                if err != nil {
                    return err
                }
                defer dst.Close()
                if _, err = io.Copy(dst, src); err != nil {
                    return err
                }

                user.Ktp = file.Filename
                fmt.Println("Ada file, akan disimpan")
            }
        }
        response := struct {
            Message string
            Data    Users
        }{
            Message: "Sukses melakukan penambahan data",
            Data:    *user,
        }
        return c.JSON(http.StatusOK, response)
    })

    route.PUT("user/update_user/:email", func(c echo.Context) error {
        user := new(Users)
        c.Bind(user)
        user.Email = c.Param("email")
        // do something here ....
        response := struct {
            Message string
            Data    Users
        }{
            Message: "Sukses mengupdate data",
            Data:    *user,
        }
        return c.JSON(http.StatusOK, response)
    })

    route.DELETE("user/delete_user/:email", func(c echo.Context) error {
        user := new(Users)
        user.Email = c.Param("email")
        // do something here ....
        response := struct {
            Message string
            ID      string
        }{
            Message: "Sukses menghapus data",
            ID:      user.Email,
        }
        return c.JSON(http.StatusOK, response)
    })

    route.GET("user/search_user", func(c echo.Context) error {
        user := new(Users)
        user.Email = c.QueryParam("keywords")
        user.Nama = "AdityaDS"
        user.ALamat = "Jalan Jalan"
        user.Ktp = "file.jpg"
        // do something here ....
        response := struct {
            Message string
            Data    Users
        }{
            Message: "Sukses melihat data",
            Data:    *user,
        }
        return c.JSON(http.StatusOK, response)
    })

    route.Start(":9000")
}

Untuk tutorial dasar Rest API di Golang Menggunakan Echo Framework cukup sampai disini. 
Read More

13 December 2021

Ask Cara Deploy Laravel, Codeigniter dan Framework PHP Lainnya di Docker AdityaDees

22:48 0
Cara Deploy Laravel, Codeigniter dan Framework PHP Lainnya di Docker
Bismillah…
Beberapa tahun belakangan kita tentu sering mendengar istilah docker dan kontainerisasi. Nah pada tulisan saya kali ini kita akan langsung mempraktekkan bagaimana cara men-deploy atau memasang website yang sebelumnya sudah kita buat kedalam sebuah container. Sebelum memulai, ada baiknya kita mengerti terlebih dahulu apa itu container dan apa itu docker.
  • Container
  • Container yang dimaksud disini merupakan wadah yang digunakan untuk menempatkan seluruh kebutuhan aplikasi baik itu web server, database ataupun kebutuhan lainnya yang dibutuhkan oleh aplikasi kita tadi supaya bisa berjalan layaknya di komputer lokal.

  • Docker
  • Docker merupakan salah satu platform yang bisa digunakan sebagai container/wadah untuk menempatkan seluruh kebutuhan software yang kita butuhkan. Docker seperti halnya sebuah VM yang berjalan di mesin virtual, hanya saja docker lebih ringan daripada VM yang membutuhkan resource lebih besar daripada docker.

    Dengan menggunakan docker, kita bebas memilih versi bahasa pemrograman, database, library dan software lainnya tanpa khawatir terjadi bentrok antara 1 aplikasi dengan aplikasi lainnya, karena docker bersifat isolate dimana konfigurasi sebuah project anda tidak akan mengganggu konfigurasi dan kebutuhan project yang lain.

    Misalnya saya memiliki 2 buah project, dimana project 1 menggunakan php versi 7.4 sedangkan project kedua menggunakan php versi 8.0 maka antara 2 project tersebut tidak mungkin terjadi bentok karena masing-masing project sudah memiliki container dan konfigurasi terisolasi masing-masing.

Nah, setelah mengetahui pengertian diatas, sekarang kita akan memulai untuk proses deploy. Disini saya akan men-deploy sebuah project aplikasi web dengan bahasa pemrograman php dimana aplikasi ini menggunakan nginx sebagai web server dan MySQL sebagai database. Kita akan lakukan konfigurasi di file tersendiri untuk masing-masing tools tersebut. Untuk php dan nginx disini saya menggunakan varian alpine linux, karena image docker dari alpine ini paling ringan dan paling kecil untuk ukuran filenya dibandingkan dengan image lainnya.

Berikut adalah langkah-langkah untuk melakukan deploy website ke docker :
  1. Didalam project website anda, buat sebuah direktori/folder bernama docker-config kemudian tambahkan lagi didalamnya direktori mysql, nginx dan php seperti berikut ini:
  2. Deploy php ke docker
  3. Didalam direktori mysql, buat sebuah direktori baru dengan nama db. Kemudian tempatkan di dalam direktori db ini database dari website yang anda buat sebelumnya.
  4. Selanjutnya beralih ke direktori nginx, buat sebuah file docker dengan nama web.dockerfile. Kemudian masukkan konfigurasi seperti dibawah ini didalam file tersebut :
  5. FROM nginx:1.21.4-alpine

    ADD ./docker-config/nginx/vhost.conf /etc/nginx/conf.d/default.conf
  6. Masih di direktori yang sama, tambahkan lagi sebuah file vhost.conf, dimana file ini berisi konfigurasi untuk nginx.
  7. server {
    listen 80;
    index index.php index.html;
    root /var/www/public/public;

    location / {
    try_files $uri /index.php?$args;
    }

    location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass app:9000;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    }
  8. Beralih ke direktori php yang sudah dibuat sebelumnya, buat sebuah file php.dockerfile, lalu masukkan konfigurasi seperti dibawah ini :
  9. FROM php:8.0.5-fpm-alpine

    RUN docker-php-ext-install mysqli pdo pdo_mysql && docker-php-ext-enable pdo_mysql
  10. Selanjutnya kembali ke direktori awal project. Lalu buat sebuah file docker-compose.yml. Didalam file inilah kita akan mendeklarasikan seluruh kebutuhan guna menjalankan website kita tadi.
  11. version: '3'
    services:
    web:
    build:
    context: ./
    dockerfile: ./docker-config/nginx/web.dockerfile
    container_name: inventory-webserver
    volumes:
    - ./:/var/www/public
    ports:
    - "8080:80"
    networks:
    - app-network

    app:
    build:
    context: ./
    dockerfile: ./docker-config/php/php.dockerfile
    container_name: inventory
    volumes:
    - ./:/var/www/public
    networks:
    - app-network
    links:
    - database
    depends_on:
    - database

    database:
    image: mariadb
    container_name: inventory_database
    restart: unless-stopped
    tty: true
    ports:
    - "3307:3306"
    environment:
    MYSQL_DATABASE: inventory_sample
    MYSQL_ROOT_PASSWORD: 12345
    SERVICE_NAME: mysql
    SERVICE_TAGS: dev
    volumes:
    - dbdata:/var/lib/mysql/
    - ./docker-config/mysql/db:/docker-entrypoint-initdb.d
    networks:
    - app-network

    networks:
    app-network:
    driver: bridge
    volumes:
    dbdata:
    driver: local
  12. Setelah seluruh file tersebut dibuat, jalankan docker-compose di terminal/command line anda dengan perintah :
  13. docker-compose up
  14. Tunggu hingga proses selesai, dan jalankan website anda di http://localhost:8080
Demikianlah tutorial cara deploy laravel, codeigniter dan framework PHP lainnya di docker. 
Read More

https://payclick.com/

Contact us for advertising.