Setelah di part sebelumnya kita berhasil membuat endpoint GET untuk list dan detail post, di part ini kita akan lanjut membuat endpoint untuk Create (Store), Update, dan Delete data post — lengkap dengan validasi input sebelum data disimpan ke database.
Menambahkan Method Store, Update, dan Destroy di PostController
Buka file app/http/controllers/post_controller.go, kemudian tambahkan method Store:
func (r *PostController) Store(ctx http.Context) http.Response {
validator, err := ctx.Request().Validate(map[string]string{
"title": "required|max_len:255",
"body": "required",
})
if err != nil {
return ctx.Response().Json(http.StatusInternalServerError, http.Json{
"error": err.Error(),
})
}
if validator.Fails() {
return ctx.Response().Json(http.StatusUnprocessableEntity, http.Json{
"errors": validator.Errors().All(),
})
}
post := models.Post{
Title: ctx.Request().Input("title"),
Body: ctx.Request().Input("body"),
Status: "DRAFT",
}
if err := facades.Orm().Query().Create(&post); err != nil {
return ctx.Response().Json(http.StatusBadRequest, http.Json{
"error": err.Error(),
})
}
return ctx.Response().Json(http.StatusCreated, post)
}
Perhatikan di method Store ini kita menggunakan ctx.Request().Validate() untuk memvalidasi input sebelum data disimpan. Rule required memastikan field wajib diisi, sedangkan max_len:255 membatasi panjang karakter title. Kalau validasi gagal, endpoint akan merespon dengan status 422 Unprocessable Entity beserta detail error-nya. Post baru yang dibuat otomatis diberi status DRAFT.
Selanjutnya method Update:
func (r *PostController) Update(ctx http.Context) http.Response {
id := ctx.Request().Route("id")
var post models.Post
if err := facades.Orm().Query().Where("id", id).First(&post); err != nil {
return ctx.Response().Json(http.StatusNotFound, http.Json{
"error": "Post not found",
})
}
validator, err := ctx.Request().Validate(map[string]string{
"title": "required|max_len:255",
"body": "required",
})
if err != nil {
return ctx.Response().Json(http.StatusInternalServerError, http.Json{
"error": err.Error(),
})
}
if validator.Fails() {
return ctx.Response().Json(http.StatusUnprocessableEntity, http.Json{
"errors": validator.Errors().All(),
})
}
post.Title = ctx.Request().Input("title")
post.Body = ctx.Request().Input("body")
if ctx.Request().Input("status") != "" {
post.Status = ctx.Request().Input("status")
}
if err := facades.Orm().Query().Save(&post); err != nil {
return ctx.Response().Json(http.StatusBadRequest, http.Json{
"error": err.Error(),
})
}
return ctx.Response().Json(http.StatusOK, post)
}
Di method ini kita cari dulu post berdasarkan id dari parameter route. Kalau tidak ketemu, langsung return 404 Not Found. Field status sifatnya opsional — kalau dikirim, statusnya akan diupdate (misalnya dari DRAFT ke ACTIVE).
Terakhir method Destroy:
func (r *PostController) Destroy(ctx http.Context) http.Response {
id := ctx.Request().Route("id")
var post models.Post
if err := facades.Orm().Query().Where("id", id).First(&post); err != nil {
return ctx.Response().Json(http.StatusNotFound, http.Json{
"error": "Post not found",
})
}
if _, err := facades.Orm().Query().Delete(&post); err != nil {
return ctx.Response().Json(http.StatusBadRequest, http.Json{
"error": err.Error(),
})
}
return ctx.Response().Json(http.StatusOK, http.Json{"success": true})
}
Karena model Post menggunakan orm.Model yang sudah include SoftDeletes (lihat kembali migration di Part 4), method Delete di sini sebenarnya melakukan soft delete — data tidak benar-benar hilang dari database, hanya ditandai terhapus lewat kolom deleted_at.
Menambahkan Route
Daftarkan ketiga endpoint baru ini di routes/api.go:
package routes
import (
"github.com/goravel/framework/facades"
"myblog/app/http/controllers"
)
func Api() {
userController := controllers.NewUserController()
facades.Route().Get("/users/{id}", userController.Show)
postContoller := controllers.NewPostController()
facades.Route().Get("/posts", postContoller.Index)
facades.Route().Get("/posts/{id}", postContoller.Show)
facades.Route().Post("/posts", postContoller.Store)
facades.Route().Put("/posts/{id}", postContoller.Update)
facades.Route().Delete("/posts/{id}", postContoller.Destroy)
}
Sampai di part ini, endpoint create/update/delete masih bisa diakses oleh siapa saja tanpa autentikasi. Ini akan kita perbaiki nanti setelah kita bahas Register, Login, dan JWT Token di part berikutnya.
Testing Endpoint
Jalankan ulang server (go run .), lalu coba endpoint berikut menggunakan Postman atau REST client lainnya:
POST /postsdengan body{"title": "...", "body": "..."}→ membuat post baruPUT /posts/{id}dengan body yang sama → update postDELETE /posts/{id}→ hapus post (soft delete)
Coba juga kirim request tanpa title atau body untuk melihat response validasi error-nya.
Video Tutorial
Tutorial dalam bentuk video dapat di akses di channel Youtube IndoKoding: https://www.youtube.com/watch?v=YoCsr7fGuiE
Bagian dari Series: Seri Tutorial Belajar Framework Goravel Rest API untuk Pemula
Overview Seri ini membahas cara membangun REST API menggunakan Goravel, framework web berbasis Golang yang terinspirasi dari Laravel. Materi mencakup...
Lihat Series Lengkap