Files
marktvogt.de/backend/internal/pkg/apierror/error.go
T
vikingowl a1d93f7a8e feat: implement MVP backend API
Go backend with Gin, pgx, Valkey (go-valkey), and PostGIS.

Domains:
- Market search with PostGIS geo-queries (ST_DWithin, ST_Distance),
  German full-text search (tsvector + ILIKE fallback for compound words),
  date range filtering, pagination, and slug-based detail endpoint
- Auth with email+password (bcrypt), JWT access tokens (15min),
  session tokens (30d, dual Valkey+Postgres storage), OAuth
  (Google/GitHub/Facebook), magic links, and TOTP 2FA
- User profile with CRUD, soft-delete (30d grace), and restore

Infrastructure:
- 6 database migrations (users, sessions, oauth_accounts, magic_links,
  markets with PostGIS+FTS, totp_secrets)
- Middleware: recovery, request ID, structured logging (slog), CORS,
  per-IP rate limiting, JWT auth
- Seed data: 10 medieval markets across DACH region
- Docker Compose (PostGIS 17 + Valkey 8), multi-stage Dockerfile,
  Woodpecker CI pipeline, Kubernetes manifests
- Justfile, golangci-lint config, env example
2026-02-18 05:52:20 +01:00

83 lines
1.8 KiB
Go

package apierror
import (
"fmt"
"net/http"
)
type Error struct {
Status int `json:"-"`
Code string `json:"code"`
Message string `json:"message"`
}
func (e *Error) Error() string {
return fmt.Sprintf("[%d] %s: %s", e.Status, e.Code, e.Message)
}
type Response struct {
Error *ErrorBody `json:"error"`
}
type ErrorBody struct {
Code string `json:"code"`
Message string `json:"message"`
}
func NewResponse(e *Error) Response {
return Response{
Error: &ErrorBody{
Code: e.Code,
Message: e.Message,
},
}
}
func BadRequest(code, message string) *Error {
return &Error{Status: http.StatusBadRequest, Code: code, Message: message}
}
func Unauthorized(message string) *Error {
return &Error{Status: http.StatusUnauthorized, Code: "unauthorized", Message: message}
}
func Forbidden(message string) *Error {
return &Error{Status: http.StatusForbidden, Code: "forbidden", Message: message}
}
func NotFound(resource string) *Error {
return &Error{
Status: http.StatusNotFound,
Code: "not_found",
Message: fmt.Sprintf("%s not found", resource),
}
}
func Conflict(message string) *Error {
return &Error{Status: http.StatusConflict, Code: "conflict", Message: message}
}
func TooManyRequests() *Error {
return &Error{
Status: http.StatusTooManyRequests,
Code: "rate_limited",
Message: "too many requests, please try again later",
}
}
func Internal(message string) *Error {
return &Error{
Status: http.StatusInternalServerError,
Code: "internal_error",
Message: message,
}
}
func Validation(message string) *Error {
return &Error{Status: http.StatusUnprocessableEntity, Code: "validation_error", Message: message}
}
func Gone(message string) *Error {
return &Error{Status: http.StatusGone, Code: "gone", Message: message}
}