BACKEND & API ENGINEER
← All work

[ Go ] 2 of 6

The Gateway

Next.js BFF over a Go gateway: register upstream APIs, forward calls server-side.

cd project && docker compose up -d postgres
5 fails / 10 minConfig: login throttle
2 to 10Config: HPA replica range
30s (5s dial)Config: upstream timeout
20sConfig: BFF request abort
  • Next.js 15
  • React 19
  • TypeScript
  • chi + pgx
  • PostgreSQL
  • Kubernetes

[ 01 ] WHAT IT IS

In plain words

It is a self-hosted API management console: you register an upstream API by giving it an identifier, host, path, method, and the headers or parameters it may pass through, then the gateway forwards those calls for you.

It also manages store accounts (a client id plus a secret key you can regenerate) and keeps the login token in a server-side httpOnly cookie, so no JWT ever reaches browser JavaScript or localStorage.

It is for a developer or small team that wants one controlled front door for internal or third-party APIs instead of scattering upstream credentials across every client app.

[ 02 ] ARCHITECTURE

How it is put together

  • Browser to Next.js BFF: frontend/src/middleware.ts guards /home, /api/* and /store/*, and frontend/src/lib/session.ts keeps the JWT in an httpOnly, SameSite=Lax cookie.
  • frontend/src/app/gw/[...path]/route.ts dispatches the declarative route table in frontend/src/lib/gwRoutes.ts; frontend/src/lib/bffGateway.ts owns session to 401 mapping, the 20s AbortController, sanitization, and envelope to NextResponse translation.
  • Go surface: gateway-go/internal/handler/handler.go wires chi routes, leaving only /health and /gateway/user/login public; everything under /api/gateway and /api/store passes through the Bearer-token middleware in internal/handler/middleware.go.
  • Persistence: gateway-go/internal/store is split per entity (user, account, api, postgres.go) over pgx, and the signing secret is read per request from the system_properties table.
  • Forwarding: gateway-go/internal/service/forward.go takes a typed ForwardRequest and internal/service/upstream.go applies the persisted header allowlist, encodes the query once, and calls the upstream with a 5s dial and 30s client timeout.
  • Runtime: k8s/gateway-go/deployment.yaml runs 2 replicas with /health probes at 32Mi request / 64Mi limit, and hpa.yaml scales 2 to 10 pods on CPU 60% and memory 70%.

[ 03 ] INSTALL

Set it up

cd project && docker compose up -d postgres
psql "$DATABASE_URL" -f pg-init-scripts/gateway.sql   # still inside project/
cd ../gateway-go
DATABASE_URL=postgres://microservices:password@localhost:5432/gateway?sslmode=disable go run ./cmd/server
cd ../frontend && npm install
BACKEND_API_URL=http://localhost:8080 npm run dev

[ 04 ] QUICKSTART

See it work

  1. Seed the database with project/pg-init-scripts/gateway.sql: it creates the api_gateway table with three example upstreams pointing at https://api.thecatapi.com.
  2. Start the Go service and the frontend, then open http://localhost:3000 and sign in with a seeded user from that same SQL file.
  3. You land on /home (frontend/src/app/home/page.tsx) with API and Store tabs listing the configured upstreams and store accounts.
  4. Click an API row to open its detail page, edit the allowed headers and parameters, then press Try it Now! to send a real request through /gw/apis/execute/<identifier> and see the upstream response body.
  5. curl http://localhost:8080/health returns {"status":"ok"}, the same check the Kubernetes probes use.

[ 05 ] NUMBERS

What the repo states

Config: login throttle

REPO STATES

5 fails / 10 min

Config: HPA replica range

REPO STATES

2 to 10

Config: upstream timeout

REPO STATES

30s (5s dial)

Config: BFF request abort

REPO STATES

20s

[ 06 ] TRADEOFFS

What it does not do

  1. The README has no limitations section, so the scope notes here are read off the code rather than claimed.
  2. Login throttling is per-username and in memory (gateway-go/internal/auth/auth.go), so counters reset on restart and do not aggregate across the 2 to 10 replicas the HPA can run.
  3. The BFF route table accepts only GET and POST (frontend/src/lib/gwRoutes.ts) even though upstream forwarding itself supports GET, POST, PUT, PATCH and DELETE.
  4. Kubernetes manifests cover gateway-go only (k8s/gateway-go/); the frontend and PostgreSQL have no Deployment or Service, and the repo ships no benchmark or load-test numbers at all.

[ 07 ] SOURCE

Read the code

The full implementation, tests and documentation live in the repository.