From 744b1c88280faa8e5979fe09c9eee229c7bfbde8 Mon Sep 17 00:00:00 2001 From: "mohammad.farrokhnia" Date: Tue, 30 Jun 2026 11:15:03 +0330 Subject: [PATCH 1/2] docs: update README with UUID for idempotency key and clarify migration requirements --- README.md | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 3af2211..fbdc2f9 100644 --- a/README.md +++ b/README.md @@ -157,8 +157,9 @@ grpcurl -plaintext -d '{ ### Top up a user wallet (mint money from SYSTEM) ```bash +# idempotency_key must be a UUID — generate one before the call grpcurl -plaintext -d '{ - "idempotency_key": "topup-alice-001", + "idempotency_key": "550e8400-e29b-41d4-a716-446655440001", "from_account_id": "", "to_account_id": "", "amount": 10000, @@ -175,9 +176,9 @@ curl http://localhost:8080/v1/wallets//balance | jq . ### Retry with same idempotency key (safe — returns original) ```bash -# Sending the same request again returns the original transaction, money moves once +# Sending the same UUID again returns the original transaction, money moves once grpcurl -plaintext -d '{ - "idempotency_key": "topup-alice-001", + "idempotency_key": "550e8400-e29b-41d4-a716-446655440001", "from_account_id": "", "to_account_id": "", "amount": 10000, @@ -212,16 +213,24 @@ curl http://localhost:8080/metrics | grep ledger make up # start Postgres + pgAdmin (localhost:5050) make down # stop containers, keep data make down-volumes # stop containers, delete all data -make migrate # run migrations on dev DB -make migrate-test # run migrations on test DB -make gen # regenerate proto → Go + Swagger +make migrate # run migrations on dev DB (requires DB_DSN in .env or env) +make migrate-test # run migrations on test DB (requires DB_DSN_TEST) +make gen # regenerate proto → Go + Swagger (requires buf + protoc plugins) make lint # run golangci-lint make test # run all tests with -race flag -make run # run the service (reads .env) +make run # run the service (reads configs/config.yaml) make db # open psql shell make help # list all targets ``` +`make gen` requires `buf` and the Go protoc plugins: +```bash +go install google.golang.org/protobuf/cmd/protoc-gen-go@latest +go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest +go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest +go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest +``` + ## Configuration The service loads `configs/config.yaml` first, then overlays any matching environment variables. Create your config by copying the template: @@ -244,8 +253,11 @@ The Makefile (`make migrate`, `make db`) reads a `.env` file for convenience — ## Running Tests +Integration tests (postgres package) require a running Postgres instance and `DB_DSN_TEST`: + ```bash -# Ensure test DB is migrated +# Set DB_DSN_TEST in your environment or .env, then migrate the test DB +export DB_DSN_TEST="postgres://postgres:postgres@localhost:5432/ledger_test?sslmode=disable" make migrate-test # Run all tests including concurrency tests @@ -257,6 +269,8 @@ make test # TestCreateTransaction_Idempotency — same key twice, money moves once ``` +Unit tests (ledger package) use a mock store and run without Postgres. Integration tests skip automatically when `DB_DSN_TEST` is unset. + ## Building the Docker Image ```bash @@ -284,16 +298,15 @@ docker compose -f deployments/docker/docker-compose.yml up ## Project Structure ``` -api/proto/ledger/v1/ proto definition + generated Go code +api/proto/ledger/v1/ ledger.proto — generated .pb.go files are gitignored (make gen) cmd/ledger/ entrypoint — composition root only configs/ config.yaml template deployments/docker/ Dockerfile + docker-compose -docs/ API documentation internal/ audit/ outbox worker — polls DB, POSTs events to webhook config/ koanf config loader i18n/ error message translation (English + Farsi) - ledger/ domain: types, errors, Store/Auditor ports, Service + ledger/ domain: types, errors, Store/OutboxStore ports, Service metrics/ Prometheus metric definitions store/postgres/ Postgres implementation of ledger.Store transport/grpc/ gRPC server, handler, interceptors, mappers From 32b93f7f25dac94f4b06cac248ac0ffa4b042b3a Mon Sep 17 00:00:00 2001 From: "mohammad.farrokhnia" Date: Tue, 30 Jun 2026 11:19:31 +0330 Subject: [PATCH 2/2] style: :truck: chnage the name of the project from go-ledger to ledger --- .gitignore | 3 --- CONTRIBUTING.md | 4 ++-- README.md | 14 +++++++------- api/openapi/ledger.swagger.json | 2 +- api/proto/ledger/v1/ledger.proto | 4 ++-- cmd/ledger/main.go | 14 +++++++------- go.mod | 2 +- internal/audit/worker.go | 2 +- internal/i18n/messages.go | 2 +- internal/ledger/service_test.go | 2 +- internal/store/postgres/account.go | 2 +- internal/store/postgres/entry.go | 2 +- internal/store/postgres/outbox.go | 2 +- internal/store/postgres/store.go | 2 +- internal/store/postgres/transaction.go | 2 +- internal/store/postgres/transaction_test.go | 4 ++-- internal/transport/grpc/errors.go | 2 +- internal/transport/grpc/handler.go | 6 +++--- internal/transport/grpc/mapper.go | 4 ++-- internal/transport/grpc/server.go | 4 ++-- internal/transport/http/gateway.go | 2 +- internal/transport/http/response.go | 6 +++--- internal/transport/http/swagger.json | 2 +- internal/transport/http/swagger.swagger.json | 2 +- pkg/apperr/apperr.go | 11 +---------- pkg/response/response.go | 13 +------------ 26 files changed, 46 insertions(+), 69 deletions(-) diff --git a/.gitignore b/.gitignore index e49c5dd..3f84559 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# # Binaries for programs and plugins *.exe *.exe~ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b04a547..ac23c48 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -# Contributing to go-ledger +# Contributing to ledger -Thank you for your interest in contributing to `go-ledger`! As a high-consistency financial service, we mastertain strict code quality standards. +Thank you for your interest in contributing to `ledger`! As a high-consistency financial service, we mastertain strict code quality standards. ## 🌿 Branching Strategy diff --git a/README.md b/README.md index fbdc2f9..47c1311 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# go-ledger +# ledger A bank-grade financial transaction service built in Go. Designed to be the central financial brain that microservices talk to when they need to move value safely. @@ -22,7 +22,7 @@ graph TD ### Why hexagonal architecture -go-ledger has three input transports: gRPC, HTTP Gateway, and a future event consumer. Hexagonal architecture isolates the domain from all of them — the service layer never imports gRPC, HTTP, or Postgres packages. Each transport is a plug-in adapter. +ledger has three input transports: gRPC, HTTP Gateway, and a future event consumer. Hexagonal architecture isolates the domain from all of them — the service layer never imports gRPC, HTTP, or Postgres packages. Each transport is a plug-in adapter. ### The dependency flow (strictly one-directional, no cycles) @@ -115,8 +115,8 @@ Error messages are translated based on the client's `Accept-Language` header. Su ```bash # Clone and configure -git clone https://github.com/mohammad-farrokhnia/go-ledger.git -cd go-ledger +git clone https://github.com/mohammad-farrokhnia/ledger.git +cd ledger cp configs/config.example.yaml configs/config.yaml # Edit configs/config.yaml — at minimum set database.dsn @@ -191,8 +191,8 @@ grpcurl -plaintext -d '{ ```bash curl http://localhost:8080/health | jq . # { -# "data": {"status": "ok", "version": "1.0.0", "app": "go-ledger", "checks": {"postgres": "ok"}}, -# "meta": {"appName": "go-ledger", "version": "1.0.0", "timestamp": "...", "messageCode": "HEALTH_OK", "message": "healthy"} +# "data": {"status": "ok", "version": "1.0.0", "app": "ledger", "checks": {"postgres": "ok"}}, +# "meta": {"appName": "ledger", "version": "1.0.0", "timestamp": "...", "messageCode": "HEALTH_OK", "message": "healthy"} # } ``` @@ -274,7 +274,7 @@ Unit tests (ledger package) use a mock store and run without Postgres. Integrati ## Building the Docker Image ```bash -docker build -f deployments/docker/Dockerfile -t go-ledger:latest . +docker build -f deployments/docker/Dockerfile -t ledger:latest . # Run with docker compose (includes Postgres) docker compose -f deployments/docker/docker-compose.yml up diff --git a/api/openapi/ledger.swagger.json b/api/openapi/ledger.swagger.json index 3c9a34a..6b3e2a9 100644 --- a/api/openapi/ledger.swagger.json +++ b/api/openapi/ledger.swagger.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "go-ledger API", + "title": "ledger API", "description": "A high-consistency, bank-grade financial transaction service.", "version": "1.0" }, diff --git a/api/proto/ledger/v1/ledger.proto b/api/proto/ledger/v1/ledger.proto index 41f240d..37d2889 100644 --- a/api/proto/ledger/v1/ledger.proto +++ b/api/proto/ledger/v1/ledger.proto @@ -6,10 +6,10 @@ import "google/api/annotations.proto"; import "google/protobuf/timestamp.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; -option go_package = "github.com/mohammad-farrokhnia/go-ledger/api/proto/ledger/v1;ledgerv1"; +option go_package = "github.com/mohammad-farrokhnia/ledger/api/proto/ledger/v1;ledgerv1"; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { info: { - title: "go-ledger API" + title: "ledger API" version: "1.0" description: "A high-consistency, bank-grade financial transaction service." } diff --git a/cmd/ledger/main.go b/cmd/ledger/main.go index 82eaa19..d0cb78d 100644 --- a/cmd/ledger/main.go +++ b/cmd/ledger/main.go @@ -12,13 +12,13 @@ import ( "golang.org/x/sync/errgroup" - "github.com/mohammad-farrokhnia/go-ledger/internal/audit" - "github.com/mohammad-farrokhnia/go-ledger/internal/config" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" - _ "github.com/mohammad-farrokhnia/go-ledger/internal/metrics" - "github.com/mohammad-farrokhnia/go-ledger/internal/store/postgres" - transportgrpc "github.com/mohammad-farrokhnia/go-ledger/internal/transport/grpc" - transporthttp "github.com/mohammad-farrokhnia/go-ledger/internal/transport/http" + "github.com/mohammad-farrokhnia/ledger/internal/audit" + "github.com/mohammad-farrokhnia/ledger/internal/config" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" + _ "github.com/mohammad-farrokhnia/ledger/internal/metrics" + "github.com/mohammad-farrokhnia/ledger/internal/store/postgres" + transportgrpc "github.com/mohammad-farrokhnia/ledger/internal/transport/grpc" + transporthttp "github.com/mohammad-farrokhnia/ledger/internal/transport/http" ) func main() { diff --git a/go.mod b/go.mod index 9033e57..225c6f1 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/mohammad-farrokhnia/go-ledger +module github.com/mohammad-farrokhnia/ledger go 1.26.3 diff --git a/internal/audit/worker.go b/internal/audit/worker.go index 43520c9..ee4b4a7 100644 --- a/internal/audit/worker.go +++ b/internal/audit/worker.go @@ -9,7 +9,7 @@ import ( "net/http" "time" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" ) type Worker struct { diff --git a/internal/i18n/messages.go b/internal/i18n/messages.go index 1709b7b..4ecbc4c 100644 --- a/internal/i18n/messages.go +++ b/internal/i18n/messages.go @@ -1,7 +1,7 @@ //nolint:staticcheck // U+200C (ZWNJ) is intentional Persian typography package i18n -import "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" +import "github.com/mohammad-farrokhnia/ledger/internal/ledger" var catalog = map[string]map[Lang]string{ "account_not_found": { diff --git a/internal/ledger/service_test.go b/internal/ledger/service_test.go index b7c9c3d..c794883 100644 --- a/internal/ledger/service_test.go +++ b/internal/ledger/service_test.go @@ -5,7 +5,7 @@ import ( "errors" "testing" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" ) type mockStore struct { diff --git a/internal/store/postgres/account.go b/internal/store/postgres/account.go index e02187b..ed0dfa1 100644 --- a/internal/store/postgres/account.go +++ b/internal/store/postgres/account.go @@ -7,7 +7,7 @@ import ( "github.com/jackc/pgx/v5" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" ) func (s *Store) CreateAccount(ctx context.Context, params ledger.CreateAccountParams) (ledger.Account, error) { diff --git a/internal/store/postgres/entry.go b/internal/store/postgres/entry.go index f095cbe..fd1faf3 100644 --- a/internal/store/postgres/entry.go +++ b/internal/store/postgres/entry.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" ) func (s *Store) GetWalletHistory(ctx context.Context, params ledger.GetWalletHistoryParams) ([]ledger.Entry, error) { diff --git a/internal/store/postgres/outbox.go b/internal/store/postgres/outbox.go index 5aa0640..e86bde2 100644 --- a/internal/store/postgres/outbox.go +++ b/internal/store/postgres/outbox.go @@ -5,7 +5,7 @@ import ( "encoding/json" "fmt" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" ) func (s *Store) PollAuditOutbox(ctx context.Context, limit int) ([]ledger.AuditOutboxEntry, error) { diff --git a/internal/store/postgres/store.go b/internal/store/postgres/store.go index 5d12ade..e01e488 100644 --- a/internal/store/postgres/store.go +++ b/internal/store/postgres/store.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/jackc/pgx/v5/pgxpool" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" ) type Store struct { diff --git a/internal/store/postgres/transaction.go b/internal/store/postgres/transaction.go index d0a0f1f..001cd08 100644 --- a/internal/store/postgres/transaction.go +++ b/internal/store/postgres/transaction.go @@ -9,7 +9,7 @@ import ( "sort" "github.com/jackc/pgx/v5" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" ) type accountSnapshot struct { diff --git a/internal/store/postgres/transaction_test.go b/internal/store/postgres/transaction_test.go index a5d6556..677a9fe 100644 --- a/internal/store/postgres/transaction_test.go +++ b/internal/store/postgres/transaction_test.go @@ -9,8 +9,8 @@ import ( "sync" "testing" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" - "github.com/mohammad-farrokhnia/go-ledger/internal/store/postgres" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" + "github.com/mohammad-farrokhnia/ledger/internal/store/postgres" ) func newKey() string { diff --git a/internal/transport/grpc/errors.go b/internal/transport/grpc/errors.go index 508e4a0..4d7b44d 100644 --- a/internal/transport/grpc/errors.go +++ b/internal/transport/grpc/errors.go @@ -8,7 +8,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" ) func domainErrorToGRPC(err error) error { diff --git a/internal/transport/grpc/handler.go b/internal/transport/grpc/handler.go index 1e0c56e..05171ce 100644 --- a/internal/transport/grpc/handler.go +++ b/internal/transport/grpc/handler.go @@ -10,9 +10,9 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - ledgerv1 "github.com/mohammad-farrokhnia/go-ledger/api/proto/ledger/v1" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" - "github.com/mohammad-farrokhnia/go-ledger/internal/metrics" + ledgerv1 "github.com/mohammad-farrokhnia/ledger/api/proto/ledger/v1" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" + "github.com/mohammad-farrokhnia/ledger/internal/metrics" ) type Handler struct { diff --git a/internal/transport/grpc/mapper.go b/internal/transport/grpc/mapper.go index a6509f4..62ab242 100644 --- a/internal/transport/grpc/mapper.go +++ b/internal/transport/grpc/mapper.go @@ -3,8 +3,8 @@ package grpc import ( "google.golang.org/protobuf/types/known/timestamppb" - ledgerv1 "github.com/mohammad-farrokhnia/go-ledger/api/proto/ledger/v1" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" + ledgerv1 "github.com/mohammad-farrokhnia/ledger/api/proto/ledger/v1" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" ) func accountToProto(a ledger.Account) *ledgerv1.Wallet { diff --git a/internal/transport/grpc/server.go b/internal/transport/grpc/server.go index 5ee8d56..5e1f9e2 100644 --- a/internal/transport/grpc/server.go +++ b/internal/transport/grpc/server.go @@ -8,8 +8,8 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/reflection" - ledgerv1 "github.com/mohammad-farrokhnia/go-ledger/api/proto/ledger/v1" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" + ledgerv1 "github.com/mohammad-farrokhnia/ledger/api/proto/ledger/v1" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" ) type Server struct { diff --git a/internal/transport/http/gateway.go b/internal/transport/http/gateway.go index 0b30ea7..121286d 100644 --- a/internal/transport/http/gateway.go +++ b/internal/transport/http/gateway.go @@ -13,7 +13,7 @@ import ( "google.golang.org/grpc/credentials/insecure" "google.golang.org/protobuf/encoding/protojson" - ledgerv1 "github.com/mohammad-farrokhnia/go-ledger/api/proto/ledger/v1" + ledgerv1 "github.com/mohammad-farrokhnia/ledger/api/proto/ledger/v1" ) //go:embed swagger.json diff --git a/internal/transport/http/response.go b/internal/transport/http/response.go index 59f6658..9f82cd2 100644 --- a/internal/transport/http/response.go +++ b/internal/transport/http/response.go @@ -10,8 +10,8 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/mohammad-farrokhnia/go-ledger/internal/i18n" - "github.com/mohammad-farrokhnia/go-ledger/internal/ledger" + "github.com/mohammad-farrokhnia/ledger/internal/i18n" + "github.com/mohammad-farrokhnia/ledger/internal/ledger" ) var grpcToHTTP = map[codes.Code]int{ @@ -57,7 +57,7 @@ func newMeta(acceptLang string, code i18n.MessageCode) Meta { } const ( - appName = "go-ledger" + appName = "ledger" appVersion = "1.0.0" ) diff --git a/internal/transport/http/swagger.json b/internal/transport/http/swagger.json index 3c9a34a..6b3e2a9 100644 --- a/internal/transport/http/swagger.json +++ b/internal/transport/http/swagger.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "go-ledger API", + "title": "ledger API", "description": "A high-consistency, bank-grade financial transaction service.", "version": "1.0" }, diff --git a/internal/transport/http/swagger.swagger.json b/internal/transport/http/swagger.swagger.json index 3c9a34a..6b3e2a9 100644 --- a/internal/transport/http/swagger.swagger.json +++ b/internal/transport/http/swagger.swagger.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "go-ledger API", + "title": "ledger API", "description": "A high-consistency, bank-grade financial transaction service.", "version": "1.0" }, diff --git a/pkg/apperr/apperr.go b/pkg/apperr/apperr.go index 333fa3c..c010738 100644 --- a/pkg/apperr/apperr.go +++ b/pkg/apperr/apperr.go @@ -1,16 +1,12 @@ -// Package apperr provides the AppError type for go-ledger. -// Mirrors LibreCore's pkg/errors: typed error codes, error types, -// HTTP status mapping, and context for additional details. package apperr import ( "fmt" "net/http" - "github.com/mohammad-farrokhnia/go-ledger/internal/i18n" + "github.com/mohammad-farrokhnia/ledger/internal/i18n" ) -// Type classifies the error for logging and HTTP status mapping. type Type string const ( @@ -22,8 +18,6 @@ const ( TypeForbidden Type = "forbidden" ) -// Code is a stable string identifier for each error condition. -// Clients can rely on these — they never change. const ( ErrAccountNotFound = "ACCOUNT_NOT_FOUND" ErrTransactionNotFound = "TRANSACTION_NOT_FOUND" @@ -38,7 +32,6 @@ const ( ErrBadRequest = "BAD_REQUEST" ) -// codeToMessageCode maps error codes to i18n message codes. var codeToMessageCode = map[string]i18n.MessageCode{ ErrAccountNotFound: i18n.MsgAccountNotFound, ErrTransactionNotFound: i18n.MsgTransactionNotFound, @@ -53,7 +46,6 @@ var codeToMessageCode = map[string]i18n.MessageCode{ ErrBadRequest: i18n.MsgBadRequest, } -// MessageCode returns the i18n code for this error code. func MessageCode(errCode string) i18n.MessageCode { if code, ok := codeToMessageCode[errCode]; ok { return code @@ -61,7 +53,6 @@ func MessageCode(errCode string) i18n.MessageCode { return i18n.MsgInternalError } -// AppError is the single error type used across all layers. type AppError struct { code string errType Type diff --git a/pkg/response/response.go b/pkg/response/response.go index 1a9687e..9a17913 100644 --- a/pkg/response/response.go +++ b/pkg/response/response.go @@ -1,6 +1,3 @@ -// Package response provides the unified HTTP response envelope for go-ledger. -// Every response — success or error — uses the same {data, meta} shape. -// This mirrors the pattern from LibreCore's pkg/response package. package response import ( @@ -8,7 +5,7 @@ import ( "net/http" "time" - "github.com/mohammad-farrokhnia/go-ledger/internal/i18n" + "github.com/mohammad-farrokhnia/ledger/internal/i18n" ) var ( @@ -16,16 +13,11 @@ var ( version string ) -// Init sets the application name and version embedded in every Meta. -// Call once from main() before starting the server. func Init(name, ver string) { appName = name version = ver } -// Meta is present on every response. -// MessageCode lets clients do their own i18n if needed. -// Message is already translated to the caller's Accept-Language. type Meta struct { AppName string `json:"appName"` Version string `json:"version"` @@ -46,7 +38,6 @@ func newMeta(requestID, acceptLang string, code i18n.MessageCode) Meta { } } -// OK writes a 200 success response. func OK(w http.ResponseWriter, r *http.Request, data any, code i18n.MessageCode) { write(w, http.StatusOK, map[string]any{ "data": data, @@ -54,7 +45,6 @@ func OK(w http.ResponseWriter, r *http.Request, data any, code i18n.MessageCode) }) } -// Created writes a 201 created response. func Created(w http.ResponseWriter, r *http.Request, data any, code i18n.MessageCode) { write(w, http.StatusCreated, map[string]any{ "data": data, @@ -62,7 +52,6 @@ func Created(w http.ResponseWriter, r *http.Request, data any, code i18n.Message }) } -// Error writes an error response with the given HTTP status. func Error(w http.ResponseWriter, r *http.Request, status int, code i18n.MessageCode) { write(w, status, map[string]any{ "error": map[string]any{},