https://github.com/aatuh/api-svc
Go domain services for SaaS APIs: billing, identity, payments, credits/tokens, and contact—built with ports/adapters, Postgres migrations, and optional HTTP handlers.
https://github.com/aatuh/api-svc
api backend billing chi clean-architecture credits ddd email go golang hexagonal-architecture identity migrations payments ports-and-adapters postgresql saas stripe tokens webhooks
Last synced: 5 months ago
JSON representation
Go domain services for SaaS APIs: billing, identity, payments, credits/tokens, and contact—built with ports/adapters, Postgres migrations, and optional HTTP handlers.
- Host: GitHub
- URL: https://github.com/aatuh/api-svc
- Owner: aatuh
- License: apache-2.0
- Created: 2026-01-09T11:07:09.000Z (5 months ago)
- Default Branch: master
- Last Pushed: 2026-01-09T11:09:29.000Z (5 months ago)
- Last Synced: 2026-01-12T02:44:08.635Z (5 months ago)
- Topics: api, backend, billing, chi, clean-architecture, credits, ddd, email, go, golang, hexagonal-architecture, identity, migrations, payments, ports-and-adapters, postgresql, saas, stripe, tokens, webhooks
- Language: Go
- Homepage:
- Size: 48.8 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# api-svc
## Overview
`api-svc` is a collection of reusable domain services for Go HTTP APIs:
billing, credits/tokens, identity, payments, and contact. Each service is
packaged as plain Go with clear ports (interfaces) for persistence and
third‑party providers. Some services include optional HTTP handlers
(chi-based via `api-toolkit`) and Postgres adapters + embedded migrations.
This repository is intentionally both human- and agent-friendly:
predictable folder layout, small packages, explicit wiring, and minimal
hidden magic.
## Design goals
- Domain logic in `Service` types; adapters stay thin.
- Depend on stable interfaces at boundaries (`github.com/aatuh/api-toolkit/ports`).
- Make persistence/provider swaps straightforward.
- Keep wiring explicit and test-friendly (fakes over ports).
## Services (package map)
- `billingsvc` — billing profiles, invoices, “outstanding” invoicing, and
webhook processing.
- HTTP: `billingsvc/http`
- Postgres: `billingsvc/postgres`
- Migrations: `billingsvc/migrations` (embedded `embed.FS`)
- `creditsvc` — token/credit accounts + transaction ledger.
- Postgres: `creditsvc/postgres`
- Migrations: `creditsvc/migrations` (embedded `embed.FS`)
- `identity` — external identity → local user, role management.
- HTTP: `identity/http` (ensure middleware + profile endpoints)
- Postgres: `identity/postgres` (configurable table names)
- Migrations: `identity.MustMigrationsFS()` (embedded `fs.FS`)
- `paymentsvc` — token pack catalog + checkout + webhook handling.
- HTTP: `paymentsvc/http` (Stripe webhook handler)
- `contact` — contact form message delivery via an email `Sender`.
- HTTP: `contact/http` (endpoint wrapper; you provide decode/validation)
## Installation
```bash
go get github.com/aatuh/api-svc@latest
```
## Quickstart (wiring example)
This repo is a library, not a runnable server. Your application wires
services with adapters (for Postgres, Stripe, email, etc.) and mounts the
HTTP handlers onto your router.
### Identity + profile endpoints
```go
package main
import (
"log"
"net/http"
"github.com/aatuh/api-svc/identity"
identityhttp "github.com/aatuh/api-svc/identity/http"
identitypg "github.com/aatuh/api-svc/identity/postgres"
"github.com/aatuh/api-toolkit/adapters/chi"
"github.com/aatuh/api-toolkit/adapters/clock"
"github.com/aatuh/api-toolkit/adapters/logzap"
"github.com/aatuh/api-toolkit/adapters/pgxpool"
"github.com/aatuh/api-toolkit/adapters/txpostgres"
"github.com/aatuh/api-toolkit/adapters/uuid"
)
func main() {
pool, err := pgxpool.New("postgres://user:pass@localhost:5432/app?sslmode=disable")
if err != nil {
log.Fatal(err)
}
defer pool.Close()
tx := txpostgres.New(pool)
logr := logzap.NewProduction()
clk := clock.NewSystemClock()
ids := uuid.NewUUIDGen()
repo := identitypg.NewRepo(pool, identitypg.DefaultConfig())
svc := identity.NewDefault(repo, tx, logr, clk, ids)
r := chi.New()
r.Mount("/me", identityhttp.NewProfileHandler(identityhttp.ProfileConfig{
Service: svc,
}).Routes())
log.Fatal(http.ListenAndServe(":8080", r))
}
```
## Configuration
Configuration is expressed as plain structs. Some services include helper
loaders that read environment variables via `api-toolkit/config.Loader`.
## Postgres adapters and migrations
Some services include Postgres adapters and embedded SQL migrations.
Migrations are designed to be run via `api-toolkit/migrator` (or its
`adapters/migrate` wrapper) without requiring a migrations directory on
disk.
```go
package main
import (
"context"
"io/fs"
billingmigrations "github.com/aatuh/api-svc/billingsvc/migrations"
creditsmigrations "github.com/aatuh/api-svc/creditsvc/migrations"
"github.com/aatuh/api-svc/identity"
"github.com/aatuh/api-toolkit/adapters/migrate"
"github.com/aatuh/api-toolkit/adapters/logzap"
)
func migrateDB(ctx context.Context, dsn string) error {
log := logzap.NewProduction()
m, err := migrate.New(migrate.Options{
DSN: dsn,
Log: log,
EmbeddedFSs: []fs.FS{
identity.MustMigrationsFS(),
billingmigrations.Migrations,
creditsmigrations.Migrations,
},
})
if err != nil {
return err
}
defer m.Close()
return m.Up(ctx, "")
}
```
## HTTP handlers
Services that ship HTTP handlers expose reusable routers/handlers that
follow a consistent flow: decode → validate → service call → encode.
Defaults use RFC‑7807 Problem+JSON via `api-toolkit/httpx`, and most
handlers allow overriding the encoding/problem writers.
Starting points:
- Billing routes: `billingsvc/http/handler.go`
- Contact endpoint wrapper: `contact/http/handler.go`
- Identity middleware and profile endpoints: `identity/http/middleware.go`,
`identity/http/profile_handler.go`
- Stripe webhook fan-out: `paymentsvc/http/stripe_webhook.go`
## Development
- Run: `go test ./...` (if you’re inside a larger repo with a parent
`go.work` that doesn’t include this module, use `GOWORK=off go test ./...`)
- Format: `gofmt -w .`
## License
Apache-2.0. See `LICENSE`.