๐ฌ Golang Ticket Booking System from Scratch โ No Framework (Part 4)
๐ Booking Controller & HTTP Handler (main.go)
Setelah kita berhasil membangun logic utama BookingService dan mengamankan sistem dari race condition di Part 3, sekarang saatnya membuat sistem ini bisa diakses melalui HTTP API. Di part ini, kita akan membahas:
* Pembuatan Booking Controller untuk menerima HTTP request
* Penyusunan struct JSON untuk request dan response
* Konfigurasi HTTP server menggunakan httprouter
* Contoh testing via Postman atau Curl
๐ง Struktur Proyek Saat Ini
ticket-booking/
โโโ app/
โ โโโ database.go # Koneksi database
โโโ controller/
โ โโโ booking_controller.go # HTTP handler untuk booking
โโโ main.go # Entry point aplikasi
โโโ repository/
โ โโโ booking_repository.go # Akses query ke DB
โโโ request/
โ โโโ booking_request.go # Struct input request
โโโ response/
โ โโโ api_response.go # Struct response standar
โโโ service/
โ โโโ booking_service.go # Logika pemesanan kursi
โโโ go.mod1. Membuat Booking Controller
๐ File: controller/booking_controller.go
package controller
import (
"context"
"encoding/json"
"net/http"
"github.com/fardannozami/ticket-booking/helper"
"github.com/fardannozami/ticket-booking/request"
"github.com/fardannozami/ticket-booking/response"
"github.com/fardannozami/ticket-booking/service"
"github.com/julienschmidt/httprouter"
)
type BookingController interface {
BookSeat(writer http.ResponseWriter, req *http.Request, params httprouter.Params)
}
type bookingController struct {
bookingService service.BookingService
}
func NewBookingController(bookingService service.BookingService) BookingController {
return &bookingController{
bookingService: bookingService,
}
}
func (c *bookingController) BookSeat(writer http.ResponseWriter, req *http.Request, params httprouter.Params) {
var bookCreateRequest request.BookingCreateRequest
decoder := json.NewDecoder(req.Body)
err := decoder.Decode(&bookCreateRequest)
helper.PanicIfError(err)
_, err = c.bookingService.BookSeat(context.Background(), bookCreateRequest.EventId, bookCreateRequest.SeatId, bookCreateRequest.UserId)
helper.PanicIfError(err)
apiResponse := response.ApiResponse{
Code: http.StatusCreated,
Message: "created",
}
writer.Header().Set("Content-Type", "application/json")
err = json.NewEncoder(writer).Encode(&apiResponse)
helper.PanicIfError(err)
}2. Membuat Struct Request dan Response
๐ File: request/booking_request.go
package request
type BookingCreateRequest struct {
EventId int `json:"event_id"`
SeatId int `json:"seat_id"`
UserId int `json:"user_id"`
}๐ File: response/api_response.go
package response
type ApiResponse struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}3. Setup Koneksi Database
๐ File: app/database.go
package app
import (
"database/sql"
"github.com/fardannozami/ticket-booking/helper"
)
func NewSqlDb() *sql.DB {
db, err := sql.Open("mysql", "root@tcp(127.0.0.1:3306)/ticket-booking")
helper.PanicIfError(err)
return db
}4. Tambahkan Exception Handler
๐ File: exception/error_handler.go
package exception
import (
"encoding/json"
"net/http"
"github.com/fardannozami/ticket-booking/helper"
"github.com/fardannozami/ticket-booking/response"
)
func ErrorHandler(w http.ResponseWriter, r *http.Request, err interface{}) {
internalServerError(w, r, err)
}
func internalServerError(w http.ResponseWriter, r *http.Request, err interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
var message string
switch e := err.(type) {
case string:
message = e
case error:
message = e.Error()
default:
message = "Unknown error"
}
apiResponse := response.ApiResponse{
Code: http.StatusInternalServerError,
Message: "Internal Server Error",
Data: message,
}
encode := json.NewEncoder(w)
error := encode.Encode(&apiResponse)
helper.PanicIfError(error)
}5. Menjalankan HTTP Server
๐ File: main.go
package main
import (
"net/http"
"github.com/fardannozami/ticket-booking/app"
"github.com/fardannozami/ticket-booking/controller"
"github.com/fardannozami/ticket-booking/exception"
"github.com/fardannozami/ticket-booking/helper"
"github.com/fardannozami/ticket-booking/repository"
"github.com/fardannozami/ticket-booking/service"
_ "github.com/go-sql-driver/mysql"
"github.com/julienschmidt/httprouter"
)
func main() {
db := app.NewSqlDb()
bookingRepo := repository.NewBookingRepository()
bookingService := service.NewBookingService(db, bookingRepo)
bookingController := controller.NewBookingController(bookingService)
router := httprouter.New()
router.POST("/api/bookseat", bookingController.BookSeat)
router.PanicHandler = exception.ErrorHandler
server := http.Server{
Addr: ":3000",
Handler: router,
}
err := server.ListenAndServe()
helper.PanicIfError(err)
}๐งช Contoh Testing via Curl atau Postman
๐ธ Request (Booking Kursi)
curl -X POST http://localhost:3000/api/bookseat \
-H "Content-Type: application/json" \
-d '{
"event_id": 1,
"seat_id": 2,
"user_id": 12
}'โ Response Berhasil
{
"code": 201,
"message": "created",
"data": null
}โ Response Gagal (kursi sudah dibooking)
{
"code": 409,
"message": "seat already booked",
"data": null
}> ๐ Pastikan data event_id dan seat_id valid dan tersedia di database untuk testing ini.
๐ Summary
| Fitur | Status |
|---|---|
| BookingService | โ |
| Race Condition Handling | โ |
| JSON Request & Response | โ |
HTTP Routing (httprouter) | โ |
| Endpoint Booking Seat | โ |
๐ Tips Tambahan
Jika kamu ingin meningkatkan proyek ini lebih jauh, pertimbangkan untuk:
* Menambahkan validasi input menggunakan go-playground/validator
* Menyimpan konfigurasi ke .env dan memuatnya menggunakan joho/godotenv
* Menambahkan middleware untuk logging atau recovery
* Menyusun error handling lebih rapi agar tidak semua pakai PanicIfError
More Articles
You might also like
Claim Management System - Filament v4 Setup & Workflow Awal
Di Part 2, kita sudah: melakukan setup project Laravel 12 mendesain database schema yang realistis dan audit-friendly Sekarang di Part 3, kita mulai membangun UI dan workflow awal menggunakan Filament v4. ๐ฏ Target Part 3 Pada bagian ini kita ak...
Panduan Lengkap If-Else dan Switch dalam Golang
1. Pengenalan If-Else Dalam bahasa pemrograman Golang, if dan else digunakan untuk pengambilan keputusan dalam suatu program. Dengan if, kita bisa mengevaluasi suatu kondisi, dan berdasarkan hasilnya (benar atau salah), program akan mengeksekusi blok...
Menunggu Goroutine Selesai dengan WaitGroup
Halo teman-teman! Kita ketemu lagi di seri Golang Goroutine.Setelah sebelumnya kita belajar tentang Race Condition, kali ini kita akan membahas cara menunggu semua Goroutine selesai dengan benar menggunakan sync.WaitGroup. Ini topik penting supaya pr...