๐ฌ 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
.envdan memuatnya menggunakanjoho/godotenv - Menambahkan middleware untuk logging atau recovery
- Menyusun error handling lebih rapi agar tidak semua pakai
PanicIfError
More Articles
You might also like
Go Financial Core System - System Design
Kita mau bikin sistem seperti e-wallet (contoh: Dana, OVO), tapi: Aman (tidak bisa saldo dobel / hilang) Tidak error saat banyak orang transaksi bersamaan Mudah dikembangkan ๐ง 1. Gambaran Besar
Package errors, os, dan flag di Golang
Setelah memahami dasar penggunaan package fmt, kini kita lanjut ke tiga package penting lainnya dalam standard library Golang: errors, os, dan flag. Ketiganya sering digunakan dalam pembuatan aplikasi CLI (Command Line Interface) dan sangat berguna u...
Panduan Instalasi Golang di WSL 2 Ubuntu
Halo teman-teman! Pada tutorial ini, kita akan belajar cara menginstal Golang di WSL 2 Ubuntu dengan langkah-langkah yang mudah dipahami. Yuk, kita mulai! 1. Mengatur WSL ke Versi 2 Sebelum menginstal Golang, pastikan WSL (Windows Subsystem for Linux...