Sejauh ini setiap handler membangun response JSON-nya sendiri-sendiri lewat fiber.Map{...} berulang kali. Formatnya konsisten secara kebetulan, bukan by design — kalau lupa satu field saja, respons antar endpoint bisa jadi tidak seragam. Di part ini kita rapikan dengan helper response reusable, sekaligus tambahkan penanganan error terpusat.
Helper Response
Buat response/response.go:
package response
import "github.com/gofiber/fiber/v2"
func Success(c *fiber.Ctx, status int, message string, data interface{}) error {
return c.Status(status).JSON(fiber.Map{
"message": message,
"data": data,
})
}
func Error(c *fiber.Ctx, status int, message string) error {
return c.Status(status).JSON(fiber.Map{
"message": message,
})
}
func ValidationError(c *fiber.Ctx, errors map[string]string) error {
return c.Status(fiber.StatusUnprocessableEntity).JSON(fiber.Map{
"message": "validasi gagal",
"errors": errors,
})
}
Refactor PostHandler dan AuthHandler supaya semua respons lewat tiga fungsi ini. Sebagai contoh, PostHandler.Show yang sebelumnya:
func (h *PostHandler) Show(c *fiber.Ctx) error {
var post models.Post
id := c.Params("id")
if err := h.DB.First(&post, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
"message": "post tidak ditemukan",
})
}
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"message": "gagal mengambil data post",
})
}
return c.JSON(fiber.Map{
"data": post,
})
}
menjadi lebih ringkas:
func (h *PostHandler) Show(c *fiber.Ctx) error {
var post models.Post
id := c.Params("id")
if err := h.DB.First(&post, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return response.Error(c, fiber.StatusNotFound, "post tidak ditemukan")
}
return response.Error(c, fiber.StatusInternalServerError, "gagal mengambil data post")
}
return response.Success(c, fiber.StatusOK, "berhasil mengambil data post", post)
}
Pola yang sama diterapkan ke semua method di PostHandler dan AuthHandler — termasuk mengganti manual fiber.Map{"errors": ...} di validation jadi response.ValidationError(c, validation.FormatErrors(err)).
Error Handler Terpusat
Secara default, kalau terjadi panic di dalam handler (misalnya nil pointer dereference), Fiber akan mengirim response HTML generik dan (tergantung skenario) bisa membuat server berhenti merespons. Kita tidak mau itu — API harus selalu balas JSON, bahkan saat terjadi error tak terduga.
Fiber punya dua bagian untuk ini: ErrorHandler di config (menangani error yang di-return dari handler) dan middleware recover (menangkap panic supaya tidak menjatuhkan seluruh proses). Update main.go:
app := fiber.New(fiber.Config{
ErrorHandler: func(c *fiber.Ctx, err error) error {
code := fiber.StatusInternalServerError
message := "terjadi kesalahan pada server"
var fiberErr *fiber.Error
if errors.As(err, &fiberErr) {
code = fiberErr.Code
message = fiberErr.Message
}
return response.Error(c, code, message)
},
})
app.Use(recover.New())
recover.New() adalah middleware bawaan Fiber (github.com/gofiber/fiber/v2/middleware/recover) yang menangkap panic di handler manapun, mengubahnya jadi error biasa, lalu meneruskannya ke ErrorHandler di atas — jadi walaupun ada bug yang menyebabkan panic, server tetap hidup dan client tetap dapat response JSON yang rapi (500 dengan pesan generik), bukan koneksi putus begitu saja.
ErrorHandler juga otomatis menangani kasus route yang tidak ditemukan (404) — Fiber membungkusnya sebagai *fiber.Error dengan Code: 404, yang oleh handler kita di atas ikut diformat ulang jadi JSON konsisten, bukan format bawaan Fiber.
Testing
Jalankan server, lalu coba akses route yang tidak ada:
curl -i http://127.0.0.1:3000/api/v1/tidak-ada
Responnya sekarang konsisten dengan format API kita:
{"message":"Cannot GET /api/v1/tidak-ada"}
Semua endpoint yang sudah kita buat sebelumnya (Post CRUD, auth) tetap berfungsi sama seperti sebelumnya — hanya format kodenya yang lebih rapi dan konsisten, plus sekarang tahan terhadap panic tak terduga.
Response kita sekarang seragam di seluruh API. Di part berikutnya kita tambahkan pagination dan search ke endpoint Index Post, supaya tidak semua data ditarik sekaligus saat datanya sudah banyak.
Bagian dari Series: GoFiber Dasar - Belajar Fundamental Lewat REST API Blog
Belajar konsep-konsep dasar GoFiber (routing, handler, GORM, MySQL, JWT auth) dengan membangun REST API blog sederhana dari nol - lengkap dengan auten...
Lihat Series Lengkap