dim

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 18, 2026 License: MIT Imports: 39 Imported by: 0

README

Dim Framework

Dim adalah web framework Go yang sederhana, dirancang untuk membantu membangun RESTful API dengan cepat.

Saya membangun Dim di atas http.ServeMux (Go 1.22+) agar tetap ringan dan kompatibel dengan standar library Go, namun menambahkan berbagai "bumbu" yang biasanya saya butuhkan di aplikasi nyata: konsistensi struktur, database management, dan keamanan.

Kenapa Dim?

Daripada menyusun ulang library yang sama setiap kali memulai project baru (seperti Router, Middleware, Config, Database), Dim menyediakannya dalam satu paket yang kohesif dan siap pakai.

Fitur yang "Just Works"
  • Routing: Menggunakan standar http.ServeMux Go 1.22+ dengan dukungan parameter (/users/{id}) dan method matching.
  • Productivity CLI: Command line tools bawaan untuk migrasi database, generate file, dan manajemen server.
  • Database Ready: Wrapper pgx untuk PostgreSQL dengan fitur Auto-Masking Logs (data sensitif di log database otomatis disensor).
  • Security First: Bawaan Rate Limiting, CORS, CSRF, dan JWT helpers.
  • Developer Experience: Helper untuk JSON response, pagination, sorting, dan error handling yang konsisten.

Instalasi

go get github.com/dimframework/dim

Dokumentasi Lengkap

Panduan lengkap, referensi API, dan tutorial mendalam tersedia di folder docs:

Cara Pakai

Berikut adalah setup standar aplikasi menggunakan Console agar fitur CLI aktif:

package main

import (
	"log"
	"net/http"
	"os"

	"github.com/dimframework/dim"
)

func main() {
	// 1. Load Config & DB
	config, _ := dim.LoadConfig()
	db, _ := dim.NewPostgresDatabase(config.Database)
	defer db.Close()

	// 2. Setup Router
	router := dim.NewRouter()
	router.Use(dim.RecoveryMiddleware)
	router.Use(dim.LoggerMiddleware)

	// 3. Define Routes
	router.Get("/", func(w http.ResponseWriter, r *http.Request) {
		dim.Response(w).Ok(dim.Map{"message": "Halo, Dunia!"})
	})

	// 4. Run Console
	router.Build() // Siapkan router untuk introspeksi
	console := dim.NewConsole(db, router, config)
	console.RegisterBuiltInCommands()

	// Menjalankan aplikasi
	if err := console.Run(os.Args[1:]); err != nil {
		log.Fatal(err)
	}
}

CLI Tools

Dim menyertakan tool CLI untuk membantu workflow development Anda sehari-hari.

# Menjalankan Server
go run main.go serve

# Membuat File Migrasi Baru (Timestamped)
go run main.go make:migration create_users_table

# Menjalankan Migrasi Database
go run main.go migrate

# Melihat Status Migrasi
go run main.go migrate:list

# Melihat Daftar Route
go run main.go route:list

# Bantuan Lengkap
go run main.go help

Fitur Populer

1. Database Migrations

Tidak perlu tool eksternal atau file .sql manual. Migrasi ditulis dalam Go, menggunakan init() function untuk registrasi otomatis, dan mendukung timestamp versioning.

2. Smart Logging

Framework ini peduli pada keamanan data log Anda. Query database yang mengandung field sensitif seperti password, token, atau api_key akan otomatis disensor (*****) sebelum dicetak ke log.

3. SPA & Static Files

Dim memudahkan integrasi dengan frontend modern (React, Vue, Svelte). Method router.SPA() menangani fallback routing di sisi klien sehingga user yang me-refresh halaman /dashboard tidak akan terkena 404 error.

Kontribusi

Project ini dikembangkan secara terbuka. Jika Anda menemukan bug atau memiliki ide untuk perbaikan, silakan buka Issue atau kirimkan Pull Request.

Lisensi

MIT

Documentation

Overview

Package dim menyediakan utilitas upload file dengan fitur keamanan komprehensif. Mendukung pemrosesan sequential dan concurrent dengan validasi, sanitisasi, dan deteksi content-type.

Index

Constants

View Source
const (
	// MinPasswordLength is the minimum required password length
	MinPasswordLength = 8
	// BcryptCost is the bcrypt cost factor
	BcryptCost = 12
)

Variables

View Source
var (
	ErrBadRequest          = NewAppError("Permintaan tidak valid", 400)
	ErrValidation          = NewAppError("Validasi gagal", 400)
	ErrUnauthorized        = NewAppError("Tidak terotorisasi", 401)
	ErrForbidden           = NewAppError("Dilarang", 403)
	ErrNotFound            = NewAppError("Tidak ditemukan", 404)
	ErrConflict            = NewAppError("Konflik", 409)
	ErrInternalServerError = NewAppError("Kesalahan server internal", 500)
)

Common error instances

Functions

func BadRequest

func BadRequest(w http.ResponseWriter, message string, errors map[string]string) error

BadRequest menulis 400 Bad Request error response. Berguna untuk validation errors atau malformed requests.

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • message: error message
  • errors: optional map dari field names ke error messages untuk validation errors

Returns:

  • error: error jika encoding JSON gagal

Example:

BadRequest(w, "Validasi gagal", map[string]string{
  "email": "Email tidak valid",
})

func BuiltinConstraintValidators

func BuiltinConstraintValidators() map[string]ConstraintValidator

BuiltinConstraintValidators returns a map of built-in constraint validators. These validators handle common constraints like "in" for enums. Can be extended by adding custom validators to FilterParser.

func CleanIPAddress

func CleanIPAddress(address string) string

CleanIPAddress menghapus port number dari IP address string. Menangani IPv6 format dengan bracket notation dan IPv4:port format. Returns IP tanpa port atau original string jika tidak ada port.

Parameters:

  • address: IP address string dengan atau tanpa port (contoh: "192.168.1.1:8080" atau "[::1]:8080")

Returns:

  • string: clean IP address tanpa port

Example:

CleanIPAddress("192.168.1.1:8080")   // returns "192.168.1.1"
CleanIPAddress("[::1]:8080")         // returns "::1"
CleanIPAddress("192.168.1.1")        // returns "192.168.1.1"

func Conflict

func Conflict(w http.ResponseWriter, message string, errors map[string]string) error

Conflict menulis 409 Conflict error response. Berguna untuk requests yang conflict dengan state saat ini (contoh: duplicate email).

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • message: error message
  • errors: optional map dari field names ke error messages

Returns:

  • error: error jika encoding JSON gagal

Example:

Conflict(w, "Email sudah terdaftar", map[string]string{
  "email": "Email ini sudah digunakan oleh pengguna lain",
})

func ContainsDigit

func ContainsDigit(s string) bool

ContainsDigit mengecek apakah string contains digits (0-9). Berguna untuk password validation dan number checking.

Parameters:

  • s: string yang akan dicek

Returns:

  • bool: true jika ada digits, false sebaliknya

Example:

ContainsDigit("Hello123")    // returns true
ContainsDigit("Hello")       // returns false

func ContainsLowercase

func ContainsLowercase(s string) bool

ContainsLowercase mengecek apakah string contains lowercase letters (a-z). Berguna untuk password validation dan character set checking.

Parameters:

  • s: string yang akan dicek

Returns:

  • bool: true jika ada lowercase letters, false sebaliknya

Example:

ContainsLowercase("Hello")    // returns true
ContainsLowercase("HELLO")    // returns false

func ContainsRune

func ContainsRune(s string, predicate func(rune) bool) bool

ContainsRune mengecek apakah string contains any rune yang match predicate function. Generic helper untuk custom character checking dengan flexible predicates.

Parameters:

  • s: string yang akan dicek
  • predicate: function yang return true untuk matching runes

Returns:

  • bool: true jika ada rune yang match, false sebaliknya

Example:

ContainsRune("Hello123", unicode.IsDigit)  // returns true
ContainsRune("Hello", unicode.IsDigit)     // returns false

func ContainsSpecial

func ContainsSpecial(s string) bool

ContainsSpecial mengecek apakah string contains special characters. Supported special characters: !@#$%^&*()-_=+[]{}|;:',.<>?/\~` Berguna untuk password strength validation.

Parameters:

  • s: string yang akan dicek

Returns:

  • bool: true jika ada special characters, false sebaliknya

Example:

ContainsSpecial("Hello!123")    // returns true
ContainsSpecial("Hello123")     // returns false

func ContainsUppercase

func ContainsUppercase(s string) bool

ContainsUppercase mengecek apakah string contains uppercase letters (A-Z). Berguna untuk password validation dan character set checking.

Parameters:

  • s: string yang akan dicek

Returns:

  • bool: true jika ada uppercase letters, false sebaliknya

Example:

ContainsUppercase("Hello")    // returns true
ContainsUppercase("hello")    // returns false

func CreatePasswordResetTokensTable

func CreatePasswordResetTokensTable(pool *pgxpool.Pool) error

CreatePasswordResetTokensTable membuat password_reset_tokens table.

func CreateRateLimitsTable

func CreateRateLimitsTable(pool *pgxpool.Pool) error

CreateRateLimitsTable membuat tabel UNLOGGED untuk rate limiting.

func CreateRefreshTokensTable

func CreateRefreshTokensTable(pool *pgxpool.Pool) error

CreateRefreshTokensTable membuat refresh_tokens table.

func CreateTokenBlocklistTable

func CreateTokenBlocklistTable(pool *pgxpool.Pool) error

CreateTokenBlocklistTable membuat tabel UNLOGGED untuk token blocklist.

func Created

func Created(w http.ResponseWriter, data interface{}) error

Created menulis 201 Created response dengan data. Berguna untuk successful POST requests yang membuat resource baru.

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • data: resource baru yang dibuat

Returns:

  • error: error jika encoding JSON gagal

Example:

user := User{ID: 1, Name: "John"}
Created(w, user)  // 201 Created

func DetectContentType

func DetectContentType(filename string) string

DetectContentType mendeteksi MIME content type file berdasarkan extension-nya.

Fungsi melakukan case-insensitive extension matching terhadap map komprehensif dari MIME types yang diketahui. Mengembalikan MIME type string yang sesuai untuk extension file, atau "application/octet-stream" jika extension tidak diketahui.

Kategori file yang didukung:

  • Images: JPEG, PNG, GIF, WebP, SVG, ICO, TIFF, BMP
  • Documents: PDF, Word (DOC/DOCX), Excel (XLS/XLSX), PowerPoint (PPT/PPTX), ODF formats
  • Text & Code: TXT, CSV, HTML, CSS, JavaScript, JSON, XML, YAML, Markdown, TypeScript, etc.
  • Archives: ZIP, RAR, 7Z, TAR, GZIP, BZIP2, etc.
  • Video: MP4, AVI, MOV, WMV, WebM, MPEG, MKV, FLV
  • Audio: MP3, WAV, OGG, FLAC, M4A, AAC
  • Web Fonts: WOFF, WOFF2, TTF, OTF, EOT
  • Others: EPUB, TORRENT, etc.

Parameter:

filename - Nama file (dapat include path, extension di-extract otomatis)

Return:

MIME type string dalam format "type/subtype" (misal: "image/jpeg", "text/plain").
Mengembalikan "application/octet-stream" sebagai fallback untuk extension yang tidak diketahui.

Contoh:

DetectContentType("photo.jpg")       // Mengembalikan "image/jpeg"
DetectContentType("document.pdf")    // Mengembalikan "application/pdf"
DetectContentType("script.js")       // Mengembalikan "application/javascript"
DetectContentType("unknown.xyz")     // Mengembalikan "application/octet-stream"
DetectContentType("/path/to/file.png") // Mengembalikan "image/png" (path di-handle otomatis)

func DropPasswordResetTokensTable

func DropPasswordResetTokensTable(pool *pgxpool.Pool) error

DropPasswordResetTokensTable menghapus password_reset_tokens table.

func DropRateLimitsTable

func DropRateLimitsTable(pool *pgxpool.Pool) error

DropRateLimitsTable menghapus tabel rate limits.

func DropRefreshTokensTable

func DropRefreshTokensTable(pool *pgxpool.Pool) error

DropRefreshTokensTable menghapus refresh_tokens table.

func DropTokenBlocklistTable

func DropTokenBlocklistTable(pool *pgxpool.Pool) error

DropTokenBlocklistTable menghapus tabel token blocklist.

func Forbidden

func Forbidden(w http.ResponseWriter, message string) error

Forbidden menulis 403 Forbidden error response. Berguna untuk authenticated requests yang tidak punya permission untuk access resource.

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • message: error message

Returns:

  • error: error jika encoding JSON gagal

Example:

Forbidden(w, "Anda tidak memiliki permission untuk access resource ini")

func GenerateCSRFToken

func GenerateCSRFToken(length int) (string, error)

GenerateCSRFToken menghasilkan token CSRF baru dengan secure random bytes. Token di-encode sebagai hex string dengan specified length. Token ini harus disimpan di cookie dan dikirim di request header atau form untuk verification.

Parameters:

  • length: jumlah random bytes untuk generate (contoh: 32)

Returns:

  • string: hex-encoded CSRF token
  • error: error jika random byte generation gagal

Example:

token, err := GenerateCSRFToken(32)
if err != nil {
  return err
}
SetCSRFToken(w, token, csrfConfig)

func GenerateSecureToken

func GenerateSecureToken(length int) (string, error)

GenerateSecureToken menghasilkan token random yang cryptographically secure. Token di-generate menggunakan crypto/rand dan di-encode sebagai hex string. Berguna untuk session tokens, API keys, CSRF tokens, password reset tokens, dll.

Parameters:

  • length: jumlah bytes random untuk generate (contoh: 32)

Returns:

  • string: hex-encoded token string
  • error: error jika random generation gagal

Example:

token, err := GenerateSecureToken(32)
if err != nil {
  return err
}
// token adalah hex string dengan panjang 64 (32 bytes * 2)

func GenerateTokenHash

func GenerateTokenHash(token string) string

GenerateTokenHash membuat hash dari token untuk disimpan di database. Menggunakan bcrypt hashing untuk keamanan, bukan actual token.

Parameters:

  • token: token string yang akan di-hash

Returns:

  • string: hashed token yang bisa disimpan di database

Example:

tokenHash := GenerateTokenHash(refreshToken)
// store tokenHash in database instead of actual token

func GetAuthToken

func GetAuthToken(r *http.Request) (string, bool)

GetAuthToken mengekstrak JWT token dari Authorization header. Mengharapkan format: "Bearer <token>" Returns token dan boolean indicating apakah token ditemukan dan valid format.

Parameters:

  • r: *http.Request request yang di-check Authorization headernya

Returns:

  • string: JWT token string (tanpa "Bearer" prefix)
  • bool: true jika token valid format, false jika tidak ada atau invalid format

Example:

token, ok := GetAuthToken(req)
if !ok {
  return JsonError(w, 401, "Token tidak ditemukan", nil)
}
userID, err := jwtManager.VerifyAccessToken(token)

func GetCSRFToken

func GetCSRFToken(r *http.Request, headerName string) string

GetCSRFToken mengekstrak CSRF token dari request dengan mencek multiple sources. Cek dilakukan dalam urutan: header (X-CSRF-Token), form data (_csrf field). Returns empty string jika token tidak ditemukan di manapun. Header check diprioritaskan untuk API requests, form data untuk traditional forms.

Parameters:

  • r: *http.Request yang akan di-check token-nya
  • headerName: nama header untuk cek CSRF token (contoh: X-CSRF-Token)

Returns:

  • string: CSRF token jika ditemukan, empty string jika tidak ada

Example:

token := GetCSRFToken(req, "X-CSRF-Token")
if token == "" {
  return JsonError(w, 400, "Token CSRF diperlukan", nil)
}

func GetClaims

func GetClaims(r *http.Request) map[string]interface{}

GetClaims mengambil custom claims dari request context jika user terotentikasi. Memeriksa apakah user mengimplementasikan method GetClaims() map[string]interface{}.

Parameters:

  • r: *http.Request request yang akan diperiksa

Returns:

  • map[string]interface{}: map claims, atau nil jika tidak ada atau user tidak punya claims

func GetClientIP

func GetClientIP(r *http.Request) string

GetClientIP mengekstrak client IP address dari HTTP request. Mengecek X-Forwarded-For, X-Real-IP, X-Forwarded headers (untuk proxy scenarios). Falls back ke RemoteAddr jika headers tidak ada. Menangani IPv4 dan IPv6 formats dengan port numbers.

Parameters:

  • r: *http.Request yang berisi client information

Returns:

  • string: client IP address string (IPv4 atau IPv6 format tanpa port)

Example:

clientIP := GetClientIP(req)  // returns "192.168.1.1" atau "::1"

func GetCookie

func GetCookie(r *http.Request, name string) string

GetCookie mengambil nilai cookie dari HTTP request berdasarkan nama. Returns empty string jika cookie tidak ditemukan.

Parameters:

  • r: *http.Request yang berisi cookies
  • name: nama cookie yang akan diambil

Returns:

  • string: cookie value, empty string jika tidak ditemukan

Example:

sessionID := GetCookie(req, "session_id")  // returns cookie value atau ""

func GetEnv

func GetEnv(key string) string

GetEnv mengambil environment variable berdasarkan key. Returns empty string jika variable tidak ada.

Parameters:

  • key: nama environment variable yang akan diambil

Returns:

  • string: value dari environment variable, empty string jika tidak ada

Example:

port := GetEnv("PORT")  // jika PORT=8080, returns "8080"

func GetEnvOrDefault

func GetEnvOrDefault(key, defaultValue string) string

GetEnvOrDefault mengambil environment variable atau return default value jika tidak ada. Useful untuk provide fallback values untuk configuration.

Parameters:

  • key: nama environment variable
  • defaultValue: default value jika variable tidak ada atau empty

Returns:

  • string: value dari environment variable atau defaultValue

Example:

port := GetEnvOrDefault("PORT", "8080")  // returns "8080" jika PORT tidak set
dbHost := GetEnvOrDefault("DB_HOST", "localhost")

func GetHeaderValue

func GetHeaderValue(r *http.Request, key string) string

GetHeaderValue mengambil header value dari HTTP request. Header names case-insensitive (Go automatically handles this). Returns empty string jika header tidak ditemukan.

Parameters:

  • r: *http.Request request yang di-check headernya
  • key: nama header yang akan diambil

Returns:

  • string: header value, empty string jika tidak ditemukan

Example:

contentType := GetHeaderValue(req, "Content-Type")

func GetParam

func GetParam(r *http.Request, key string) string

GetParam mengambil single path parameter dari request. Menggunakan stdlib r.PathValue() untuk pattern {id}. Returns empty string jika parameter tidak ditemukan.

Parameters:

  • r: *http.Request request yang di-check parameternya
  • key: nama parameter yang akan diambil

Returns:

  • string: parameter value, empty string jika tidak ditemukan

Example:

// Route: GET /users/{id}
userID := GetParam(req, "id")

func GetQueryParam

func GetQueryParam(r *http.Request, key string) string

GetQueryParam mengambil single query parameter dari request URL. Query parameters adalah bagian dari URL setelah "?" (contoh: ?name=value). Returns empty string jika parameter tidak ditemukan.

Parameters:

  • r: *http.Request request yang di-check query parameternya
  • key: nama query parameter yang akan diambil

Returns:

  • string: query parameter value, empty string jika tidak ditemukan

Example:

page := GetQueryParam(req, "page")  // dari URL: /users?page=2

func GetQueryParams

func GetQueryParams(r *http.Request, keys ...string) map[string]string

GetQueryParams mengambil multiple query parameters dari request URL. Berguna untuk mengambil beberapa query parameters sekaligus. Returns map dengan empty string values untuk parameters yang tidak ditemukan.

Parameters:

  • r: *http.Request request yang di-check query parameternya
  • keys: variadic list dari query parameter names yang akan diambil

Returns:

  • map[string]string: map dari parameter names ke values

Example:

params := GetQueryParams(req, "page", "limit", "sort")
page := params["page"]

func GetRequestID

func GetRequestID(r *http.Request) string

GetRequestID mengambil request ID dari context. Returns empty string jika request ID tidak ditemukan. Gunakan value ini untuk logging dan request tracing.

Parameters:

  • r: *http.Request request yang di-check contextnya

Returns:

  • string: request ID, empty string jika tidak ada

Example:

requestID := GetRequestID(req)
logger.Info("Processing request", "request_id", requestID)

func HashPassword

func HashPassword(password string) (string, error)

HashPassword melakukan hash password menggunakan bcrypt algorithm. Menggunakan BcryptCost constant untuk set hashing difficulty level.

Parameters:

  • password: plaintext password yang akan di-hash

Returns:

  • string: hashed password yang bisa disimpan di database
  • error: error jika hashing gagal

Example:

hashedPassword, err := HashPassword("myPassword123!")
if err != nil {
  return err
}

func InternalServerError

func InternalServerError(w http.ResponseWriter, message string) error

InternalServerError menulis 500 Internal Server Error response. Berguna untuk unexpected server errors. Jangan expose detailed error information ke client untuk security.

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • message: error message yang aman untuk dikirim ke client

Returns:

  • error: error jika encoding JSON gagal

Example:

InternalServerError(w, "Terjadi kesalahan pada server")

func IsAppError

func IsAppError(err error) bool

IsAppError mengecek apakah error adalah AppError instance. Berguna untuk type checking sebelum mengakses AppError-specific fields. Gunakan sebelum AsAppError untuk type assertion yang aman.

Parameters:

  • err: error yang akan di-check tipenya

Returns:

  • bool: true jika error adalah AppError, false jika tipe lain

Example:

if IsAppError(err) {
  appErr, _ := AsAppError(err)
  JsonAppError(w, appErr)
}

func IsHexChar

func IsHexChar(char byte) bool

IsHexChar mengecek apakah byte adalah valid hex digit (0-9, a-f, A-F). Berguna untuk validasi hex string seperti hash, color codes, dll.

Parameters:

  • char: byte character yang akan dicek

Returns:

  • bool: true jika char adalah hex digit, false sebaliknya

Example:

IsHexChar('A')  // returns true
IsHexChar('5')  // returns true
IsHexChar('G')  // returns false

func IsSafeHttpMethod

func IsSafeHttpMethod(method string) bool

IsSafeHttpMethod mengecek apakah HTTP method adalah safe (tidak mengubah state). Safe methods: GET, HEAD, OPTIONS (tidak memiliki side effects). Berguna untuk CSRF protection, caching, dan conditional logic.

Parameters:

  • method: HTTP method string (GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD)

Returns:

  • bool: true jika method adalah safe, false sebaliknya

Example:

IsSafeHttpMethod("GET")     // returns true
IsSafeHttpMethod("POST")    // returns false
IsSafeHttpMethod("OPTIONS") // returns true

func IsSafeRead

func IsSafeRead(query string) bool

IsSafeRead determines if a query is safe to route to a read replica. It uses a whitelist approach: only explicitly safe SELECT and CTE queries are allowed. Everything else (INSERT, UPDATE, Locking Reads, etc.) returns false.

func IsValidDateFormat

func IsValidDateFormat(date string) bool

IsValidDateFormat memvalidasi apakah string adalah valid YYYY-MM-DD format. Strict validation: harus exactly 10 characters, hyphens di positions 4 dan 7. Tidak mengvalidasi actual date validity (misalnya February 30).

Parameters:

  • date: date string yang akan divalidasi

Returns:

  • bool: true jika format valid YYYY-MM-DD, false sebaliknya

Example:

IsValidDateFormat("2024-01-15")  // returns true
IsValidDateFormat("2024-1-15")   // returns false (missing leading zero)
IsValidDateFormat("01/15/2024")  // returns false (wrong separator)

func IsValidUuid

func IsValidUuid(s string) bool

IsValidUuid mengecek apakah string adalah valid UUID tanpa melakukan full parsing. Lebih efficient daripada ParseUUID jika hanya perlu validation. Validates format, length, hyphen positions, dan hex characters.

Parameters:

  • s: string yang akan di-check

Returns:

  • bool: true jika valid UUID format, false sebaliknya

Example:

if IsValidUuid(userID) {
  uuid, _ := ParseUUID(userID)
}

func Json

func Json(w http.ResponseWriter, status int, data interface{}) error

Json menulis JSON response dengan status code dan data yang diberikan. Content-Type header otomatis di-set ke "application/json". Untuk single objects, write langsung tanpa wrapper: {"id": 1, "name": "John"} Untuk arrays, write langsung tanpa wrapper: [{"id": 1, "name": "John"}]

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • status: HTTP status code (contoh: 200, 400, 500)
  • data: data yang akan di-encode sebagai JSON

Returns:

  • error: error jika encoding JSON gagal

Example:

user := User{ID: 1, Name: "John", Email: "[email protected]"}
Json(w, 200, user)

func JsonAppError

func JsonAppError(w http.ResponseWriter, appErr *AppError) error

JsonAppError menulis AppError sebagai JSON response. Mengekstrak status code, message, dan field errors dari AppError dan mengirimnya. Convenience function yang wrap JsonError dengan AppError data.

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • appErr: *AppError yang berisi response data

Returns:

  • error: error jika encoding JSON gagal

Example:

appErr := NewAppError("Validasi gagal", 400)
appErr.WithFieldError("email", "Email sudah terdaftar")
JsonAppError(w, appErr)

func JsonError

func JsonError(w http.ResponseWriter, status int, message string, errors map[string]string) error

JsonError menulis error JSON response dengan message dan optional field errors. Response format: {"message": "error message", "errors": {"field": "error message"}} Content-Type header otomatis di-set ke "application/json". Gunakan untuk standard error responses dengan field-level error details.

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • status: HTTP status code (contoh: 400, 401, 404, 500)
  • message: error message string
  • errors: optional map dari field names ke error messages

Returns:

  • error: error jika encoding JSON gagal

Example:

JsonError(w, 400, "Validasi gagal", map[string]string{
  "email": "Email harus valid",
  "password": "Password minimal 8 karakter",
})

func JsonPagination

func JsonPagination(w http.ResponseWriter, status int, data interface{}, meta PaginationMeta) error

JsonPagination menulis paginated JSON response dengan data dan pagination metadata. Response format: {"data": [...], "meta": {"page": 1, "per_page": 10, "total": 100, "total_pages": 10}} Content-Type header otomatis di-set ke "application/json".

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • status: HTTP status code
  • data: data array/slice yang akan dipaginate
  • meta: PaginationMeta berisi pagination information

Returns:

  • error: error jika encoding JSON gagal

Example:

users := []User{{ID: 1, Name: "John"}, {ID: 2, Name: "Jane"}}
meta := PaginationMeta{Page: 1, PerPage: 10, Total: 100, TotalPages: 10}
JsonPagination(w, 200, users, meta)

func LoadEnvFile

func LoadEnvFile(filename string) error

LoadEnvFile memuat variabel lingkungan dari file .env yang ditentukan. Fungsi ini membaca file baris per baris, mengabaikan komentar dan baris kosong. Variabel lingkungan hanya akan diatur jika belum ada nilainya.

Parameters:

  • filename: Path lengkap ke file .env.

Returns:

  • error: Error jika file tidak dapat dibuka atau dibaca. Mengembalikan `nil` jika file tidak ada.

Example:

if err := LoadEnvFile(".env.development"); err != nil {
    log.Fatalf("Gagal memuat file .env: %v", err)
}

func LoadEnvFileFromPath

func LoadEnvFileFromPath(dir string) error

LoadEnvFileFromPath memuat variabel lingkungan dari file .env di dalam direktori yang ditentukan. Ini adalah fungsi pembantu yang membangun path ke .env dan memanggil LoadEnvFile.

Parameters:

  • dir: Direktori tempat file .env berada.

Returns:

  • error: Error yang sama seperti LoadEnvFile.

Example:

// Memuat .env dari direktori saat ini
LoadEnvFileFromPath(".")

// Memuat .env dari direktori konfigurasi
LoadEnvFileFromPath("./config")

func MiddlewareToHandler

func MiddlewareToHandler(m MiddlewareFunc, next http.Handler) http.Handler

MiddlewareToHandler mengkonversi MiddlewareFunc menjadi http.Handler. Berguna untuk menggunakan middleware dengan standard http patterns dan packages. Wrapper next parameter memungkinkan middleware untuk call next handler jika diperlukan.

Parameters:

  • m: MiddlewareFunc yang akan dikonversi
  • next: http.Handler yang akan dijalankan setelah middleware

Returns:

  • http.Handler: handler yang mengimplementasikan http.Handler interface

Example:

handler := MiddlewareToHandler(LoggerMiddleware, http.DefaultServeMux)
http.ListenAndServe(":8080", handler)

func NoContent

func NoContent(w http.ResponseWriter) error

NoContent menulis 204 No Content response. Berguna untuk successful requests yang tidak mengembalikan data (contoh: DELETE, PUT tanpa response body). Tidak ada response body yang dikirim.

Parameters:

  • w: http.ResponseWriter untuk menulis response

Returns:

  • error: selalu nil

Example:

NoContent(w)  // 204 No Content

func NotFound

func NotFound(w http.ResponseWriter, message string) error

NotFound menulis 404 Not Found error response. Berguna untuk requests ke resource yang tidak ada.

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • message: error message

Returns:

  • error: error jika encoding JSON gagal

Example:

NotFound(w, "User dengan ID 123 tidak ditemukan")

func OK

func OK(w http.ResponseWriter, data interface{}) error

OK menulis 200 OK response dengan data. Berguna untuk successful GET atau update requests yang mengembalikan data.

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • data: response data

Returns:

  • error: error jika encoding JSON gagal

Example:

users := []User{{ID: 1}, {ID: 2}}
OK(w, users)  // 200 OK

func ParseEnvBool

func ParseEnvBool(s string) bool

ParseEnvBool mengurai string boolean dari variabel lingkungan. Nilai yang dikenali sebagai `true` (tidak case-sensitive) adalah "true", "yes", "1", "on". Semua nilai lain dianggap `false`.

Parameters:

  • s: Nilai string untuk diurai.

Returns:

  • bool: Nilai boolean yang diurai.

Example:

debugMode := ParseEnvBool("true")   // returns true
featureOn := ParseEnvBool("1")      // returns true
disabled := ParseEnvBool("false") // returns false

func ParseEnvDuration

func ParseEnvDuration(value string) (time.Duration, error)

ParseEnvDuration mengurai string durasi dari variabel lingkungan.

Parameters:

  • value: Nilai string untuk diurai (misalnya, "30s", "15m", "1h").

Returns:

  • time.Duration: Nilai durasi yang diurai. Mengembalikan 0 jika input kosong.
  • error: Error jika string durasi tidak valid.

Example:

timeout, err := ParseEnvDuration("30s") // returns 30 * time.Second, nil
invalid, err := ParseEnvDuration("abc") // returns 0, error

func ParseEnvInt

func ParseEnvInt(value string) (int, error)

ParseEnvInt mengurai string integer dari variabel lingkungan. Spasi di awal dan akhir akan diabaikan.

Parameters:

  • value: Nilai string untuk diurai.

Returns:

  • int: Nilai integer yang diurai. Mengembalikan 0 jika input kosong.
  • error: Error jika string integer tidak valid.

Example:

port, err := ParseEnvInt(" 8080 ") // returns 8080, nil
invalid, err := ParseEnvInt("abc")  // returns 0, error

func PathMatches

func PathMatches(path string, patterns []string) bool

PathMatches mengecek apakah path match any pattern dalam list. Supports simple glob patterns dengan * wildcard. Pattern: "*" cocok semua path, "/webhooks/*" cocok /webhooks/anything.

Parameters:

  • path: URL path yang akan dicek
  • patterns: list pattern untuk matching (exact atau glob)

Returns:

  • bool: true jika path cocok dengan any pattern, false sebaliknya

Example:

PathMatches("/webhooks/github", []string{"/webhooks/*"})  // returns true
PathMatches("/admin", []string{"/admin", "/api/*"})       // returns true
PathMatches("/users", []string{"/admin/*"})               // returns false

func Register

func Register(m Migration)

Register mendaftarkan migration ke global registry. Fungsi ini biasanya dipanggil di dalam fungsi init() pada file migration.

func RegisterMIMEType

func RegisterMIMEType(ext, mimeType string)

RegisterMIMEType mendaftarkan custom MIME type untuk file extension.

Ini memungkinkan Anda menambah support untuk custom atau proprietary file types di luar daftar built-in. Custom MIME types dicek terlebih dahulu sebelum built-in types, jadi Anda dapat override default MIME types jika diperlukan.

Fungsi adalah thread-safe dan dapat dipanggil concurrently dari multiple goroutines.

Parameter:

ext - File extension termasuk dot (misal: ".custom", ".myformat")
mimeType - MIME type string (misal: "application/x-custom")

Contoh:

RegisterMIMEType(".webmanifest", "application/manifest+json")
RegisterMIMEType(".wasm", "application/wasm")
RegisterMIMEType(".custom", "application/x-custom")

func RollbackMigration

func RollbackMigration(db *PostgresDatabase, migration Migration) error

RollbackMigration membatalkan/rollback migration tertentu dengan menjalankan Down function. Menghapus record migration dari migrations table.

Parameters:

  • db: PostgresDatabase instance untuk execute rollback queries
  • migration: Migration struct yang akan di-rollback

Returns:

  • error: error jika Down function gagal atau gagal menghapus migration record

Example:

err := RollbackMigration(db, migration)
if err != nil {
  log.Fatal(err)
}

func RunMigrations

func RunMigrations(db *PostgresDatabase, migrations []Migration) error

RunMigrations menjalankan semua pending migrations yang belum pernah dijalankan. Membuat migrations table jika belum ada, kemudian menjalankan migrations yang baru. Semua migrations di-log menggunakan slog.

Parameters:

  • db: PostgresDatabase instance untuk execute migration queries
  • migrations: slice dari Migration structs yang berisi Up dan Down functions

Returns:

  • error: error jika pembuatan migrations table gagal atau ada migration yang error

Example:

err := RunMigrations(db, migrations)
if err != nil {
  log.Fatal(err)
}

func ServeFile

func ServeFile(w http.ResponseWriter, filename, filePath string, statusCode int) error

ServeFile melayani file dari filesystem dengan Content-Type header yang tepat.

Fungsi helper ini mengirim file ke client dengan MIME type yang sesuai yang terdeteksi dari file extension. File dilayani sebagai attachment (download), berarti browser akan meminta user untuk download file daripada menampilkannya secara inline.

Fungsi otomatis mendeteksi Content-Type header yang benar berdasarkan file extension menggunakan DetectContentType().

Parameter:

w - http.ResponseWriter untuk menulis response ke
filename - Filename original (digunakan untuk content-type detection)
filePath - Path file sebenarnya di filesystem
statusCode - HTTP status code (biasanya http.StatusOK atau http.StatusCreated)

Return:

Error jika file tidak dapat dibuka atau dibaca, atau nil jika sukses.

Contoh:

ServeFile(w, "document.pdf", "/tmp/document.pdf", http.StatusOK)
ServeFile(w, "report.xlsx", "/data/reports/q1.xlsx", http.StatusOK)

Catatan: Gunakan ServeFileInline() jika Anda ingin file ditampilkan di browser daripada diunduh.

func ServeFileInline

func ServeFileInline(w http.ResponseWriter, filename, filePath string, statusCode int) error

ServeFileInline melayani file dari filesystem untuk inline display.

Fungsi helper ini mengirim file ke client dengan MIME type yang sesuai yang terdeteksi dari file extension. File dilayani sebagai inline content, artinya browser akan mencoba menampilkan file (jika tipe yang didukung seperti images, PDFs, atau videos) daripada meminta download.

Fungsi otomatis mendeteksi Content-Type header yang benar berdasarkan file extension menggunakan DetectContentType().

Parameter:

w - http.ResponseWriter untuk menulis response ke
filename - Filename original (digunakan untuk content-type detection)
filePath - Path file sebenarnya di filesystem
statusCode - HTTP status code (biasanya http.StatusOK)

Return:

Error jika file tidak dapat dibuka atau dibaca, atau nil jika sukses.

Contoh:

ServeFileInline(w, "image.jpg", "/images/photo.jpg", http.StatusOK)
ServeFileInline(w, "document.pdf", "/pdfs/report.pdf", http.StatusOK)
ServeFileInline(w, "video.mp4", "/videos/tutorial.mp4", http.StatusOK)

Catatan: Gunakan ServeFile() jika Anda ingin file diunduh daripada ditampilkan.

func SetCSRFToken

func SetCSRFToken(w http.ResponseWriter, token string, config CSRFConfig)

SetCSRFToken menyimpan CSRF token dalam cookie response. Cookie di-set dengan HttpOnly=false sehingga accessible dari JavaScript. SameSite=Lax digunakan untuk prevent CSRF attacks sambil tetap allow cross-site form submissions.

Parameters:

  • w: http.ResponseWriter untuk menulis cookie
  • token: CSRF token string yang akan disimpan
  • config: CSRFConfig yang berisi cookie configuration

Example:

token, _ := GenerateCSRFToken(32)
SetCSRFToken(w, token, csrfConfig)

func SetContentType

func SetContentType(w http.ResponseWriter, contentType string)

SetContentType menetapkan Content-Type header untuk response. Berguna untuk mengset content type custom selain application/json.

Parameters:

  • w: http.ResponseWriter untuk menulis header
  • contentType: content type string (contoh: text/plain, text/html, application/xml)

Example:

SetContentType(w, "text/html")
w.Write([]byte("<html><body>Hello</body></html>"))

func SetCookie

func SetCookie(w http.ResponseWriter, cookie *http.Cookie)

SetCookie menetapkan response cookie. Cookie akan dikirim ke client dan disimpan untuk subsequent requests.

Parameters:

  • w: http.ResponseWriter untuk menulis cookie
  • cookie: *http.Cookie yang akan dikirim

Example:

cookie := &http.Cookie{
  Name: "session_id",
  Value: "abc123",
  HttpOnly: true,
  Secure: true,
  MaxAge: 3600,
}
SetCookie(w, cookie)

func SetHeader

func SetHeader(w http.ResponseWriter, key, value string)

SetHeader menetapkan single response header. Header dapat di-set sebelum WriteHeader/SetStatus dipanggil.

Parameters:

  • w: http.ResponseWriter untuk menulis header
  • key: nama header (contoh: X-Custom-Header, Authorization)
  • value: header value

Example:

SetHeader(w, "X-Request-ID", "12345")
SetHeader(w, "Cache-Control", "no-cache")

func SetHeaders

func SetHeaders(w http.ResponseWriter, headers map[string]string)

SetHeaders menetapkan multiple response headers sekaligus. Convenience function untuk mengset banyak headers dalam satu call. Headers dapat di-set sebelum WriteHeader/SetStatus dipanggil.

Parameters:

  • w: http.ResponseWriter untuk menulis headers
  • headers: map[string]string dari header names ke values

Example:

SetHeaders(w, map[string]string{
  "X-Request-ID": "12345",
  "X-Version": "1.0",
  "Cache-Control": "no-cache",
})

func SetRequestID

func SetRequestID(r *http.Request, requestID string) *http.Request

SetRequestID menyimpan unique request ID ke dalam context. Request ID berguna untuk logging dan tracing requests across systems. Biasanya di-set oleh logger middleware di awal request processing.

Parameters:

  • r: *http.Request request yang akan diupdate contextnya
  • requestID: string unique identifier untuk request ini

Returns:

  • *http.Request: request baru dengan requestID disimpan di context

Example:

requestID := GenerateSecureToken(16)
req = SetRequestID(req, requestID)

func SetStatus

func SetStatus(w http.ResponseWriter, status int)

SetStatus menulis HTTP response status code. Harus dipanggil sebelum menulis response body. Setelah status ditulis, tidak bisa diubah lagi.

Parameters:

  • w: http.ResponseWriter untuk menulis status
  • status: HTTP status code (contoh: 200, 400, 500)

Example:

SetStatus(w, 201)  // Created
w.Write([]byte(`{"id": 1}`))

func SetUser

func SetUser(r *http.Request, user Authenticatable) *http.Request

SetUser menyimpan user object ke dalam request context. Berguna untuk menyimpan authenticated user info yang dapat diakses di handlers. Returns request baru dengan updated context.

Parameters:

  • r: *http.Request request yang akan diupdate contextnya
  • user: Authenticatable object yang akan disimpan

Returns:

  • *http.Request: request baru dengan user disimpan di context

Example:

req = SetUser(req, user)
user, ok := GetUser(req)

func SimpleGlobMatch

func SimpleGlobMatch(path, pattern string) bool

SimpleGlobMatch mengimplementasikan basic glob matching dengan * wildcard saja. Supports exact match dan trailing wildcard pattern. Pattern "*" cocok semua path, "/path/*" cocok /path/anything dan /path/anything/nested.

Parameters:

  • path: URL path yang akan dicek
  • pattern: glob pattern untuk matching

Returns:

  • bool: true jika path cocok dengan pattern, false sebaliknya

Example:

SimpleGlobMatch("/webhooks/github", "/webhooks/*")  // returns true
SimpleGlobMatch("/admin/users", "/admin")            // returns false
SimpleGlobMatch("/anything", "*")                    // returns true

func StartServer

func StartServer(ctx context.Context, config ServerConfig, handler http.Handler) error

StartServer starts the HTTP server with graceful shutdown support. It listens on the specified port and serves requests using the provided handler. When a SIGINT or SIGTERM signal is received (or context cancelled), it will attempt to shut down the server gracefully.

Parameters:

  • ctx: context to control the server (e.g., from main)
  • config: ServerConfig containing port and timeouts.
  • handler: http.Handler to serve (usually the Router).

Returns:

  • error: error if server fails to start or shutdown error.

Example:

ctx := context.Background()
config := dim.ServerConfig{Port: "8080"}
router := dim.NewRouter()
// ... register routes ...
if err := dim.StartServer(ctx, config, router); err != nil {
    log.Fatal(err)
}

func StripComments

func StripComments(query string) string

StripComments removes SQL comments (-- and /* */) and whitespace from the start of the string. This is an internal helper exposed for testing purposes.

func ToCamelCase

func ToCamelCase(s string) string

ToCamelCase converts snake_case or anything to CamelCase (PascalCase) example: create_users -> CreateUsers

func TooManyRequests

func TooManyRequests(w http.ResponseWriter, retryAfterSeconds int) error

TooManyRequests menulis 429 Too Many Requests response. Mengatur header Retry-After dan mengirim pesan error standar. Berguna untuk rate limiting middleware.

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • retryAfterSeconds: jumlah detik yang harus ditunggu client sebelum retry

Returns:

  • error: error jika encoding JSON gagal

Example:

TooManyRequests(w, 60)

func Unauthorized

func Unauthorized(w http.ResponseWriter, message string) error

Unauthorized menulis 401 Unauthorized error response. Berguna untuk requests tanpa authentication atau dengan invalid credentials.

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • message: error message

Returns:

  • error: error jika encoding JSON gagal

Example:

Unauthorized(w, "Token tidak valid atau telah expired")

func UploadFiles

func UploadFiles(
	ctx context.Context,
	disk storage.Storage,
	files []*multipart.FileHeader,
	opts ...UploadOption,
) ([]string, error)

UploadFiles meng-upload multiple file dengan validasi dan pemrosesan concurrent opsional.

Parameter:

  • ctx: Context untuk cancellation dan deadlines
  • disk: Storage backend (mengimplementasikan interface storage.Storage)
  • files: Slice multipart file headers untuk di-upload
  • opts: Konfigurasi opsional (WithPath, WithMaxFileSize, dll.)

Return:

  • []string: Path file yang berhasil di-upload
  • error: Error pertama yang ditemukan (lihat field Errors untuk complete error map)

Validasi:

  • Jumlah file dicek terhadap batas maxFiles
  • Ekstensi file divalidasi terhadap allowedExts
  • Ukuran file dicek terhadap batas maxFileSize
  • Content-type divalidasi untuk cocok dengan ekstensi
  • Nama file dan path disanitisasi terhadap serangan traversal

Saat Error:

  • File yang berhasil di-upload dibersihkan dari storage
  • Mengembalikan error dengan jumlah file yang gagal
  • Gunakan pesan error untuk menentukan file mana yang gagal

Contoh (Sequential):

paths, err := dim.UploadFiles(
    ctx, disk, formFiles,
    dim.WithPath("/uploads"),
    dim.WithMaxFileSize(10 << 20),
    dim.WithAllowedExts(".jpg", ".png", ".pdf"),
)
if err != nil {
    log.Printf("Upload failed: %v", err)
    return
}

Contoh (Concurrent):

paths, err := dim.UploadFiles(
    ctx, disk, formFiles,
    dim.WithConcurrent(true),
    dim.WithMaxWorkers(5),
    dim.WithLogger(logger),
)

func ValidatePasswordStrength

func ValidatePasswordStrength(password string) error

ValidatePasswordStrength memvalidasi password strength menggunakan default rules. Merupakan convenience function yang membuat validator dan langsung validate.

Parameters:

  • password: password string yang akan divalidasi

Returns:

  • error: AppError jika password tidak memenuhi strength requirements

Example:

err := ValidatePasswordStrength(password)

func VerifyPassword

func VerifyPassword(hashedPassword, password string) error

VerifyPassword memverifikasi plaintext password terhadap hash yang tersimpan. Menggunakan bcrypt untuk aman time-constant comparison.

Parameters:

  • hashedPassword: hashed password dari database
  • password: plaintext password untuk diverifikasi

Returns:

  • error: error jika password tidak cocok dengan hash

Example:

err := VerifyPassword(storedHash, providedPassword)
if err != nil {
  return "password tidak valid"
}

func VerifyTokenHash

func VerifyTokenHash(hash, token string) error

VerifyTokenHash memverifikasi token terhadap hash yang tersimpan di database. Menggunakan bcrypt compare untuk aman.

Parameters:

  • hash: hashed token dari database
  • token: actual token string untuk diverifikasi

Returns:

  • error: error jika token tidak cocok dengan hash

Example:

err := VerifyTokenHash(storedHash, token)
if err != nil {
  return "token tidak valid"
}

Types

type AmountRange

type AmountRange = Range[float64]

AmountRange: Floating point amount range Example: "100.50" or "100.50,500.75"

type AppError

type AppError struct {
	Message    string            `json:"message"`
	StatusCode int               `json:"-"`
	Errors     map[string]string `json:"errors,omitempty"`
}

AppError represents an application error with optional field-specific validation errors

func AsAppError

func AsAppError(err error) (*AppError, bool)

AsAppError mengkonversi error menjadi AppError jika possible. Type-safe conversion dengan ok flag untuk checking apakah conversion berhasil. Returns nil dan false jika error bukan AppError type. Gunakan dengan IsAppError untuk safe type conversion.

Parameters:

  • err: error yang akan dikonversi menjadi AppError

Returns:

  • *AppError: AppError pointer jika conversion berhasil, nil jika tidak
  • bool: true jika conversion berhasil, false jika error bukan AppError type

Example:

appErr, ok := AsAppError(err)
if ok {
  // appErr is safe to use
  appErr.WithFieldError("field", "error message")
}

func NewAppError

func NewAppError(message string, statusCode int) *AppError

NewAppError membuat AppError baru dengan message dan HTTP status code. Status code digunakan untuk menentukan HTTP response status saat error di-return ke client. Useful untuk error handling yang consistent dengan HTTP semantics.

Parameters:

  • message: error message string dalam bahasa Indonesia
  • statusCode: HTTP status code (contoh: 400, 401, 404, 500)

Returns:

  • *AppError: AppError instance dengan empty field errors

Example:

appErr := NewAppError("Validasi gagal", 400)
appErr.WithFieldError("email", "Email harus valid")
return appErr

func (*AppError) Error

func (e *AppError) Error() string

Error mengimplementasikan error interface. Mengembalikan string representation dari error dengan message dan field errors jika ada. Format: "message" atau "message: {field: error_message, ...}" jika ada field errors.

Returns:

  • string: error message string

Example:

appErr := NewAppError("Validasi gagal", 400)
appErr.WithFieldError("email", "Email tidak valid")
fmt.Println(appErr.Error())  // Output: Validasi gagal: map[email:Email tidak valid]

func (*AppError) WithFieldError

func (e *AppError) WithFieldError(field, message string) *AppError

WithFieldError menambahkan field-specific error ke AppError. Berguna untuk validation errors yang related ke specific fields. Mendukung method chaining untuk menambahkan multiple field errors. Jika field sudah ada, akan overwrite dengan message baru.

Parameters:

  • field: nama field yang memiliki error
  • message: error message untuk field ini

Returns:

  • *AppError: pointer to AppError untuk method chaining

Example:

appErr := NewAppError("Validasi gagal", 400).
  WithFieldError("email", "Email harus valid").
  WithFieldError("password", "Password minimal 8 karakter")

func (*AppError) WithFieldErrors

func (e *AppError) WithFieldErrors(errors map[string]string) *AppError

WithFieldErrors menambahkan multiple field-specific errors ke AppError sekaligus. Convenience function untuk menambahkan banyak field errors dalam satu call. Mendukung method chaining untuk kombinasi dengan WithFieldError. Jika fields sudah ada, akan overwrite dengan messages baru.

Parameters:

  • errors: map[string]string dari field names ke error messages

Returns:

  • *AppError: pointer to AppError untuk method chaining

Example:

appErr := NewAppError("Validasi gagal", 400).
  WithFieldErrors(map[string]string{
    "email": "Email harus valid",
    "password": "Password minimal 8 karakter",
  })

type AuthService

type AuthService struct {
	// contains filtered or unexported fields
}

AuthService menangani operasi otentikasi seperti login, register, dan manajemen token.

func NewAuthService

func NewAuthService(
	userStore AuthUserStore,
	tokenStore TokenStore,
	blocklist TokenBlocklist,
	jwtConfig *JWTConfig,
) (*AuthService, error)

NewAuthService membuat instance AuthService baru.

func (*AuthService) Login

func (s *AuthService) Login(ctx context.Context, email, password string) (string, string, error)

Login mengotentikasi pengguna menggunakan email dan password. Mengembalikan access token dan refresh token jika kredensial valid.

Parameters:

  • ctx: context request
  • email: email pengguna
  • password: password pengguna

Returns:

  • string: access token
  • string: refresh token
  • error: error jika kredensial tidak valid atau terjadi kesalahan server

func (*AuthService) Logout

func (s *AuthService) Logout(ctx context.Context, refreshTokenStr string) error

Logout mengeluarkan pengguna dengan membatalkan (revoke) refresh token mereka. Karena kita menggunakan Session ID (sid), kita juga mem-blacklist sid tersebut agar Access Token yang masih hidup (yang memiliki sid sama) ikut tidak valid.

func (*AuthService) RefreshToken

func (s *AuthService) RefreshToken(ctx context.Context, refreshTokenStr string) (string, string, error)

RefreshToken memperbarui access token menggunakan refresh token yang valid. Method ini akan membatalkan refresh token lama dan mengeluarkan pasangan token baru (Token Rotation).

Parameters:

  • ctx: context request
  • refreshTokenStr: string refresh token yang dikirim oleh client

Returns:

  • string: access token baru
  • string: refresh token baru
  • error: error jika token tidak valid, kadaluarsa, atau sudah dibatalkan

func (*AuthService) RequestPasswordReset

func (s *AuthService) RequestPasswordReset(ctx context.Context, email string) (string, error)

RequestPasswordReset memproses permintaan reset password. Akan membuat token reset dan menyimpannya (pengiriman email dilakukan oleh pemanggil). Mengembalikan token reset yang belum di-hash agar bisa dikirim ke user.

func (*AuthService) ResetPassword

func (s *AuthService) ResetPassword(ctx context.Context, resetTokenStr, newPassword string) error

ResetPassword mereset password pengguna menggunakan token reset yang valid. Setelah berhasil, semua refresh token pengguna akan dihapus untuk alasan keamanan.

func (*AuthService) WithClaimsProvider

func (s *AuthService) WithClaimsProvider(provider ClaimsProvider) *AuthService

WithClaimsProvider mengatur function provider untuk custom claims dan mengembalikan instance service. Method ini menggunakan pola chaining untuk memudahkan konfigurasi.

type AuthUserStore

type AuthUserStore interface {
	FindByEmail(ctx context.Context, email string) (Authenticatable, error)
	FindByID(ctx context.Context, id string) (Authenticatable, error)
	Update(ctx context.Context, user Authenticatable) error
}

AuthUserStore mendefinisikan interface yang dibutuhkan oleh AuthService untuk berinteraksi dengan penyimpanan data pengguna.

type Authenticatable

type Authenticatable interface {
	GetID() string
	GetEmail() string
	GetPassword() string
	SetPassword(string)
}

Authenticatable merepresentasikan entitas pengguna yang dapat diotentikasi. Interface ini memungkinkan framework untuk berinteraksi dengan model User apa pun.

func GetUser

func GetUser(r *http.Request) (Authenticatable, bool)

GetUser mengambil user object dari request context. Returns user dan boolean indicating apakah user ada di context. Returns nil user dan false jika user tidak ditemukan.

Parameters:

  • r: *http.Request request yang di-check contextnya

Returns:

  • Authenticatable: user object dari context, nil jika tidak ada
  • bool: true jika user ada, false jika tidak ada

Example:

user, ok := GetUser(req)
if !ok {
  return JsonError(w, 401, "Tidak authorized", nil)
}

type CORSConfig

type CORSConfig struct {
	AllowedOrigins   []string
	AllowedMethods   []string
	AllowedHeaders   []string
	AllowCredentials bool
	MaxAge           int
}

CORSConfig holds CORS configuration

type CSRFConfig

type CSRFConfig struct {
	Enabled     bool
	ExemptPaths []string
	TokenLength int
	CookieName  string
	HeaderName  string
}

CSRFConfig holds CSRF configuration

type ClaimsProvider

type ClaimsProvider func(ctx context.Context, user Authenticatable) (map[string]interface{}, error)

ClaimsProvider adalah fungsi yang mengembalikan custom claims untuk pengguna. Gunakan ini untuk menyisipkan data tambahan ke dalam JWT (seperti workspace_id, role, dll).

type Command

type Command interface {
	// Name mengembalikan nama command (contoh: "serve", "migrate", "route:list")
	Name() string

	// Description mengembalikan deskripsi singkat command untuk help text
	Description() string

	// Execute menjalankan logika command dengan context yang berisi dependencies
	Execute(ctx *CommandContext) error
}

Command adalah interface yang harus diimplementasikan oleh semua CLI commands. Setiap command mendefinisikan nama, deskripsi, dan logika eksekusi.

type CommandContext

type CommandContext struct {
	// Args adalah arguments yang tidak termasuk flags (positional arguments)
	Args []string

	// DB adalah database instance
	DB *PostgresDatabase

	// Router adalah router instance
	Router *Router

	// Config adalah application configuration
	Config *Config

	// Out adalah output writer untuk stdout (default: os.Stdout)
	// Digunakan untuk normal output dan testing
	Out io.Writer

	// Err adalah output writer untuk stderr (default: os.Stderr)
	// Digunakan untuk error messages dan warnings
	Err io.Writer
}

CommandContext berisi dependencies dan arguments yang dibutuhkan command saat eksekusi.

type Config

type Config struct {
	Server    ServerConfig
	JWT       JWTConfig
	Database  DatabaseConfig
	Email     EmailConfig
	RateLimit RateLimitConfig
	CORS      CORSConfig
	CSRF      CSRFConfig
}

Config holds all application configuration

func LoadConfig

func LoadConfig() (*Config, error)

LoadConfig memuat konfigurasi aplikasi dari environment variables. Menggabungkan konfigurasi dari semua bagian (Server, JWT, Database, Email, RateLimit, CORS, CSRF).

Returns:

  • *Config: struktur konfigurasi lengkap aplikasi
  • error: error jika validasi konfigurasi gagal

Example:

config, err := LoadConfig()
if err != nil {
  log.Fatal(err)
}

func (*Config) Validate

func (c *Config) Validate() error

Validate memvalidasi konfigurasi aplikasi untuk memastikan nilai required sudah ada. Mengecek JWT_SECRET, DB_WRITE_HOST, DB_NAME, dan DB_USER.

type Console

type Console struct {
	// contains filtered or unexported fields
}

Console adalah registry dan executor untuk CLI commands. Console mengelola semua registered commands dan menangani parsing/eksekusi.

func NewConsole

func NewConsole(db *PostgresDatabase, router *Router, config *Config) *Console

NewConsole membuat instance Console baru dengan dependencies yang diperlukan.

Parameter:

  • db: database instance (boleh nil jika tidak diperlukan)
  • router: router instance (boleh nil jika tidak diperlukan)
  • config: application config (boleh nil jika tidak diperlukan)

Mengembalikan:

  • *Console: instance console yang siap digunakan

Contoh:

console := dim.NewConsole(db, router, config)
console.RegisterBuiltInCommands()
console.Run(os.Args[1:])

func (*Console) Register

func (c *Console) Register(cmd Command) error

Register mendaftarkan custom command ke console. Command name harus unik, jika sudah ada akan mengembalikan error.

Parameter:

  • cmd: command yang akan didaftarkan

Mengembalikan:

  • error: nil jika sukses, error jika command name sudah terdaftar

Contoh:

console.Register(&MyCustomCommand{})

func (*Console) RegisterBuiltInCommands

func (c *Console) RegisterBuiltInCommands()

RegisterBuiltInCommands mendaftarkan semua built-in commands. Dipanggil setelah NewConsole() untuk menambahkan commands bawaan framework.

Contoh:

console := dim.NewConsole(db, router, config)
console.RegisterBuiltInCommands()

func (*Console) Run

func (c *Console) Run(args []string) error

Run menjalankan command berdasarkan arguments yang diberikan. Jika args kosong, default ke command "serve". Menangani flag parsing untuk FlaggedCommand dan help (-h).

Parameter:

  • args: command arguments (biasanya os.Args[1:])

Mengembalikan:

  • error: nil jika sukses, error jika command tidak ditemukan atau eksekusi gagal

Contoh:

if err := console.Run(os.Args[1:]); err != nil {
    log.Fatal(err)
}

func (*Console) SetOutput

func (c *Console) SetOutput(out, err io.Writer)

SetOutput sets custom output writers for testing purposes. If out or err is nil, it will use os.Stdout or os.Stderr respectively.

type ConstraintValidator

type ConstraintValidator interface {
	// Name returns the constraint name (e.g., "in", "min", "max", "regex").
	// Used to match constraint tags in struct fields.
	// Must be unique within FilterParser's registered validators.
	Name() string

	// Validate validates the value(s) against the constraint.
	// Called during FilterParser.Parse() for fields with matching constraint.
	//
	// Parameters:
	//   - values: slice of string values to validate (may be single element for pointer types)
	//   - constraint: constraint parameter from tag (e.g., "active|pending" for tag "in:active|pending")
	//   - fieldType: the target field type (use for type-specific validation logic)
	//
	// Returns:
	//   - nil if validation passes
	//   - error with descriptive message if validation fails
	//   - Error message appears in fp.Errors() map with key "filters[fieldName]"
	Validate(values []string, constraint string, fieldType reflect.Type) error
}

ConstraintValidator defines an interface for custom constraint validation. Enables extensible validation system where users can implement custom constraints without modifying FilterParser.

Design:

  • Single interface for all constraint types (extensible)
  • Registered via FilterParser.RegisterConstraintValidator()
  • Multiple validators per field supported (applied sequentially)
  • Unknown constraints gracefully skipped (forward-compatible)

Use Cases:

  • Enum validation (built-in "in" constraint)
  • Min/max length constraints
  • Regex pattern matching
  • Custom business rule validation
  • Type-specific constraints

Implementations:

  • Must be thread-safe (may be used concurrently)
  • Should provide clear, actionable error messages
  • Can access field type for type-aware validation

Example implementation:

type RegexValidator struct {
    patterns map[string]*regexp.Regexp
}
func (v *RegexValidator) Name() string { return "regex" }
func (v *RegexValidator) Validate(values []string, constraint string, _ reflect.Type) error {
    pattern := v.patterns[constraint]
    for _, v := range values {
        if !pattern.MatchString(v) {
            return fmt.Errorf("does not match pattern: %s", constraint)
        }
    }
    return nil
}

type Database

type Database interface {
	Exec(ctx context.Context, query string, args ...interface{}) error
	Query(ctx context.Context, query string, args ...interface{}) (Rows, error)
	QueryRow(ctx context.Context, query string, args ...interface{}) Row
	Begin(ctx context.Context) (pgx.Tx, error)
	Close() error
}

Database is the interface for database operations

type DatabaseConfig

type DatabaseConfig struct {
	WriteHost     string
	ReadHosts     []string
	Port          int
	Database      string
	Username      string
	Password      string
	MaxConns      int
	SSLMode       string            // SSL mode: "disable", "require", "prefer", "allow", "verify-ca", "verify-full" (default: "disable")
	RuntimeParams map[string]string // Custom runtime parameters (search_path, standard_conforming_strings, etc)
	QueryExecMode string            // Query execution mode: "simple" or "" (default)
}

DatabaseConfig holds database configuration

type DateRange

type DateRange = Range[string]

Type aliases for common range types

DateRange: String format "YYYY-MM-DD" Example: "2024-01-15" or "2024-01-01,2024-12-31"

type EmailConfig

type EmailConfig struct {
	From string
}

EmailConfig holds email configuration

type ErrorResponse

type ErrorResponse struct {
	Message string            `json:"message"`
	Errors  map[string]string `json:"errors,omitempty"`
}

ErrorResponse is the response structure for error responses

type FilterParser

type FilterParser struct {
	MaxValuesPerField int            // Maximum number of values allowed per filter field (0 = unlimited)
	TimestampTimezone *time.Location // Timezone for parsing timestamps (nil = UTC)
	// contains filtered or unexported fields
}

FilterParser parses filter parameters from an HTTP request and sets the fields of a target struct accordingly.

func NewFilterParser

func NewFilterParser(r *http.Request) *FilterParser

NewFilterParser creates a new FilterParser instance with unlimited values. Defaults:

  • MaxValuesPerField: 0 (unlimited)
  • TimestampTimezone: nil (UTC)
  • constraintValidator: built-in validators (e.g., "in" for enums)

func (*FilterParser) Errors

func (fp *FilterParser) Errors() map[string]string

Errors returns the errors encountered during parsing. Key format: "filters[fieldName]" (e.g., "filters[ids]"). Returns empty map if no errors occurred.

func (*FilterParser) HasErrors

func (fp *FilterParser) HasErrors() bool

HasErrors returns true if any errors were encountered during parsing. Check this before accessing filter results.

func (*FilterParser) Parse

func (fp *FilterParser) Parse(target interface{}) *FilterParser

Parse parses the filter parameters from the request and sets the fields of the target struct accordingly. Target must be a pointer to a struct with "filter" tags. Returns the receiver for method chaining.

Tag Format: "fieldName" or "fieldName,constraint1:value1,constraint2:value2" Example struct tags:

type Filters struct {
    // Basic types
    IDs         []int64       `filter:"ids"`
    Name        *string       `filter:"name"`
    Active      *bool         `filter:"active"`
    Tags        []string      `filter:"tags"`

    // Enum constraint (pipe-separated allowed values)
    Status      *string       `filter:"status,in:active|pending|archived"`
    Statuses    []string      `filter:"statuses,in:active|pending"`

    // Range types with From/To validation
    Amount      AmountRange   `filter:"amount"`            // single: "100" or range: "100,500"
    Price       *IntRange     `filter:"price"`             // integer range with optional pointer
    CreatedAt   TimestampRange `filter:"created_at"`       // date range "2024-01-01,2024-12-31"
    Date        DateRange     `filter:"date"`              // string date range
}

Built-in Constraints:

  • in:val1|val2|val3 : Enum validation for strings (pipe-separated allowed values)

Custom Constraints:

  • Register via RegisterConstraintValidator() to add custom constraint types
  • Multiple constraints per field supported

Error Handling:

  • Check HasErrors() before accessing filter results
  • Call Errors() to get map[string]string with field-specific error messages
  • Error keys follow format: "filters[fieldName]"

func (*FilterParser) RegisterConstraintValidator

func (fp *FilterParser) RegisterConstraintValidator(validator ConstraintValidator) *FilterParser

RegisterConstraintValidator registers a custom constraint validator. Replaces any existing validator with the same name (including built-in validators). Returns the receiver for method chaining.

Example - custom length validator:

type MinLengthValidator struct{}
func (v *MinLengthValidator) Name() string { return "min_length" }
func (v *MinLengthValidator) Validate(values []string, constraint string, fieldType reflect.Type) error {
    min := 0
    fmt.Sscanf(constraint, "%d", &min)
    for _, v := range values {
        if len(v) < min {
            return fmt.Errorf("minimum length %d required", min)
        }
    }
    return nil
}

fp.RegisterConstraintValidator(&MinLengthValidator())
fp.Parse(&filters)

func (*FilterParser) WithMaxValues

func (fp *FilterParser) WithMaxValues(max int) *FilterParser

WithMaxValues sets the maximum number of values allowed per filter field. Use 0 for unlimited (default). Returns the receiver for method chaining.

Example:

fp.WithMaxValues(10).Parse(&filters)

func (*FilterParser) WithTimezone

func (fp *FilterParser) WithTimezone(tz *time.Location) *FilterParser

WithTimezone sets the timezone for parsing timestamp ranges. If nil, UTC is used (default). This affects parseTimestampRange only. Returns the receiver for method chaining.

Example:

jakartaTz, _ := time.LoadLocation("Asia/Jakarta")
fp.WithTimezone(jakartaTz).Parse(&filters)

type FlaggedCommand

type FlaggedCommand interface {
	Command

	// DefineFlags mendefinisikan flags untuk command ini
	DefineFlags(fs *flag.FlagSet)
}

FlaggedCommand adalah interface opsional untuk command yang membutuhkan flags/options. Command yang mengimplementasikan interface ini dapat mendefinisikan flags mereka sendiri.

type HandlerFunc

type HandlerFunc func(http.ResponseWriter, *http.Request)

HandlerFunc is the standard HTTP handler function signature

func Chain

func Chain(handler HandlerFunc, middleware ...MiddlewareFunc) HandlerFunc

Chain membungkus handler dengan multiple middleware functions secara beruntun. Middleware diterapkan dalam urutan maju (pertama di list dijalankan pertama). Contoh: Chain(handler, m1, m2, m3) menghasilkan execution order: m1 -> m2 -> m3 -> handler. Gunakan untuk menerapkan middleware chain ke single handler.

Parameters:

  • handler: HandlerFunc yang akan dibungkus dengan middleware
  • middleware: variadic list dari MiddlewareFunc yang diterapkan berurutan

Returns:

  • HandlerFunc: handler baru dengan middleware chain diterapkan

Example:

finalHandler := Chain(myHandler, LoggerMiddleware, AuthMiddleware, RecoveryMiddleware)

func (HandlerFunc) ServeHTTP

func (h HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP mengimplementasikan http.Handler interface untuk HandlerFunc. Memungkinkan HandlerFunc digunakan di mana http.Handler diexpect. Ini membuatnya transparent untuk menggunakan HandlerFunc dengan standard http patterns.

Parameters:

  • w: http.ResponseWriter untuk menulis response
  • r: *http.Request request yang diproses

Example:

var h HandlerFunc = myHandler
h.ServeHTTP(w, r)  // calls h(w, r)

func (HandlerFunc) ToHandler

func (h HandlerFunc) ToHandler() http.Handler

ToHandler mengkonversi HandlerFunc menjadi http.Handler interface. Memungkinkan HandlerFunc digunakan di mana saja yang expect http.Handler. Conversion ini implicit di many Go standard library functions.

Returns:

  • http.Handler: http.Handler yang membungkus HandlerFunc

Example:

handler := myHandlerFunc.ToHandler()
http.Handle("/path", handler)

type HelpCommand

type HelpCommand struct {
	// contains filtered or unexported fields
}

HelpCommand menampilkan daftar semua command yang tersedia.

func (*HelpCommand) Description

func (c *HelpCommand) Description() string

func (*HelpCommand) Execute

func (c *HelpCommand) Execute(ctx *CommandContext) error

func (*HelpCommand) Name

func (c *HelpCommand) Name() string

type InConstraintValidator

type InConstraintValidator struct{}

InConstraintValidator implements ConstraintValidator for enum validation. Validates that values are in a predefined list of allowed values.

Format:

  • Tag: "fieldName,in:value1|value2|value3"
  • Separator: pipe (|) between allowed values
  • Whitespace: automatically trimmed from values and constraint

Behavior:

  • Applied to both pointer string and slice string types
  • Single value (pointer) or multiple values (slice) validated
  • Returns error if any value not in allowed list
  • User-friendly error message listing allowed values

Example usage:

type Filters struct {
    Status    *string   `filter:"status,in:active|pending|archived"`
    Statuses  []string  `filter:"statuses,in:active|pending"`
}

func (*InConstraintValidator) Name

func (v *InConstraintValidator) Name() string

Name returns the constraint name

func (*InConstraintValidator) Validate

func (v *InConstraintValidator) Validate(values []string, constraint string, fieldType reflect.Type) error

Validate checks if values are in the allowed list. Constraint format: "value1|value2|value3" (pipe-separated)

Process:

  1. Parses constraint string by pipe separator
  2. Trims whitespace from each allowed value
  3. Validates each input value exists in allowed set
  4. Returns first error encountered, or nil if all valid

Error messages:

  • "constraint tidak valid: tidak ada nilai yang diizinkan" - empty constraint
  • "nilai tidak valid: {value} (diizinkan: {list})" - value not in allowed set

type InMemoryBlocklist

type InMemoryBlocklist struct {
	// contains filtered or unexported fields
}

InMemoryBlocklist implementasi TokenBlocklist menggunakan goreus/cache. Cocok untuk single-instance deployment atau testing. PERHATIAN: Data hilang saat restart.

func NewInMemoryBlocklist

func NewInMemoryBlocklist() *InMemoryBlocklist

NewInMemoryBlocklist membuat instance baru InMemoryBlocklist. Menggunakan kapasistas 100,000 dan default eviction 7 hari (aman untuk refresh token).

func (*InMemoryBlocklist) Invalidate

func (m *InMemoryBlocklist) Invalidate(ctx context.Context, identifier string, expiresIn time.Duration) error

func (*InMemoryBlocklist) IsRevoked

func (m *InMemoryBlocklist) IsRevoked(ctx context.Context, identifier string) (bool, error)

type InMemoryRateLimitStore

type InMemoryRateLimitStore struct {
	// contains filtered or unexported fields
}

InMemoryRateLimitStore mengimplementasikan RateLimitStore menggunakan goreus/cache. Cocok untuk deployment single-instance. Data counter disimpan di memori dan hilang saat restart.

func NewInMemoryRateLimitStore

func NewInMemoryRateLimitStore(window time.Duration) *InMemoryRateLimitStore

NewInMemoryRateLimitStore membuat store rate limit in-memory baru.

Parameters:

  • window: durasi waktu untuk TTL cache (biasanya sama dengan ResetPeriod)

func (*InMemoryRateLimitStore) Allow

func (s *InMemoryRateLimitStore) Allow(ctx context.Context, key string, limit int, window time.Duration) (bool, error)

Allow mengecek dan menaikkan limit di in-memory cache.

func (*InMemoryRateLimitStore) Close

func (s *InMemoryRateLimitStore) Close() error

Close menutup cache in-memory.

type IntRange

type IntRange = Range[int64]

IntRange: Integer range Example: "100" or "100,500"

type JWTConfig

type JWTConfig struct {
	AccessTokenExpiry  time.Duration
	RefreshTokenExpiry time.Duration

	// Algorithm configuration
	SigningMethod string // "HS256" (default), "RS256", "ES256"

	// Symmetric Config (HMAC: HS256, HS384, HS512)
	HMACSecret string

	// Asymmetric Config (RSA/ECDSA: RS256, ES256)
	PrivateKey string            // PEM content for Signing
	PublicKeys map[string]string // Key ID (kid) -> PEM content Public Key (for rotation)

	// Remote Verification (JWKS)
	JWKSURL string
}

JWTConfig holds JWT configuration

type JWTManager

type JWTManager struct {
	// contains filtered or unexported fields
}

JWTManager handles JWT operations

func NewJWTManager

func NewJWTManager(config *JWTConfig) (*JWTManager, error)

NewJWTManager membuat JWT manager baru dengan konfigurasi yang diberikan. Membaca konfigurasi Signing Method dan kunci-kunci yang diperlukan.

Parameters:

  • config: pointer ke struct JWTConfig yang berisi preferensi signing dan kunci

Returns:

  • *JWTManager: instance manager yang siap digunakan
  • error: error jika parsing kunci gagal atau konfigurasi tidak valid

func (*JWTManager) GenerateAccessToken

func (m *JWTManager) GenerateAccessToken(userID string, email string, sessionID string, extraClaims map[string]interface{}) (string, error)

GenerateAccessToken membuat access token JWT baru untuk user dengan expiry yang sudah dikonfigurasi. Token ditandatangani menggunakan metode dan kunci yang aktif saat ini.

Parameters:

  • userID: ID unik pengguna (disimpan dalam claim 'sub')
  • email: email pengguna (disimpan dalam claim 'email')
  • sessionID: ID unik sesi (disimpan dalam claim 'sid')
  • extraClaims: map tambahan claims custom yang ingin dimasukkan

Returns:

  • string: signed JWT string
  • error: error jika signing gagal

func (*JWTManager) GenerateRefreshToken

func (m *JWTManager) GenerateRefreshToken(userID, sessionID string) (string, error)

GenerateRefreshToken membuat refresh token JWT baru untuk user dengan expiry lebih panjang. Digunakan untuk mendapatkan access token baru tanpa login ulang.

Parameters:

  • userID: ID unik pengguna (disimpan dalam claim 'sub')
  • sessionID: ID unik sesi (disimpan dalam claim 'sid')

Returns:

  • string: signed JWT string
  • error: error jika signing gagal

func (*JWTManager) GetTokenExpiry

func (m *JWTManager) GetTokenExpiry(tokenString string) (time.Time, error)

GetTokenExpiry mengembalikan waktu expiry dari token. Berguna untuk pengecekan sisi client atau logika refresh otomatis.

Parameters:

  • tokenString: raw JWT string

Returns:

  • time.Time: waktu kapan token tersebut expired
  • error: error jika parsing token gagal

func (*JWTManager) IsTokenExpired

func (m *JWTManager) IsTokenExpired(tokenString string) (bool, error)

IsTokenExpired mengecek apakah token sudah expired atau tidak.

Parameters:

  • tokenString: JWT token string

Returns:

  • bool: true jika token sudah expired, false jika masih valid
  • error: error jika parse token gagal

Example:

isExpired, err := manager.IsTokenExpired(tokenString)
if isExpired {
  // get new token
}

func (*JWTManager) VerifyRefreshToken

func (m *JWTManager) VerifyRefreshToken(tokenString string) (string, string, error)

VerifyRefreshToken memverifikasi refresh token dan mengembalikan userID dan sessionID. Memastikan token valid dan belum kedaluwarsa.

Parameters:

  • tokenString: raw JWT string

Returns:

  • string: userID yang tersimpan dalam claim 'sub'
  • string: sessionID yang tersimpan dalam claim 'sid'
  • error: error jika token tidak valid

func (*JWTManager) VerifyToken

func (m *JWTManager) VerifyToken(tokenString string) (jwt.MapClaims, error)

VerifyToken memverifikasi access token dan mengembalikan claims di dalamnya. Mendukung rotasi kunci melalui header 'kid'.

Parameters:

  • tokenString: raw JWT string yang diterima dari client

Returns:

  • jwt.MapClaims: klaim-klaim yang ada di dalam token jika valid
  • error: error jika signature tidak valid, token kedaluwarsa, atau format salah

type JsonNull

type JsonNull[T any] = jsonull.JsonNull[T]

JsonNull represents a nullable value that distinguishes between: - Field not present in JSON (Present=false) - Field explicitly set to null (Present=true, Valid=false) - Field with a value (Present=true, Valid=true)

This is useful for partial updates in PATCH endpoints where you need to distinguish between "don't update this field" vs "set this field to null" vs "set this field to a new value".

func JsonNullFromPtr

func JsonNullFromPtr[T any](ptr *T) JsonNull[T]

JsonNullFromPtr converts a pointer to JsonNull. nil pointer becomes null, non-nil becomes valid value

func NewJsonNull

func NewJsonNull[T any](value T) JsonNull[T]

NewJsonNull creates a JsonNull with a valid value

func NewJsonNullNull

func NewJsonNullNull[T any]() JsonNull[T]

NewJsonNullNull creates a JsonNull representing an explicit null

type Logger

type Logger struct {
	*slog.Logger
}

Logger is a wrapper around slog.Logger for structured logging

func NewLogger

func NewLogger(level slog.Level) *Logger

NewLogger membuat logger baru dengan JSON output format dan specified log level. Output dikirim ke stdout (os.Stdout). Gunakan untuk structured logging dalam JSON format yang bisa di-parse oleh log aggregation tools.

Parameters:

  • level: slog.Level untuk minimum log level (LevelDebug, LevelInfo, LevelWarn, LevelError)

Returns:

  • *Logger: logger instance dengan JSON handler

Example:

logger := NewLogger(slog.LevelInfo)
logger.Info("User login", "user_id", 123, "email", "[email protected]")

func NewLoggerWithWriter

func NewLoggerWithWriter(w io.Writer, level slog.Level) *Logger

NewLoggerWithWriter membuat logger baru dengan JSON output format dan custom writer. Berguna untuk logging ke file, buffer, atau custom destinations. Output di-encode sebagai JSON untuk structured logging.

Parameters:

  • w: io.Writer untuk output destination (file, buffer, etc)
  • level: slog.Level untuk minimum log level

Returns:

  • *Logger: logger instance dengan JSON handler dan custom writer

Example:

file, _ := os.Create("app.log")
logger := NewLoggerWithWriter(file, slog.LevelInfo)
logger.Info("Application started")

func NewTextLogger

func NewTextLogger(level slog.Level) *Logger

NewTextLogger membuat logger baru dengan text output format dan specified log level. Output dikirim ke stdout (os.Stdout) dalam human-readable text format. Gunakan untuk development environment atau ketika structured JSON tidak diperlukan.

Parameters:

  • level: slog.Level untuk minimum log level

Returns:

  • *Logger: logger instance dengan text handler

Example:

logger := NewTextLogger(slog.LevelDebug)
logger.Debug("Debug information", "key", "value")

func NewTextLoggerWithWriter

func NewTextLoggerWithWriter(w io.Writer, level slog.Level) *Logger

NewTextLoggerWithWriter membuat logger baru dengan text output format dan custom writer. Output dalam human-readable text format ke specified writer. Berguna untuk logging ke file dalam text format.

Parameters:

  • w: io.Writer untuk output destination
  • level: slog.Level untuk minimum log level

Returns:

  • *Logger: logger instance dengan text handler dan custom writer

Example:

file, _ := os.Create("app.log")
logger := NewTextLoggerWithWriter(file, slog.LevelInfo)
logger.Info("User registered", "email", "[email protected]")

func (*Logger) Debug

func (l *Logger) Debug(msg string, args ...any)

Debug menulis debug-level log message dengan optional key-value attributes. Debug level digunakan untuk detailed debugging information. Hanya ditampilkan jika logger level di-set ke LevelDebug. Arguments adalah variadic key-value pairs untuk debugging context.

Parameters:

  • msg: debug message string
  • args: variadic arguments (key-value pairs)

Example:

logger.Debug("Processing request", "method", "GET", "path", "/users/123")

func (*Logger) Error

func (l *Logger) Error(msg string, args ...any)

Error menulis error-level log message dengan optional key-value attributes. Error level digunakan untuk error messages yang perlu attention. Arguments adalah variadic key-value pairs untuk additional context.

Parameters:

  • msg: error message string
  • args: variadic arguments (key-value pairs)

Example:

logger.Error("Database connection failed", "error", err, "retry_count", 3)

func (*Logger) Info

func (l *Logger) Info(msg string, args ...any)

Info menulis info-level log message dengan optional key-value attributes. Info level digunakan untuk general informational messages (login, request, etc). Arguments adalah variadic key-value pairs (key1, value1, key2, value2, ...).

Parameters:

  • msg: log message string
  • args: variadic arguments (key-value pairs)

Example:

logger.Info("User login successful", "user_id", 123, "ip", "192.168.1.1")

func (*Logger) Warn

func (l *Logger) Warn(msg string, args ...any)

Warn menulis warn-level log message dengan optional key-value attributes. Warn level digunakan untuk warning messages tentang non-critical issues. Arguments adalah variadic key-value pairs untuk additional context.

Parameters:

  • msg: warning message string
  • args: variadic arguments (key-value pairs)

Example:

logger.Warn("High memory usage detected", "usage_percent", 85.5)

func (*Logger) WithAttrs

func (l *Logger) WithAttrs(attrs ...slog.Attr) *Logger

WithAttrs returns a new logger with the attributes added

func (*Logger) WithGroup

func (l *Logger) WithGroup(name string) *Logger

WithGroup returns a new logger with a group added to attributes

type LoginRequest

type LoginRequest struct {
	Email    string
	Password string
}

LoginRequest merepresentasikan data yang dibutuhkan untuk login.

type MakeMigrationCommand

type MakeMigrationCommand struct {
	// contains filtered or unexported fields
}

MakeMigrationCommand generates a new migration file

func (*MakeMigrationCommand) DefineFlags

func (c *MakeMigrationCommand) DefineFlags(fs *flag.FlagSet)

func (*MakeMigrationCommand) Description

func (c *MakeMigrationCommand) Description() string

func (*MakeMigrationCommand) Execute

func (c *MakeMigrationCommand) Execute(ctx *CommandContext) error

func (*MakeMigrationCommand) Name

func (c *MakeMigrationCommand) Name() string

type MiddlewareFunc

type MiddlewareFunc func(HandlerFunc) HandlerFunc

MiddlewareFunc is a function that wraps a handler with middleware

func AllowBearerToken

func AllowBearerToken() MiddlewareFunc

AllowBearerToken adalah middleware pasif yang tidak melakukan apa-apa. Tujuannya adalah untuk secara eksplisit menandai sebuah rute yang memperbolehkan header Authorization, meskipun tidak divalidasi di tingkat middleware. Penggunaannya sangat jarang dan untuk kasus yang sangat spesifik.

func CORS

func CORS(config CORSConfig) MiddlewareFunc

CORS membuat middleware yang handle Cross-Origin Resource Sharing (CORS). Middleware ini set CORS headers untuk allow cross-origin requests dari specified origins. Support preflight requests (OPTIONS method) dan credential requests. Origin checking dilakukan dengan exact match atau wildcard (*).

Parameters:

  • config: CORSConfig yang berisi allowed origins, methods, headers, credentials setting

Returns:

  • MiddlewareFunc: middleware function yang handle CORS

Example:

corsConfig := CORSConfig{
  AllowedOrigins: []string{"https://example.com", "https://app.example.com"},
  AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
  AllowedHeaders: []string{"Content-Type", "Authorization"},
  AllowCredentials: true,
  MaxAge: 3600,
}
router.Use(CORS(corsConfig))

func CSRFMiddleware

func CSRFMiddleware(config CSRFConfig) MiddlewareFunc

CSRFMiddleware membuat middleware yang handle CSRF (Cross-Site Request Forgery) protection. Middleware ini verify CSRF token untuk unsafe HTTP methods (POST, PUT, DELETE, PATCH). Safe methods (GET, HEAD, OPTIONS) dan exempt paths di-skip dari CSRF check. Token divalidasi dengan membandingkan value dari header/form dengan value dari cookie. Mengembalikan 403 Forbidden jika token tidak valid atau tidak match.

Parameters:

  • config: CSRFConfig yang berisi enabled status, header name, cookie name, exempt paths

Returns:

  • MiddlewareFunc: middleware function yang handle CSRF protection

Example:

csrfConfig := CSRFConfig{
  Enabled: true,
  HeaderName: "X-CSRF-Token",
  CookieName: "_csrf",
  ExemptPaths: []string{"/api/public/*"},
}
router.Use(CSRFMiddleware(csrfConfig))

func ChainMiddleware

func ChainMiddleware(middleware ...MiddlewareFunc) MiddlewareFunc

ChainMiddleware membuat MiddlewareFunc dari multiple middleware tanpa final handler. Berguna untuk membuat reusable middleware chain yang bisa diterapkan ke multiple routes. Return value adalah MiddlewareFunc yang bisa digunakan di route registration.

Parameters:

  • middleware: variadic list dari MiddlewareFunc yang akan di-chain

Returns:

  • MiddlewareFunc: middleware function yang combine semua middleware

Example:

authChain := ChainMiddleware(AuthMiddleware, LoggerMiddleware)
router.Get("/users", getUsersHandler, authChain)

func Compose

func Compose(middleware ...MiddlewareFunc) MiddlewareFunc

Compose membuat middleware baru dari multiple middleware functions. Similar dengan Chain tetapi return MiddlewareFunc dan dapat digunakan sebagai single middleware. Berguna untuk membuat composite middleware yang dapat di-reuse di berbagai places.

Parameters:

  • middleware: variadic list dari MiddlewareFunc yang akan di-compose

Returns:

  • MiddlewareFunc: composed middleware function

Example:

authAndLog := Compose(AuthMiddleware, LoggerMiddleware)
router.Get("/protected", handler, authAndLog)

func ExpectBearerToken

func ExpectBearerToken() MiddlewareFunc

ExpectBearerToken adalah middleware yang hanya memeriksa keberadaan header `Authorization: Bearer <token>`. **TIDAK AMAN**: Middleware ini TIDAK memverifikasi validitas token itu sendiri. Gunakan ini hanya untuk kasus penggunaan lanjutan di mana verifikasi dilakukan secara manual di tempat lain. Untuk keamanan, selalu prioritaskan penggunaan `RequireAuth`.

func HandlerToMiddleware

func HandlerToMiddleware(h http.Handler) MiddlewareFunc

HandlerToMiddleware mengkonversi http.Handler menjadi MiddlewareFunc. Memungkinkan penggunaan standard http.Handler implementations sebagai middleware. Berguna untuk integrasi dengan third-party packages yang implement http.Handler.

Parameters:

  • h: http.Handler yang akan dikonversi menjadi middleware

Returns:

  • MiddlewareFunc: middleware function yang membungkus http.Handler

Example:

corsHandler := HandlerToMiddleware(corsStandardHandler)
router.Use(corsHandler)

func LoggerMiddleware

func LoggerMiddleware(logger *Logger) MiddlewareFunc

LoggerMiddleware membuat middleware yang log HTTP requests dan responses. Middleware ini: 1. Generate unique request ID dan set di context untuk request tracing 2. Wrap response writer untuk capture response status code 3. Measure request duration 4. Log request details termasuk method, path, status code, dan duration Berguna untuk debugging, monitoring, dan audit trail.

Parameters:

  • logger: *Logger untuk menulis log entries

Returns:

  • MiddlewareFunc: middleware function yang log request/response

Example:

logger := NewLogger(slog.LevelInfo)
router.Use(LoggerMiddleware(logger))
// Log output: time=... level=INFO msg="request completed" request_id=abc123 method=GET path=/users status=200 duration_ms=45

func OptionalAuth

func OptionalAuth(jwtManager *JWTManager) MiddlewareFunc

OptionalAuth (sebelumnya OptionalAuthWithManager) adalah middleware yang aman dan direkomendasikan untuk secara opsional memverifikasi token JWT jika ada. Middleware ini tidak akan gagal jika token tidak ada atau tidak valid. Jika token valid, info pengguna akan ditempatkan di konteks. Berguna untuk endpoint yang mendukung konteks pengguna opsional.

Parameters:

  • jwtManager: *JWTManager untuk verifikasi token.

Returns:

  • MiddlewareFunc: Middleware yang memungkinkan autentikasi opsional dengan verifikasi.

Example:

router.Get("/semi-protected", handler, OptionalAuth(jwtManager))
// Di dalam handler: user, ok := GetUser(req); if ok { /* authenticated */ }

func RateLimit

func RateLimit(config RateLimitConfig, store ...RateLimitStore) MiddlewareFunc

RateLimit membuat middleware yang menerapkan pembatasan kecepatan (rate limiting). Middleware ini mencegah penyalahgunaan API dengan membatasi jumlah request per IP atau per User.

Parameters:

  • config: Struct RateLimitConfig yang berisi aturan limit.
  • store: (Opsional) Backend storage custom via variadic parameter. Jika kosong, menggunakan InMemoryRateLimitStore. Gunakan NewPostgresRateLimitStore(db) untuk persistensi database.

Returns:

  • MiddlewareFunc: Middleware function untuk router.

Example:

// Default In-Memory
router.Use(dim.RateLimit(config))

// Dengan Postgres Store
store := dim.NewPostgresRateLimitStore(db)
router.Use(dim.RateLimit(config, store))

func Recovery

func Recovery(logger *Logger) MiddlewareFunc

Recovery membuat middleware yang recover dari panics dan log mereka. Middleware ini: 1. Catch panic yang terjadi di handler atau downstream middleware 2. Log panic error dengan request details (path, method) untuk debugging 3. Return 500 Internal Server Error response ke client 4. Prevent application crash dan memastikan graceful error handling Berguna untuk production safety dan error monitoring.

Parameters:

  • logger: *Logger untuk menulis panic error logs

Returns:

  • MiddlewareFunc: middleware function yang recover dari panics

Example:

logger := NewLogger(slog.LevelError)
router.Use(Recovery(logger))
// Jika ada panic di handler, akan logged dan 500 response dikirim ke client

func RequireAuth

func RequireAuth(jwtManager *JWTManager, blocklist TokenBlocklist) MiddlewareFunc

RequireAuth adalah middleware yang aman dan direkomendasikan untuk mewajibkan dan memverifikasi token JWT yang valid. Middleware ini menggunakan JWTManager untuk memvalidasi token dan menempatkan info pengguna ke dalam konteks. Juga dapat mengecek TokenBlocklist jika disediakan (opsional). Mengembalikan 401 Unauthorized jika token tidak ada, tidak valid, atau kedaluwarsa.

Parameters:

  • jwtManager: *JWTManager untuk verifikasi token.
  • blocklist: TokenBlocklist interface (opsional, pass nil jika tidak digunakan).

Returns:

  • MiddlewareFunc: Middleware yang memberlakukan autentikasi aman.

Example:

router.Get("/protected", handler, RequireAuth(jwtManager, blocklist))
// Di dalam handler, gunakan GetUser(req) untuk mendapatkan pengguna yang terautentikasi.

type MigrateCommand

type MigrateCommand struct {
	// contains filtered or unexported fields
}

MigrateCommand menjalankan semua pending database migrations.

func (*MigrateCommand) DefineFlags

func (c *MigrateCommand) DefineFlags(fs *flag.FlagSet)

func (*MigrateCommand) Description

func (c *MigrateCommand) Description() string

func (*MigrateCommand) Execute

func (c *MigrateCommand) Execute(ctx *CommandContext) error

func (*MigrateCommand) Name

func (c *MigrateCommand) Name() string

type MigrateListCommand

type MigrateListCommand struct{}

MigrateListCommand menampilkan status semua migrations (applied dan pending).

func (*MigrateListCommand) Description

func (c *MigrateListCommand) Description() string

func (*MigrateListCommand) Execute

func (c *MigrateListCommand) Execute(ctx *CommandContext) error

func (*MigrateListCommand) Name

func (c *MigrateListCommand) Name() string

type MigrateRollbackCommand

type MigrateRollbackCommand struct {
	// contains filtered or unexported fields
}

MigrateRollbackCommand membatalkan migration yang sudah dijalankan.

func (*MigrateRollbackCommand) DefineFlags

func (c *MigrateRollbackCommand) DefineFlags(fs *flag.FlagSet)

func (*MigrateRollbackCommand) Description

func (c *MigrateRollbackCommand) Description() string

func (*MigrateRollbackCommand) Execute

func (c *MigrateRollbackCommand) Execute(ctx *CommandContext) error

func (*MigrateRollbackCommand) Name

func (c *MigrateRollbackCommand) Name() string

type Migration

type Migration struct {
	Version int64
	Name    string
	Up      func(*pgxpool.Pool) error
	Down    func(*pgxpool.Pool) error
}

Migration represents a single migration

func GetFrameworkMigrations

func GetFrameworkMigrations() []Migration

GetFrameworkMigrations mengembalikan semua migrasi bawaan framework dim (User, Token, RateLimit). Migrasi ini mencakup tabel-tabel inti yang diperlukan oleh fitur-fitur framework. Urutan versi: 1. Users 2. Refresh Tokens 3. Password Reset Tokens 4. Token Blocklist 5. Rate Limits

func GetRateLimitMigrations

func GetRateLimitMigrations() []Migration

GetRateLimitMigrations mengembalikan daftar migrasi terkait rate limit. Dimulai dari versi 5 (melanjutkan token migrations).

func GetRegisteredMigrations

func GetRegisteredMigrations() []Migration

GetRegisteredMigrations mengembalikan semua migration yang terdaftar via Register(). Migration akan otomatis diurutkan berdasarkan Version.

func GetTokenMigrations

func GetTokenMigrations() []Migration

GetTokenMigrations mengembalikan daftar migrasi terkait token (refresh, reset, blocklist). Dimulai dari versi 2 (asumsi versi 1 adalah users).

func GetUserMigrations

func GetUserMigrations() []Migration

GetUserMigrations mengembalikan daftar migrasi terkait tabel users. Mencakup pembuatan tabel users dasar.

type MigrationHistory

type MigrationHistory struct {
	Version int64
	Name    string
}

MigrationHistory represents the migration history table

type MockTokenStore

type MockTokenStore struct {
	// contains filtered or unexported fields
}

MockTokenStore is a mock implementation for testing

func NewMockTokenStore

func NewMockTokenStore() *MockTokenStore

NewMockTokenStore membuat mock token store untuk testing. Mock store menyimpan tokens dalam memory dan cocok untuk unit tests.

Returns:

  • *MockTokenStore: mock store instance dengan empty token maps

Example:

mockStore := NewMockTokenStore()
// use in tests

func (*MockTokenStore) FindPasswordResetToken

func (s *MockTokenStore) FindPasswordResetToken(ctx context.Context, tokenHash string) (*PasswordResetToken, error)

FindPasswordResetToken mencari password reset token dalam mock store.

Parameters:

  • ctx: context (tidak digunakan dalam mock)
  • tokenHash: hash dari reset token yang akan dicari

Returns:

  • *PasswordResetToken: token jika ditemukan, nil jika tidak
  • error: error message jika token tidak ditemukan

Example:

token, err := mockStore.FindPasswordResetToken(ctx, tokenHash)

func (*MockTokenStore) FindRefreshToken

func (s *MockTokenStore) FindRefreshToken(ctx context.Context, tokenHash string) (*RefreshToken, error)

FindRefreshToken mencari refresh token dalam mock store.

Parameters:

  • ctx: context (tidak digunakan dalam mock)
  • tokenHash: hash dari token yang akan dicari

Returns:

  • *RefreshToken: token jika ditemukan, nil jika tidak
  • error: error message jika token tidak ditemukan

Example:

token, err := mockStore.FindRefreshToken(ctx, tokenHash)

func (*MockTokenStore) MarkPasswordResetUsed

func (s *MockTokenStore) MarkPasswordResetUsed(ctx context.Context, tokenHash string) error

MarkPasswordResetUsed menandai password reset token sebagai used dalam mock store.

Parameters:

  • ctx: context (tidak digunakan dalam mock)
  • tokenHash: hash dari reset token yang akan ditandai as used

Returns:

  • error: selalu nil untuk mock

Example:

err := mockStore.MarkPasswordResetUsed(ctx, tokenHash)

func (*MockTokenStore) RevokeAllUserTokens

func (s *MockTokenStore) RevokeAllUserTokens(ctx context.Context, userID string) error

RevokeAllUserTokens membatalkan semua tokens user dalam mock store.

Parameters:

  • ctx: context (tidak digunakan dalam mock)
  • userID: ID dari user yang semua token-nya akan di-revoke

Returns:

  • error: selalu nil untuk mock

Example:

err := mockStore.RevokeAllUserTokens(ctx, userID)

func (*MockTokenStore) RevokeRefreshToken

func (s *MockTokenStore) RevokeRefreshToken(ctx context.Context, tokenHash string) error

RevokeRefreshToken membatalkan refresh token dalam mock store.

Parameters:

  • ctx: context (tidak digunakan dalam mock)
  • tokenHash: hash dari token yang akan di-revoke

Returns:

  • error: selalu nil untuk mock

Example:

err := mockStore.RevokeRefreshToken(ctx, tokenHash)

func (*MockTokenStore) SavePasswordResetToken

func (s *MockTokenStore) SavePasswordResetToken(ctx context.Context, token *PasswordResetToken) error

SavePasswordResetToken menyimpan password reset token dalam mock store.

Parameters:

  • ctx: context (tidak digunakan dalam mock)
  • token: PasswordResetToken struct yang akan disimpan

Returns:

  • error: selalu nil untuk mock

Example:

err := mockStore.SavePasswordResetToken(ctx, &token)

func (*MockTokenStore) SaveRefreshToken

func (s *MockTokenStore) SaveRefreshToken(ctx context.Context, token *RefreshToken) error

SaveRefreshToken menyimpan refresh token dalam mock store (memory).

Parameters:

  • ctx: context (tidak digunakan dalam mock)
  • token: RefreshToken struct yang akan disimpan

Returns:

  • error: selalu nil untuk mock

Example:

err := mockStore.SaveRefreshToken(ctx, &token)

type Observable

type Observable interface {
	AddHook(hook QueryHook)
}

Observable defines specific interface for adding observability hooks

type Pagination

type Pagination struct {
	Page  int `json:"page"`
	Limit int `json:"limit"`
}

Pagination struct holds the pagination details

func (*Pagination) Offset

func (p *Pagination) Offset() int

Offset returns the SQL offset

type PaginationMeta

type PaginationMeta struct {
	Page       int `json:"page"`
	PerPage    int `json:"per_page"`
	Total      int `json:"total"`
	TotalPages int `json:"total_pages"`
}

PaginationMeta contains pagination information

type PaginationParser

type PaginationParser struct {
	DefaultLimit int
	MaxLimit     int
}

PaginationParser parses pagination parameters

func NewPaginationParser

func NewPaginationParser(defaultLimit, maxLimit int) *PaginationParser

NewPaginationParser creates a new PaginationParser

func (*PaginationParser) Parse

func (p *PaginationParser) Parse(r *http.Request) (*Pagination, error)

Parse parses page[number] and page[size] Also supports page and limit/size query params as fallback or standard simple pagination

type PaginationResponse

type PaginationResponse struct {
	Data interface{}    `json:"data"`
	Meta PaginationMeta `json:"meta"`
}

PaginationResponse is the response structure for paginated data

type PasswordResetToken

type PasswordResetToken struct {
	ID        int64      `json:"id"`
	UserID    string     `json:"user_id"`
	TokenHash string     `json:"-"`
	ExpiresAt time.Time  `json:"expires_at"`
	UsedAt    *time.Time `json:"used_at,omitempty"`
	CreatedAt time.Time  `json:"created_at"`
}

PasswordResetToken represents a password reset token entity

type PasswordValidator

type PasswordValidator struct {
	// contains filtered or unexported fields
}

PasswordValidator provides password validation utilities

func NewPasswordValidator

func NewPasswordValidator() *PasswordValidator

NewPasswordValidator membuat PasswordValidator baru dengan default settings. Default settings: minLength=8, require uppercase, lowercase, digit, dan special char.

Returns:

  • *PasswordValidator: validator instance dengan default rules

Example:

validator := NewPasswordValidator()
err := validator.Validate(password)

func (*PasswordValidator) RequireDigit

func (pv *PasswordValidator) RequireDigit(required bool) *PasswordValidator

RequireDigit sets whether digits are required

func (*PasswordValidator) RequireLowercase

func (pv *PasswordValidator) RequireLowercase(required bool) *PasswordValidator

RequireLowercase sets whether lowercase letters are required

func (*PasswordValidator) RequireSpecial

func (pv *PasswordValidator) RequireSpecial(required bool) *PasswordValidator

RequireSpecial sets whether special characters are required

func (*PasswordValidator) RequireUppercase

func (pv *PasswordValidator) RequireUppercase(required bool) *PasswordValidator

RequireUppercase sets whether uppercase letters are required

func (*PasswordValidator) SetMinLength

func (pv *PasswordValidator) SetMinLength(length int) *PasswordValidator

SetMinLength sets the minimum password length

func (*PasswordValidator) Validate

func (pv *PasswordValidator) Validate(password string) error

Validate memvalidasi password terhadap semua configured rules. Return error dengan detail field error jika validasi gagal.

Parameters:

  • password: password string yang akan divalidasi

Returns:

  • error: AppError dengan field errors jika ada rule yang tidak terpenuhi

Example:

err := validator.Validate("MyPassword123!")
if err != nil {
  // handle validation error
}

type PostgresBlocklist

type PostgresBlocklist struct {
	// contains filtered or unexported fields
}

PostgresBlocklist implementasi TokenBlocklist menggunakan PostgreSQL UNLOGGED Table. Cocok untuk production & multi-instance deployment.

func NewPostgresBlocklist

func NewPostgresBlocklist(db Database) *PostgresBlocklist

NewPostgresBlocklist membuat instance baru PostgresBlocklist.

func (*PostgresBlocklist) Cleanup

func (p *PostgresBlocklist) Cleanup(ctx context.Context) error

Cleanup menghapus token yang sudah expired dari database. Sebaiknya dijalankan sebagai cron job atau background task.

func (*PostgresBlocklist) InitSchema

func (p *PostgresBlocklist) InitSchema(ctx context.Context) error

InitSchema membuat tabel UNLOGGED 'token_blocklist' jika belum ada. UNLOGGED table tidak ditulis ke WAL (Write Ahead Log), performa lebih cepat (seperti Redis) dengan tradeoff data hilang jika DB crash (yang acceptable untuk cache/blocklist).

func (*PostgresBlocklist) Invalidate

func (p *PostgresBlocklist) Invalidate(ctx context.Context, identifier string, expiresIn time.Duration) error

func (*PostgresBlocklist) IsRevoked

func (p *PostgresBlocklist) IsRevoked(ctx context.Context, identifier string) (bool, error)

type PostgresDatabase

type PostgresDatabase struct {
	// contains filtered or unexported fields
}

PostgresDatabase is the PostgreSQL implementation of Database interface It supports read/write connection splitting with load balancing on read connections

func NewPostgresDatabase

func NewPostgresDatabase(config DatabaseConfig) (*PostgresDatabase, error)

NewPostgresDatabase membuat koneksi database PostgreSQL baru dengan mendukung read/write splitting. Membuat write pool untuk operasi INSERT/UPDATE/DELETE dan read pools untuk operasi SELECT. Jika tidak ada read hosts yang dikonfigurasi, menggunakan write pool untuk reads.

Parameters:

  • config: DatabaseConfig berisi konfigurasi koneksi database

Returns:

  • *PostgresDatabase: instance database yang siap digunakan
  • error: error jika gagal membuat connection pool

Example:

db, err := NewPostgresDatabase(config)
if err != nil {
  log.Fatal(err)
}

func (*PostgresDatabase) AddHook

func (db *PostgresDatabase) AddHook(hook QueryHook)

AddHook adds a new query hook to the database. Thread-safe.

func (*PostgresDatabase) Begin

func (db *PostgresDatabase) Begin(ctx context.Context) (pgx.Tx, error)

Begin memulai transaction baru di write connection. Semua transaction selalu dibuat di write pool untuk consistency.

Parameters:

  • ctx: context untuk membatalkan operasi

Returns:

  • pgx.Tx: transaction object yang bisa digunakan untuk execute queries
  • error: error jika gagal membuat transaction

Example:

tx, err := db.Begin(ctx)
if err != nil {
  return err
}
defer tx.Rollback(ctx)

func (*PostgresDatabase) Close

func (db *PostgresDatabase) Close() error

Close menutup semua connection pools (write dan read). Harus dipanggil sebelum aplikasi shutdown untuk cleanup yang proper.

Returns:

  • error: selalu nil, tapi disediakan untuk compatibility dengan interface

Example:

defer db.Close()

func (*PostgresDatabase) Exec

func (db *PostgresDatabase) Exec(ctx context.Context, query string, args ...interface{}) error

Exec mengeksekusi write query (INSERT, UPDATE, DELETE) ke write connection pool. Semua operasi write selalu dikirim ke write pool untuk consistency. Gunakan sticky mode jika perlu subsequent reads ke write connection yang sama.

Parameters:

  • ctx: context untuk membatalkan operasi
  • query: SQL query untuk dieksekusi
  • args: parameter untuk query

Returns:

  • error: error jika query execution gagal

Example:

err := db.Exec(ctx, "INSERT INTO users (email, name) VALUES ($1, $2)", email, name)

func (*PostgresDatabase) Query

func (db *PostgresDatabase) Query(ctx context.Context, query string, args ...interface{}) (Rows, error)

Query mengeksekusi read query (SELECT) dengan routing based on sticky mode. Menggunakan decision tree untuk menentukan pool mana yang digunakan: 1. Jika query adalah write operation, route ke write pool 2. Jika sticky mode enabled dan ada write dalam request, route ke write pool 3. Otherwise: route ke read pool dengan round-robin load balancing

Parameters:

  • ctx: context untuk membatalkan operasi
  • query: SQL SELECT query
  • args: parameter untuk query

Returns:

  • Rows: result set dari query
  • error: error jika query execution gagal

Example:

rows, err := db.Query(ctx, "SELECT id, email FROM users WHERE id = $1", userID)

func (*PostgresDatabase) QueryRow

func (db *PostgresDatabase) QueryRow(ctx context.Context, query string, args ...interface{}) Row

QueryRow mengeksekusi read query yang mengembalikan single row dengan routing based on sticky mode. Menggunakan decision tree yang sama dengan Query untuk menentukan pool mana yang digunakan.

Parameters:

  • ctx: context untuk membatalkan operasi
  • query: SQL SELECT query
  • args: parameter untuk query

Returns:

  • Row: single row result yang bisa di-scan

Example:

err := db.QueryRow(ctx, "SELECT email FROM users WHERE id = $1", userID).Scan(&email)

func (*PostgresDatabase) WithTx

WithTx mengeksekusi function dalam transaction dengan auto rollback/commit. Jika fn return error, transaction di-rollback. Jika sukses, transaction di-commit.

Parameters:

  • ctx: context untuk membatalkan operasi
  • fn: function yang berisi query operations dalam transaction

Returns:

  • error: error dari fn execution atau commit/rollback

Example:

err := db.WithTx(ctx, func(ctx context.Context, tx pgx.Tx) error {
  return tx.Exec(ctx, "INSERT INTO users VALUES ($1)", email)
})

type PostgresRateLimitStore

type PostgresRateLimitStore struct {
	// contains filtered or unexported fields
}

PostgresRateLimitStore mengimplementasikan RateLimitStore menggunakan PostgreSQL. Cocok untuk deployment multi-instance/cluster. Menggunakan tabel UNLOGGED untuk performa tinggi (data hilang saat crash dapat diterima untuk rate limits).

func NewPostgresRateLimitStore

func NewPostgresRateLimitStore(db Database) *PostgresRateLimitStore

NewPostgresRateLimitStore membuat store rate limit PostgreSQL baru.

Parameters:

  • db: koneksi database yang mengimplementasikan interface Database

func (*PostgresRateLimitStore) Allow

func (s *PostgresRateLimitStore) Allow(ctx context.Context, key string, limit int, window time.Duration) (bool, error)

Allow mengecek dan menaikkan limit menggunakan Atomic UPSERT di PostgreSQL.

func (*PostgresRateLimitStore) Close

func (s *PostgresRateLimitStore) Close() error

Close menutup koneksi (no-op untuk implementasi ini karena DB dikelola di luar).

func (*PostgresRateLimitStore) InitSchema

func (s *PostgresRateLimitStore) InitSchema(ctx context.Context) error

InitSchema membuat tabel yang diperlukan untuk rate limiting. Sebaiknya dipanggil saat startup aplikasi atau migrasi.

type PostgresTokenStore

type PostgresTokenStore struct {
	// contains filtered or unexported fields
}

PostgresTokenStore is the PostgreSQL implementation of TokenStore

func NewPostgresTokenStore

func NewPostgresTokenStore(db Database) *PostgresTokenStore

NewPostgresTokenStore membuat PostgreSQL token store baru. Store ini menangani operasi CRUD untuk refresh tokens dan password reset tokens.

Parameters:

  • db: Database instance untuk execute queries

Returns:

  • *PostgresTokenStore: token store instance

Example:

tokenStore := NewPostgresTokenStore(db)

func (*PostgresTokenStore) FindPasswordResetToken

func (s *PostgresTokenStore) FindPasswordResetToken(ctx context.Context, tokenHash string) (*PasswordResetToken, error)

FindPasswordResetToken mencari password reset token berdasarkan hash.

Parameters:

  • ctx: context untuk membatalkan operasi
  • tokenHash: hash dari reset token yang akan dicari

Returns:

  • *PasswordResetToken: PasswordResetToken struct jika ditemukan
  • error: error jika token tidak ditemukan atau query gagal

Example:

token, err := tokenStore.FindPasswordResetToken(ctx, tokenHash)

func (*PostgresTokenStore) FindRefreshToken

func (s *PostgresTokenStore) FindRefreshToken(ctx context.Context, tokenHash string) (*RefreshToken, error)

FindRefreshToken mencari refresh token berdasarkan hash.

Parameters:

  • ctx: context untuk membatalkan operasi
  • tokenHash: hash dari token yang akan dicari

Returns:

  • *RefreshToken: RefreshToken struct jika ditemukan
  • error: error jika token tidak ditemukan atau query gagal

Example:

token, err := tokenStore.FindRefreshToken(ctx, tokenHash)

func (*PostgresTokenStore) MarkPasswordResetUsed

func (s *PostgresTokenStore) MarkPasswordResetUsed(ctx context.Context, tokenHash string) error

MarkPasswordResetUsed menandai password reset token sudah digunakan dengan set used_at timestamp. Mencegah reuse dari token yang sama untuk reset password.

Parameters:

  • ctx: context untuk membatalkan operasi
  • tokenHash: hash dari reset token yang akan ditandai sebagai used

Returns:

  • error: error jika UPDATE query gagal

Example:

err := tokenStore.MarkPasswordResetUsed(ctx, tokenHash)

func (*PostgresTokenStore) RevokeAllUserTokens

func (s *PostgresTokenStore) RevokeAllUserTokens(ctx context.Context, userID string) error

RevokeAllUserTokens membatalkan semua refresh tokens milik pengguna tertentu. Berguna untuk security setelah password reset atau logout dari semua device.

Parameters:

  • ctx: context untuk membatalkan operasi
  • userID: ID dari user yang token-nya akan di-revoke

Returns:

  • error: error jika UPDATE query gagal

Example:

err := tokenStore.RevokeAllUserTokens(ctx, userID)

func (*PostgresTokenStore) RevokeRefreshToken

func (s *PostgresTokenStore) RevokeRefreshToken(ctx context.Context, tokenHash string) error

RevokeRefreshToken membatalkan/revoke refresh token dengan set revoked_at timestamp.

Parameters:

  • ctx: context untuk membatalkan operasi
  • tokenHash: hash dari token yang akan di-revoke

Returns:

  • error: error jika UPDATE query gagal

Example:

err := tokenStore.RevokeRefreshToken(ctx, tokenHash)

func (*PostgresTokenStore) SavePasswordResetToken

func (s *PostgresTokenStore) SavePasswordResetToken(ctx context.Context, token *PasswordResetToken) error

SavePasswordResetToken menyimpan password reset token ke database. Token disimpan dengan hash dan expiry time untuk password reset flow.

Parameters:

  • ctx: context untuk membatalkan operasi
  • token: PasswordResetToken struct dengan data yang akan disimpan

Returns:

  • error: error jika INSERT query gagal

Example:

err := tokenStore.SavePasswordResetToken(ctx, &resetToken)

func (*PostgresTokenStore) SaveRefreshToken

func (s *PostgresTokenStore) SaveRefreshToken(ctx context.Context, token *RefreshToken) error

SaveRefreshToken menyimpan refresh token ke database. Token disimpan dengan hash, user_agent, ip_address, dan expiry time.

Parameters:

  • ctx: context untuk membatalkan operasi
  • token: RefreshToken struct dengan data yang akan disimpan

Returns:

  • error: error jika INSERT query gagal

Example:

err := tokenStore.SaveRefreshToken(ctx, &refreshToken)

type QueryHook

type QueryHook func(ctx context.Context, query string, args []interface{}, duration time.Duration, err error)

QueryHook is a function that is called after a query execution.

type Range

type Range[T any] struct {
	From    T
	To      T
	Valid   bool // true if format is valid and has non-empty value and From <= To
	Present bool // true if parameter exists in request
}

Range represents a range of values with from and to bounds. Generic type supporting any comparable type for flexible range queries.

Fields:

  • From: Start value of range
  • To: End value of range
  • Valid: true if format is valid, range constraint (From <= To) satisfied, and non-empty
  • Present: true if parameter exists in request (even if Invalid)

Behavior:

  • Single value (e.g., "100") sets both From and To to same value
  • Range format (e.g., "100,500") sets From and To separately
  • Invalid format or From > To results in Valid=false but Present=true
  • Empty input results in Valid=false and Present=true

type RateLimitConfig

type RateLimitConfig struct {
	Enabled     bool
	PerIP       int
	PerUser     int
	ResetPeriod time.Duration
}

RateLimitConfig holds rate limiting configuration

type RateLimitStore

type RateLimitStore interface {
	// Allow mengecek apakah request diizinkan dan menaikkan counter.
	// Mengembalikan true jika diizinkan, false jika tidak.
	//
	// Parameters:
	//   - ctx: context untuk operasi
	//   - key: unique key untuk rate limit (misal: "ip:1.2.3.4")
	//   - limit: batas maksimum request
	//   - window: durasi waktu reset
	Allow(ctx context.Context, key string, limit int, window time.Duration) (bool, error)

	// Close membersihkan resource yang digunakan.
	Close() error
}

RateLimitStore mendefinisikan interface untuk backend penyimpanan rate limit. Memungkinkan pergantian antara InMemory (single instance) dan Postgres (multi-instance).

type RateLimiter

type RateLimiter struct {
	// contains filtered or unexported fields
}

RateLimiter menangani logika rate limiting dengan backend storage yang dapat dikonfigurasi. Memisahkan logika bisnis dari implementasi middleware.

func NewRateLimiter

func NewRateLimiter(config RateLimitConfig, store RateLimitStore) *RateLimiter

NewRateLimiter membuat instance RateLimiter baru.

Parameters:

  • config: Konfigurasi limit (PerIP, PerUser, ResetPeriod).
  • store: Backend storage (opsional). Jika nil, akan menggunakan InMemoryRateLimitStore default.

Returns:

  • *RateLimiter: Instance rate limiter yang siap digunakan.

Example:

// In-memory
limiter := NewRateLimiter(config, nil)

// Postgres
store := NewPostgresRateLimitStore(db)
limiter := NewRateLimiter(config, store)

func (*RateLimiter) CheckIPLimit

func (rl *RateLimiter) CheckIPLimit(ctx context.Context, ip string) (bool, error)

CheckIPLimit mengecek apakah IP dalam batas rate limit.

Parameters:

  • ctx: context untuk operasi
  • ip: alamat IP client

Returns:

  • bool: true jika diizinkan, false jika limit terlampaui
  • error: error dari storage backend

func (*RateLimiter) CheckUserLimit

func (rl *RateLimiter) CheckUserLimit(ctx context.Context, userKey string) (bool, error)

CheckUserLimit mengecek apakah user dalam batas rate limit.

Parameters:

  • ctx: context untuk operasi
  • userKey: unique identifier user (misal: "user:123")

Returns:

  • bool: true jika diizinkan, false jika limit terlampaui
  • error: error dari storage backend

type RefreshToken

type RefreshToken struct {
	ID        int64      `json:"id"`
	UserID    string     `json:"user_id"`
	TokenHash string     `json:"-"`
	UserAgent string     `json:"user_agent"`
	IPAddress string     `json:"ip_address"`
	ExpiresAt time.Time  `json:"expires_at"`
	CreatedAt time.Time  `json:"created_at"`
	RevokedAt *time.Time `json:"revoked_at,omitempty"`
}

RefreshToken represents a refresh token entity

type RouteInfo

type RouteInfo struct {
	Method      string   // HTTP method (GET, POST, dll)
	Path        string   // URL path pattern
	Handler     string   // Nama handler function
	Middlewares []string // Daftar nama middleware yang diterapkan
}

RouteInfo menyimpan informasi metadata tentang route yang terdaftar. Digunakan untuk introspeksi route (route:list command).

type RouteListCommand

type RouteListCommand struct{}

RouteListCommand menampilkan semua route yang terdaftar beserta handler dan middleware.

func (*RouteListCommand) Description

func (c *RouteListCommand) Description() string

func (*RouteListCommand) Execute

func (c *RouteListCommand) Execute(ctx *CommandContext) error

func (*RouteListCommand) Name

func (c *RouteListCommand) Name() string

type Router

type Router struct {
	// contains filtered or unexported fields
}

Router adalah router HTTP utama yang dibangun di atas stdlib http.ServeMux dengan dukungan middleware yang ditingkatkan.

func NewRouter

func NewRouter() *Router

NewRouter membuat instance router baru menggunakan stdlib http.ServeMux. Router mendukung pencocokan pola Go 1.22+ modern:

  • Route statis: /users
  • Parameter path: /users/{id}
  • Catch-all: /files/{path...}
  • Routing metode: GET /users/{id}

Mengembalikan:

  • *Router: instance router yang siap digunakan

Contoh:

router := NewRouter()
router.Get("/users/{id}", getUserHandler)
http.ListenAndServe(":8080", router)

func (*Router) Build

func (r *Router) Build()

Build membuild handler chain secara eksplisit. Disarankan dipanggil di main() sebelum http.ListenAndServe untuk performa terbaik (menghindari locking saat request). Jika tidak dipanggil, handler akan dibangun secara lazy pada request pertama (dengan sedikit overhead locking).

func (*Router) Delete

func (r *Router) Delete(path string, handler HandlerFunc, middleware ...MiddlewareFunc)

Delete mendaftarkan route DELETE dengan middleware spesifik route opsional.

Parameter:

  • path: path URL untuk route
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

router.Delete("/users/{id}", deleteUserHandler, AuthMiddleware)

func (*Router) Get

func (r *Router) Get(path string, handler HandlerFunc, middleware ...MiddlewareFunc)

Get mendaftarkan route GET dengan middleware spesifik route opsional. Path menggunakan pencocokan pola stdlib:

  • Statis: /users
  • Parameter: /users/{id}
  • Catch-all: /files/{path...}

Parameter:

  • path: path URL untuk route (contoh: /users, /users/{id}, /files/{path...})
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional yang diterapkan sebelum handler

Contoh:

router.Get("/users", getUsersHandler)
router.Get("/users/{id}", getUserHandler, AuthMiddleware)

func (*Router) GetRoutes

func (r *Router) GetRoutes() []RouteInfo

GetRoutes mengembalikan semua route yang terdaftar dengan caching. Thread-safe dan menggunakan in-memory cache untuk performa optimal.

Mengembalikan:

  • []RouteInfo: copy dari semua route yang terdaftar

Contoh:

routes := router.GetRoutes()
for _, route := range routes {
    fmt.Printf("%s %s -> %s\n", route.Method, route.Path, route.Handler)
}

func (*Router) Group

func (r *Router) Group(prefix string, middleware ...MiddlewareFunc) *RouterGroup

Group membuat RouterGroup baru dengan prefix dan middleware. RouterGroup memudahkan pengelompokan route dengan prefix dan middleware yang sama.

Parameter:

  • prefix: path prefix untuk semua route dalam grup
  • middleware: middleware level grup opsional yang diterapkan ke semua route

Mengembalikan:

  • *RouterGroup: instance grup router untuk menambahkan route

Contoh:

api := router.Group("/api", AuthMiddleware)
api.Get("/users", getUsersHandler)  // terdaftar sebagai GET /api/users

func (*Router) Head

func (r *Router) Head(path string, handler HandlerFunc, middleware ...MiddlewareFunc)

Head mendaftarkan route HEAD dengan middleware spesifik route opsional.

Parameter:

  • path: path URL untuk route
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

router.Head("/users", headHandler)

func (*Router) Options

func (r *Router) Options(path string, handler HandlerFunc, middleware ...MiddlewareFunc)

Options mendaftarkan route OPTIONS dengan middleware spesifik route opsional.

Parameter:

  • path: path URL untuk route
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

router.Options("/users", optionsHandler)

func (*Router) Patch

func (r *Router) Patch(path string, handler HandlerFunc, middleware ...MiddlewareFunc)

Patch mendaftarkan route PATCH dengan middleware spesifik route opsional.

Parameter:

  • path: path URL untuk route
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

router.Patch("/users/{id}", patchUserHandler, AuthMiddleware)

func (*Router) Post

func (r *Router) Post(path string, handler HandlerFunc, middleware ...MiddlewareFunc)

Post mendaftarkan route POST dengan middleware spesifik route opsional. Path menggunakan pencocokan pola stdlib.

Parameter:

  • path: path URL untuk route
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

router.Post("/users", createUserHandler)
router.Post("/upload", uploadFileHandler, AuthMiddleware)

func (*Router) Put

func (r *Router) Put(path string, handler HandlerFunc, middleware ...MiddlewareFunc)

Put mendaftarkan route PUT dengan middleware spesifik route opsional.

Parameter:

  • path: path URL untuk route
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

router.Put("/users/{id}", updateUserHandler, AuthMiddleware)

func (*Router) Register

func (r *Router) Register(method, path string, handler HandlerFunc, middleware []MiddlewareFunc)

Register mendaftarkan route dengan metode HTTP, path, handler, dan middleware opsional. Menggunakan stdlib http.ServeMux untuk pencocokan pola. Thread-safe: dilindungi dengan mutex untuk pendaftaran route konkuren. Secara otomatis mengubah metode menjadi huruf besar untuk kepatuhan.

Parameter:

  • method: metode HTTP (GET, POST, PUT, DELETE, dll)
  • path: path URL dengan pola stdlib (/users/{id}, /files/{path...})
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

router.Register("GET", "/users/{id}", getUserHandler, []MiddlewareFunc{AuthMiddleware})

func (*Router) SPA

func (r *Router) SPA(root fs.FS, index string, middleware ...MiddlewareFunc)

SPA (Single Page Application) melayani aplikasi frontend modern dengan fallback ke index.html. Secara otomatis menambahkan header keamanan dan mematikan cache untuk file index agar user selalu mendapat versi terbaru.

func (*Router) ServeHTTP

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP mengimplementasikan antarmuka http.Handler untuk menangani permintaan HTTP. Menerapkan middleware global dan menggunakan cached handler untuk kinerja yang lebih baik.

Parameter:

  • w: http.ResponseWriter untuk menulis respons
  • req: *http.Request permintaan yang akan diproses

func (*Router) Static

func (r *Router) Static(prefix string, root fs.FS, middleware ...MiddlewareFunc)

Static melayani file statis dari sistem file (lokal atau embed). Secara otomatis menambahkan header keamanan dasar.

Parameter:

  • prefix: path URL prefix (contoh: "/assets/")
  • root: fs.FS interface (gunakan os.DirFS("./public") atau embed.FS)
  • middleware: middleware tambahan (opsional)

func (*Router) Use

func (r *Router) Use(middleware ...MiddlewareFunc)

Use menambahkan middleware global yang akan diterapkan ke semua route. Middleware diterapkan dalam urutan penambahan dan sebelum middleware spesifik route. Thread-safe: dilindungi dengan mutex untuk akses konkuren.

Parameter:

  • middleware: daftar variadic dari MiddlewareFunc yang akan ditambahkan

Contoh:

router.Use(RecoveryMiddleware, LoggerMiddleware)

type RouterGroup

type RouterGroup struct {
	// contains filtered or unexported fields
}

RouterGroup merepresentasikan sekelompok route dengan prefix yang sama.

func (*RouterGroup) Delete

func (rg *RouterGroup) Delete(relativePath string, handler HandlerFunc, middleware ...MiddlewareFunc)

Delete mendaftarkan route DELETE dalam grup dengan prefix grup dan middleware. Prefix grup dan middleware secara otomatis ditambahkan ke route.

Parameter:

  • path: path URL relatif terhadap prefix grup
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

api := router.Group("/api")
api.Delete("/users/{id}", deleteUserHandler)  // terdaftar sebagai DELETE /api/users/{id}

func (*RouterGroup) Get

func (rg *RouterGroup) Get(relativePath string, handler HandlerFunc, middleware ...MiddlewareFunc)

Get mendaftarkan route GET dalam grup dengan prefix grup dan middleware. Prefix grup dan middleware secara otomatis ditambahkan ke route. Menggunakan path.Join untuk menggabungkan path secara aman.

Parameter:

  • path: path URL relatif terhadap prefix grup
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

api := router.Group("/api")
api.Get("/users", getUsersHandler)  // terdaftar sebagai GET /api/users

func (*RouterGroup) Group

func (rg *RouterGroup) Group(prefix string, middleware ...MiddlewareFunc) *RouterGroup

Group membuat grup route bersarang dengan prefix dan middleware gabungan. Prefix dan middleware dari grup induk digabungkan dengan grup baru. Berguna untuk organisasi route hierarkis (contoh: /api/v1/admin). Menggunakan path.Join untuk memastikan format path yang benar (menghindari double slash).

Parameter:

  • prefix: sub-prefix untuk grup bersarang
  • middleware: middleware level grup opsional

Mengembalikan:

  • *RouterGroup: instance grup router bersarang

Example:

api := router.Group("/api")
v1 := api.Group("/v1", AuthMiddleware)
admin := v1.Group("/admin", AdminAuthMiddleware)
admin.Get("/users", listAllUsersHandler)  // terdaftar sebagai GET /api/v1/admin/users dengan middleware gabungan

func (*RouterGroup) Head

func (rg *RouterGroup) Head(relativePath string, handler HandlerFunc, middleware ...MiddlewareFunc)

Head mendaftarkan route HEAD dalam grup dengan prefix grup dan middleware. Prefix grup dan middleware secara otomatis ditambahkan ke route.

Parameter:

  • path: path URL relatif terhadap prefix grup
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

api := router.Group("/api")
api.Head("/users", headHandler)  // terdaftar sebagai HEAD /api/users

func (*RouterGroup) Options

func (rg *RouterGroup) Options(relativePath string, handler HandlerFunc, middleware ...MiddlewareFunc)

Options mendaftarkan route OPTIONS dalam grup dengan prefix grup dan middleware. Prefix grup dan middleware secara otomatis ditambahkan ke route.

Parameter:

  • path: path URL relatif terhadap prefix grup
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

api := router.Group("/api")
api.Options("/users", optionsHandler)  // terdaftar sebagai OPTIONS /api/users

func (*RouterGroup) Patch

func (rg *RouterGroup) Patch(relativePath string, handler HandlerFunc, middleware ...MiddlewareFunc)

Patch mendaftarkan route PATCH dalam grup dengan prefix grup dan middleware. Prefix grup dan middleware secara otomatis ditambahkan ke route.

Parameter:

  • path: path URL relatif terhadap prefix grup
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

api := router.Group("/api")
api.Patch("/users/{id}", patchUserHandler)  // terdaftar sebagai PATCH /api/users/{id}

func (*RouterGroup) Post

func (rg *RouterGroup) Post(relativePath string, handler HandlerFunc, middleware ...MiddlewareFunc)

Post mendaftarkan route POST dalam grup dengan prefix grup dan middleware. Prefix grup dan middleware secara otomatis ditambahkan ke route.

Parameter:

  • path: path URL relatif terhadap prefix grup
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

api := router.Group("/api", AuthMiddleware)
api.Post("/users", createUserHandler)  // terdaftar sebagai POST /api/users dengan AuthMiddleware

func (*RouterGroup) Put

func (rg *RouterGroup) Put(relativePath string, handler HandlerFunc, middleware ...MiddlewareFunc)

Put mendaftarkan route PUT dalam grup dengan prefix grup dan middleware. Prefix grup dan middleware secara otomatis ditambahkan ke route.

Parameter:

  • path: path URL relatif terhadap prefix grup
  • handler: HandlerFunc yang akan menangani permintaan
  • middleware: middleware spesifik route opsional

Contoh:

api := router.Group("/api")
api.Put("/users/{id}", updateUserHandler)  // terdaftar sebagai PUT /api/users/{id}

func (*RouterGroup) Use

func (rg *RouterGroup) Use(middleware ...MiddlewareFunc)

Use menambahkan middleware ke dalam group yang sudah ada. Middleware akan diterapkan ke semua route yang didaftarkan SETELAH pemanggilan ini.

Parameter:

  • middleware: daftar variadic dari MiddlewareFunc

Example:

api := router.Group("/api")
api.Use(AuthMiddleware)
api.Get("/profile", profileHandler) // AuthMiddleware diterapkan

type Row

type Row interface {
	Scan(dest ...interface{}) error
}

Row represents a single query result row

type Rows

type Rows interface {
	Close()
	Next() bool
	Scan(dest ...interface{}) error
	Err() error
}

Rows represents query result rows

type ServeCommand

type ServeCommand struct {
	// contains filtered or unexported fields
}

ServeCommand menjalankan HTTP server dengan konfigurasi yang dapat di-override via flags.

func (*ServeCommand) DefineFlags

func (c *ServeCommand) DefineFlags(fs *flag.FlagSet)

func (*ServeCommand) Description

func (c *ServeCommand) Description() string

func (*ServeCommand) Execute

func (c *ServeCommand) Execute(ctx *CommandContext) error

func (*ServeCommand) Name

func (c *ServeCommand) Name() string

type ServerConfig

type ServerConfig struct {
	Port            string
	ReadTimeout     time.Duration
	WriteTimeout    time.Duration
	IdleTimeout     time.Duration
	ShutdownTimeout time.Duration
}

ServerConfig holds server configuration

type SortField

type SortField struct {
	Field     string
	Direction string // "ASC" or "DESC"
}

SortField represents a single sort criterion

func (SortField) SQL

func (s SortField) SQL() string

SQL returns a basic ORDER BY clause

type SortParser

type SortParser struct {
	AllowedFields map[string]bool
}

SortParser parses sort parameters from the request

func NewSortParser

func NewSortParser(allowedFields []string) *SortParser

NewSortParser creates a new SortParser with allowed fields

func (*SortParser) Parse

func (p *SortParser) Parse(r *http.Request) ([]SortField, error)

Parse parses the "sort" query parameter Format: ?sort=-created_at,title (descending created_at, ascending title)

type TimestampRange

type TimestampRange = Range[int64]

TimestampRange: Unix timestamp in seconds (from date string parsing) Input format: "YYYY-MM-DD" converted to Unix timestamp Example: "2024-01-15" or "2024-01-01,2024-12-31"

type TokenBlocklist

type TokenBlocklist interface {
	// Invalidate memasukkan token/session ke daftar hitam.
	// identifier: Unique identifier (bisa JTI atau SID).
	// expiresIn: Sisa durasi hidup token tersebut (sampai exp).
	Invalidate(ctx context.Context, identifier string, expiresIn time.Duration) error

	// IsRevoked mengecek apakah identifier ada di daftar hitam dan belum expired.
	IsRevoked(ctx context.Context, identifier string) (bool, error)
}

TokenBlocklist mendefinisikan interface untuk mekanisme pencabutan token (denylist). Digunakan untuk menyimpan identifier (JTI atau Session ID) dari token yang di-invalidate sebelum waktunya.

type TokenResponse

type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	ExpiresIn    int    `json:"expires_in"`
	TokenType    string `json:"token_type"`
}

TokenResponse merepresentasikan respons token setelah login berhasil.

type TokenStore

type TokenStore interface {
	SaveRefreshToken(ctx context.Context, token *RefreshToken) error
	FindRefreshToken(ctx context.Context, tokenHash string) (*RefreshToken, error)
	RevokeRefreshToken(ctx context.Context, tokenHash string) error
	RevokeAllUserTokens(ctx context.Context, userID string) error

	SavePasswordResetToken(ctx context.Context, token *PasswordResetToken) error
	FindPasswordResetToken(ctx context.Context, tokenHash string) (*PasswordResetToken, error)
	MarkPasswordResetUsed(ctx context.Context, tokenHash string) error
}

TokenStore defines the interface for token storage operations

type TokenUser

type TokenUser struct {
	ID       string
	Email    string
	Password string // Usually empty for token-derived users
	Claims   map[string]interface{}
}

TokenUser represents a minimal user entity derived from a token

func (*TokenUser) GetClaims

func (u *TokenUser) GetClaims() map[string]interface{}

func (*TokenUser) GetEmail

func (u *TokenUser) GetEmail() string

func (*TokenUser) GetID

func (u *TokenUser) GetID() string

func (*TokenUser) GetPassword

func (u *TokenUser) GetPassword() string

func (*TokenUser) SetPassword

func (u *TokenUser) SetPassword(password string)

type TransactionFunc

type TransactionFunc func(ctx context.Context, tx pgx.Tx) error

TransactionFunc is a function that performs operations within a transaction

type UUID

type UUID [16]byte

func NewUuid

func NewUuid() UUID

NewUuid menghasilkan UUID baru menggunakan v7 (time-based) atau v4 (random) sebagai fallback. Prefer v7 karena sortable berdasarkan timestamp, lebih efficient untuk database indexing. Falls back ke v4 jika random generation untuk v7 gagal.

Returns:

  • UUID: newly generated UUID

Example:

id := NewUuid()
user.ID = id.String()

func NewV4

func NewV4() UUID

NewV4 menghasilkan UUID v4 (random-based). Format: random (4 bytes) | version 4 (4 bits) | random (12 bits) | variant (2 bits) | random (62 bits). UUID v4 adalah fully random dan tidak sortable berdasarkan time. Returns zero UUID jika random generation gagal (rare edge case).

Returns:

  • UUID: newly generated v4 UUID

Example:

id := NewV4()
session.ID = id.String()

func NewV7

func NewV7() (UUID, error)

NewV7 menghasilkan UUID v7 (time-based dengan random component). Format: timestamp (48 bits) | version 7 (4 bits) | random (12 bits) | variant (2 bits) | random (62 bits). UUID v7 adalah sortable berdasarkan timestamp untuk efficient database operations. Berguna untuk primary keys dalam relational databases.

Returns:

  • UUID: newly generated v7 UUID
  • error: error jika random generation gagal

Example:

id, err := NewV7()
if err != nil {
  return err
}
log.Println(id.String())

func ParseUUIDFromString

func ParseUUIDFromString(s string) (UUID, error)

ParseUUIDFromString adalah alias untuk ParseUUID untuk consistency dengan naming conventions. Mengparse UUID string dalam standard format (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).

Parameters:

  • s: UUID string untuk di-parse

Returns:

  • UUID: parsed UUID
  • error: error jika string bukan valid UUID format

Example:

uuid, err := ParseUUIDFromString("550e8400-e29b-41d4-a716-446655440000")

func ParseUuid

func ParseUuid(s string) (UUID, error)

ParseUUID mengparse UUID string dalam standard format. Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (exactly 36 characters). Case-insensitive hex character validation. Returns error jika format invalid atau string bukan valid UUID.

Parameters:

  • s: UUID string untuk di-parse

Returns:

  • UUID: parsed UUID
  • error: error jika string bukan valid UUID format

Example:

uuid, err := ParseUUID("550e8400-e29b-41d4-a716-446655440000")
if err != nil {
  log.Fatal(err)
}
user.ID = uuid

func (UUID) String

func (u UUID) String() string

String mengembalikan string representation UUID dalam standard format. Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (32 hex chars + 4 hyphens = 36 chars).

Returns:

  • string: UUID formatted string

Example:

uuid := NewUuid()
fmt.Println(uuid.String())  // Output: 550e8400-e29b-41d4-a716-446655440000

type UploadConfig

type UploadConfig struct {
	// contains filtered or unexported fields
}

UploadConfig menyimpan konfigurasi untuk upload file.

Fields:

  • path: Path direktori untuk menyimpan file yang di-upload (sanitisasi otomatis)
  • allowedExts: Daftar ekstensi file yang diizinkan (misalnya ".jpg", ".pdf")
  • maxFileSize: Ukuran file maksimal dalam bytes (0 = tanpa batas)
  • maxFiles: Jumlah maksimal file untuk di-upload sekaligus
  • concurrent: Aktifkan pemrosesan concurrent (false = sequential)
  • maxWorkers: Jumlah concurrent workers (jika concurrent = true)
  • logger: Logger opsional untuk debugging (bisa nil)

func DefaultConfig

func DefaultConfig() *UploadConfig

DefaultConfig mengembalikan UploadConfig baru dengan nilai default yang masuk akal.

Nilai default:

  • path: "/uploads"
  • allowedExts: [".jpg", ".jpeg", ".png", ".pdf"]
  • maxFileSize: 10 MB (10 << 20 bytes)
  • maxFiles: 10
  • concurrent: false (pemrosesan sequential)
  • maxWorkers: 10
  • logger: nil (tanpa logging)

Default ini dapat ditimpa menggunakan fungsi opsi With*.

type UploadOption

type UploadOption func(*UploadConfig)

UploadOption adalah functional option untuk mengkonfigurasi UploadConfig.

func WithAllowedExts

func WithAllowedExts(exts ...string) UploadOption

WithAllowedExts mengatur daftar ekstensi file yang diizinkan.

Contoh:

WithAllowedExts(".jpg", ".jpeg", ".png", ".gif")

Ekstensi tidak case-sensitive. Jika tidak diatur, ekstensi default digunakan.

func WithConcurrent

func WithConcurrent(enabled bool) UploadOption

WithConcurrent mengaktifkan pemrosesan file concurrent.

Saat diaktifkan, menggunakan worker pool untuk upload paralel. Saat dinonaktifkan, memproses file secara sequential (lebih lambat namun lebih dapat diprediksi).

Contoh:

WithConcurrent(true)   // Gunakan worker pool
WithConcurrent(false)  // Pemrosesan sequential

func WithLogger

func WithLogger(logger *slog.Logger) UploadOption

WithLogger mengatur logger opsional untuk debugging operasi upload.

Jika disediakan, logs akan mencakup progres upload, error, dan detail validasi.

Contoh:

logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
WithLogger(logger)

func WithMaxFileSize

func WithMaxFileSize(size uint64) UploadOption

WithMaxFileSize mengatur ukuran file maksimal dalam bytes.

Contoh:

WithMaxFileSize(10 << 20) // 10 MB
WithMaxFileSize(100 << 20) // 100 MB

File yang melebihi ukuran ini akan ditolak. Hanya diatur jika size > 0.

func WithMaxFiles

func WithMaxFiles(max uint8) UploadOption

WithMaxFiles mengatur jumlah maksimal file untuk di-upload sekaligus.

Contoh:

WithMaxFiles(5)   // Maks 5 file per upload
WithMaxFiles(10)  // Maks 10 file per upload

Hanya diatur jika max > 0. Default adalah 10.

func WithMaxWorkers

func WithMaxWorkers(max int) UploadOption

WithMaxWorkers mengatur jumlah concurrent workers.

Hanya berlaku jika pemrosesan concurrent diaktifkan. Default adalah 10. Hanya diatur jika max > 0.

Contoh:

WithMaxWorkers(5)   // 5 parallel upload workers
WithMaxWorkers(20)  // 20 parallel upload workers

func WithPath

func WithPath(path string) UploadOption

WithPath mengatur path direktori upload.

Contoh:

WithPath("/uploads/files")
WithPath("uploads") // otomatis diprefiks dengan /

Path otomatis disanitisasi terhadap serangan directory traversal.

type UploadResult

type UploadResult struct {
	Paths  []string
	Errors map[string]error
}

UploadResult berisi hasil dari operasi upload file.

Fields:

  • Paths: Daftar path file yang berhasil di-upload
  • Errors: Map filename -> error untuk upload yang gagal (file -> alasan error)

type Validator

type Validator struct {
	// contains filtered or unexported fields
}

Validator is a simple validation utility

func NewValidator

func NewValidator() *Validator

NewValidator membuat instance Validator baru dengan empty error map. Gunakan method chaining untuk add validations dan check hasil dengan IsValid().

Returns:

  • *Validator: validator instance siap digunakan

Example:

v := NewValidator().
  Required("email", email).
  Email("email", email).
  Required("password", password)
if !v.IsValid() {
  return v.ErrorMap()
}

func (*Validator) AddError

func (v *Validator) AddError(field, message string) *Validator

AddError menambahkan custom error untuk field tertentu. Jika field sudah ada error, skip (first error wins).

Parameters:

  • field: nama field untuk error
  • message: error message yang akan ditambahkan

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.AddError("email", "Email sudah terdaftar")

func (*Validator) Custom

func (v *Validator) Custom(field string, fn func(string) bool, value string, message string) *Validator

Custom memvalidasi menggunakan custom validation function.

Parameters:

  • field: nama field untuk error message
  • fn: custom validation function yang return true jika valid
  • value: string value yang akan divalidasi
  • message: error message jika validation gagal

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.Custom("username", func(u string) bool { return len(u) > 3 }, username, "Username minimal 4 karakter")

func (*Validator) Email

func (v *Validator) Email(field, value string) *Validator

Email memvalidasi bahwa field adalah valid email format. Menggunakan regex pattern untuk basic email validation.

Parameters:

  • field: nama field untuk error message
  • value: email string yang akan dicek

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.Email("email", email)

func (*Validator) ErrorCount

func (v *Validator) ErrorCount() int

ErrorCount mengembalikan jumlah fields yang memiliki validation errors.

Returns:

  • int: jumlah fields dengan errors, 0 jika tidak ada errors

Example:

if v.ErrorCount() > 0 {
  return v.ErrorMap()
}

func (*Validator) ErrorMap

func (v *Validator) ErrorMap() map[string]string

ErrorMap mengembalikan validation errors sebagai map[field]error_message. Cocok untuk API responses untuk return field-specific errors.

Returns:

  • map[string]string: map dari field name ke error message

Example:

if !v.IsValid() {
  return c.JSON(400, v.ErrorMap())
}

func (*Validator) Errors

func (v *Validator) Errors() []string

Errors mengembalikan semua validation error messages sebagai string slice. Setiap field maksimal memiliki satu error message (first error wins).

Returns:

  • []string: slice dari error messages, empty jika tidak ada errors

Example:

if !v.IsValid() {
  errors := v.Errors()
  for _, err := range errors {
    fmt.Println(err)
  }
}

func (*Validator) GetError

func (v *Validator) GetError(field string) string

GetError mengembalikan error message untuk field tertentu.

Parameters:

  • field: nama field yang akan diambil error-nya

Returns:

  • string: error message untuk field, empty string jika tidak ada error

Example:

errMsg := v.GetError("email")
if errMsg != "" {
  return errMsg
}

func (*Validator) HasError

func (v *Validator) HasError(field string) bool

HasError mengecek apakah field tertentu memiliki validation error.

Parameters:

  • field: nama field yang akan dicek

Returns:

  • bool: true jika field memiliki error, false jika tidak

Example:

if v.HasError("email") {
  return "Email tidak valid"
}

func (*Validator) In

func (v *Validator) In(field, value string, allowed ...string) *Validator

In memvalidasi bahwa field value adalah salah satu dari allowed values.

Parameters:

  • field: nama field untuk error message
  • value: string value yang akan dicek
  • allowed: variadic list dari allowed values

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.In("role", role, "admin", "user", "guest")

func (*Validator) IsValid

func (v *Validator) IsValid() bool

IsValid mengecek apakah tidak ada validation errors (validation berhasil).

Returns:

  • bool: true jika validation valid (no errors), false jika ada errors

Example:

if !v.IsValid() {
  return v.ErrorMap()
}

func (*Validator) Length

func (v *Validator) Length(field, value string, length int) *Validator

Length memvalidasi bahwa field memiliki exact length yang ditentukan.

Parameters:

  • field: nama field untuk error message
  • value: string value yang akan dicek panjangnya
  • length: exact length yang dibutuhkan

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.Length("code", code, 6)

func (*Validator) Matches

func (v *Validator) Matches(field, value, otherField, otherValue string) *Validator

Matches memvalidasi bahwa dua fields memiliki nilai yang sama. Berguna untuk password confirmation, email verification, dll.

Parameters:

  • field: nama field untuk error message
  • value: value dari field pertama
  • otherField: nama field kedua untuk error message
  • otherValue: value dari field kedua

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.Matches("password", password, "password_confirmation", passwordConfirm)

func (*Validator) MaxLength

func (v *Validator) MaxLength(field, value string, max int) *Validator

MaxLength memvalidasi bahwa field tidak melebihi maximum length tertentu.

Parameters:

  • field: nama field untuk error message
  • value: string value yang akan dicek panjangnya
  • max: maximum length yang diperbolehkan

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.MaxLength("name", name, 255)

func (*Validator) MinLength

func (v *Validator) MinLength(field, value string, min int) *Validator

MinLength memvalidasi bahwa field memiliki minimum length tertentu. Length dihitung setelah trimspace.

Parameters:

  • field: nama field untuk error message
  • value: string value yang akan dicek panjangnya
  • min: minimum length yang dibutuhkan

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.MinLength("password", password, 8)

func (*Validator) NumRange

func (v *Validator) NumRange(field string, value, min, max int) *Validator

NumRange memvalidasi bahwa numeric value berada dalam range min-max.

Parameters:

  • field: nama field untuk error message
  • value: numeric value yang akan dicek
  • min: minimum value (inclusive)
  • max: maximum value (inclusive)

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.NumRange("age", age, 18, 120)

func (*Validator) OptionalEmail

func (v *Validator) OptionalEmail(field string, value JsonNull[string]) *Validator

OptionalEmail memvalidasi email format hanya jika field present dan valid. Digunakan untuk JsonNull[string] fields dengan logic: - Present=false: skip validation (field tidak dikirim) - Present=true, Valid=false: skip validation (field adalah null) - Present=true, Valid=true: validate email format

Parameters:

  • field: nama field untuk error message
  • value: JsonNull[string] field value

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.OptionalEmail("alternate_email", emailJsonNull)

func (*Validator) OptionalIn

func (v *Validator) OptionalIn(field string, value JsonNull[string], allowed ...string) *Validator

OptionalIn memvalidasi value dalam allowed list hanya jika field present dan valid.

Parameters:

  • field: nama field untuk error message
  • value: JsonNull[string] field value
  • allowed: variadic list dari allowed values

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.OptionalIn("status", statusJsonNull, "active", "inactive")

func (*Validator) OptionalLength

func (v *Validator) OptionalLength(field string, value JsonNull[string], length int) *Validator

OptionalLength memvalidasi exact length hanya jika field present dan valid.

Parameters:

  • field: nama field untuk error message
  • value: JsonNull[string] field value
  • length: exact length yang dibutuhkan

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.OptionalLength("code", codeJsonNull, 6)

func (*Validator) OptionalMatches

func (v *Validator) OptionalMatches(field string, value JsonNull[string], pattern string) *Validator

OptionalMatches memvalidasi regex pattern hanya jika field present dan valid.

Parameters:

  • field: nama field untuk error message
  • value: JsonNull[string] field value
  • pattern: regex pattern string

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.OptionalMatches("phone", phoneJsonNull, "^\\d{10,}$")

func (*Validator) OptionalMaxLength

func (v *Validator) OptionalMaxLength(field string, value JsonNull[string], max int) *Validator

OptionalMaxLength memvalidasi maximum length hanya jika field present dan valid.

Parameters:

  • field: nama field untuk error message
  • value: JsonNull[string] field value
  • max: maximum length yang diperbolehkan

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.OptionalMaxLength("bio", bioJsonNull, 500)

func (*Validator) OptionalMinLength

func (v *Validator) OptionalMinLength(field string, value JsonNull[string], min int) *Validator

OptionalMinLength memvalidasi minimum length hanya jika field present dan valid.

Parameters:

  • field: nama field untuk error message
  • value: JsonNull[string] field value
  • min: minimum length yang dibutuhkan

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.OptionalMinLength("bio", bioJsonNull, 10)

func (*Validator) Pattern

func (v *Validator) Pattern(field, value string, pattern string) *Validator

Pattern memvalidasi bahwa field cocok dengan regex pattern yang diberikan.

Parameters:

  • field: nama field untuk error message
  • value: string value yang akan di-match
  • pattern: regex pattern string

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.Pattern("phone", phone, "^\\d{10,}$")

func (*Validator) Required

func (v *Validator) Required(field, value string) *Validator

Required memvalidasi bahwa field tidak kosong (setelah trimspace). Jika field sudah ada error, skip validation ini (first error wins).

Parameters:

  • field: nama field untuk error message
  • value: string value yang akan dicek

Returns:

  • *Validator: pointer to validator untuk method chaining

Example:

v.Required("email", email)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL