This sample demonstrates a simple Payments server with a REST API exposed over HTTP.
API is modeled with REST principles in mind. A single resource to manage payments is exposed at the moment. By default payment instances are persisted using PostgreSQL, but this can be easily switched to any other RDBMS (or NoSQL database if desired). The API is described using OpenAPI v3, see the specs file directly or run the server and navigate to http://localhost:8080/docs
. It follows the Zalando guidelines for defining RESTful APIs.
Retrieve collection of payments.
Retrieve an existing payment.
Create a new payment.
Edit an existing payment.
Delete an existing payment.
You have two options, either use Docker Compose and run docker-compose up
or run server locally go run cmd/payments-server/main.go -http :8080 -database postgres:///payments -migrations file://./scripts/migrations/postgres
. In order to run server locally you have to have a running Postgres database server with a database named payments
created. Server can be gracefully shut down by sending it the SIGINT
or SIGTERM
signals (just use CTRL+C
when running locally).
Codebase is unit-tested and dependencies are mocked so no database is required to be prepared, just run go test ./...
.
The acknowledged standard Go project structure is used to avoid confusion.
Exposed payment resource follows the json:api specification. The structure is reflected in the code: a Payments API defines a single payment resource which ensures a correct payloads are being exchanged as per the json:api specification. The resource then delegates to a payments service which encapsulates business logic, validation and orchestrates the calls to stores (repositories). Stores ensures the resource's parts are correctly persisted and loaded to/from the database.
Each layer is abstracted using Go interfaces to allow easy unit-testing and enable transparently add/replace specific implementations.
As per Go best practices interfaces are implied, i.e. not being defined on the implementing side, but on the consuming side instead.
The Payments domain is described in the domain package, which the defines primitive and complex objects used by the resource, service and stores.
All errors are being wrapped in to a single common structure to allow proper conversions to HTTP statuses and json:api error payloads.