A production-oriented e-commerce backend built with Go, demonstrating a robust Microservices Architecture. The system employs a GraphQL API Gateway as its single public entry point, delegating complex operations to highly decoupled internal microservices communicating over ultra-fast gRPC using Protocol Buffers.
This architecture was deliberately chosen to combine the flexibility of GraphQL (solving over-fetching and under-fetching for client applications) with the raw performance and strict contract definitions of gRPC for internal service-to-service communication.
| Category | Technology |
|---|---|
| Language | Go (Golang 1.24+) |
| API Gateway | GraphQL (gqlgen) |
| RPC / Internal Comms | gRPC |
| Data Serialization | Protocol Buffers (Protobuf) |
| Database | PostgreSQL |
| Containerization | Docker & Docker Compose |
| Workspace Management | Go Workspaces (go.work) |
- GraphQL API Gateway: A single, flexible interface for clients resolving queries by aggregating data from internal services.
- Microservices Architecture: Completely isolated domain services (User, Order, Tracking) preventing monolithic entanglement.
- gRPC Communication: Lightning-fast, binary-encoded internal service communication.
- Protocol Buffers: Strongly typed API contracts acting as the single source of truth (
pkg/pb). - PostgreSQL Integration: Relational database persistence utilizing optimized connection pooling.
- Dockerized Deployment: Secure, non-root multi-stage Docker builds for minimal production image footprints.
- Production-Ready Configuration: Dynamic configuration utilizing
.envfiles for seamless orchestration platforms (Render, Kubernetes). - Resiliency & Graceful Shutdown: HTTP/gRPC server lifecycle management preventing hanging connections and dropped requests during deployments.
- Health Probes: Standardized HTTP (
/healthz) and gRPC health checks configured for orchestrator monitoring.
The system strictly encapsulates its logic. External clients communicate solely with the GraphQL Gateway. The Gateway parses the queries and acts as a gRPC client, forwarding requests to the respective backend services. The backend services then interact with the PostgreSQL database to persist and retrieve state.
graph TD
Client((Client))
subgraph "Public Facing"
Gateway[GraphQL API Gateway<br>:8080]
end
subgraph "Internal gRPC Microservices"
User[User Service<br>:50051]
Order[Order Service<br>:50052]
Tracking[Tracking Service<br>:50053]
end
DB[(PostgreSQL Database<br>:5432)]
Client -- HTTP POST /query --> Gateway
Gateway -- gRPC --> User
Gateway -- gRPC --> Order
Gateway -- gRPC --> Tracking
User -- TCP --> DB
Order -- TCP --> DB
Tracking -- TCP --> DB
- A client requests an Order along with its Tracking status via GraphQL.
- The Gateway receives the query.
- The Gateway makes a gRPC call to the Order Service to fetch the order details.
- The Gateway concurrently makes a gRPC call to the Tracking Service to fetch the tracking updates.
- The Gateway aggregates the responses and returns a single JSON object back to the client.
The repository utilizes Go Workspaces (go.work) to manage multiple independent modules while sharing a centralized Protobuf module.
.
βββ api/
β βββ proto/ # Single source of truth for Protobuf definitions (.proto)
βββ pkg/
β βββ pb/ # Shared Go Workspace module containing generated gRPC code
β βββ orderpb/
β βββ trackingpb/
β βββ userpb/
βββ api_gateway/ # GraphQL API Gateway (Independent Go Module)
β βββ cmd/server/main.go # Gateway entry point
β βββ internal/graph/ # GraphQL Schema & generated code
β βββ Dockerfile
βββ services/
β βββ order_service/ # Order Domain Service (Independent Go Module)
β β βββ cmd/server/main.go
β β βββ internal/grpc_server/
β β βββ Dockerfile
β βββ tracking_service/ # Tracking Domain Service (Independent Go Module)
β βββ user_service/ # User Domain Service (Independent Go Module)
βββ .env.example # Environment variables template
βββ docker-compose.yml # Local orchestration configuration
βββ go.work # Go workspace defining local module relationships
- Docker & Docker Compose
- Go 1.24+ (If running without Docker)
- Make (Optional, for scripts)
git clone https://github.com/Shreyas071845/Microservices.git
cd MicroservicesCopy the example environment file:
cp .env.example .envDocker Compose will build the gateway, the 3 microservices, and spin up a PostgreSQL instance.
docker-compose up --build(The GraphQL Gateway is now accessible at http://localhost:8080/)
# Stop and remove containers and networks
docker-compose down
# Stop, remove containers, networks, AND volumes (wipes the database)
docker-compose down -vThe system is fully configurable. The following variables are sourced from .env:
| Variable | Description | Default Value |
|---|---|---|
PORT |
API Gateway HTTP port | 8080 |
USER_SERVICE_ADDR |
Address for gRPC User Service | user-server:50051 |
ORDER_SERVICE_ADDR |
Address for gRPC Order Service | order-server:50052 |
TRACKING_SERVICE_ADDR |
Address for gRPC Tracking Service | tracking-server:50053 |
USER_SERVICE_PORT |
Port for the User Service to listen on | 50051 |
ORDER_SERVICE_PORT |
Port for the Order Service to listen on | 50052 |
TRACKING_SERVICE_PORT |
Port for the Tracking Service to listen on | 50053 |
DATABASE_URL |
PostgreSQL connection string | postgres://devuser:devpassword@postgres-db:5432/assignment_db?sslmode=disable |
Thanks to go.work, running the microservices locally on bare-metal is seamless. Ensure you have a local PostgreSQL instance running and matching your .env DATABASE_URL.
Start each service in a separate terminal from the repository root:
# Terminal 1: User Service
cd services/user_service && go run ./cmd/server
# Terminal 2: Order Service
cd services/order_service && go run ./cmd/server
# Terminal 3: Tracking Service
cd services/tracking_service && go run ./cmd/server
# Terminal 4: API Gateway
cd api_gateway && go run ./cmd/serverAccess the GraphQL endpoint via POST requests to http://localhost:8080/query.
Request:
mutation {
createUser(input: {
name: "Jane Doe"
email: "jane@example.com"
}) {
id
name
email
}
}Response:
{
"data": {
"createUser": {
"id": "a1b2c3d4",
"name": "Jane Doe",
"email": "jane@example.com"
}
}
}Request:
mutation {
createOrder(input: {
userId: "a1b2c3d4"
productName: "Mechanical Keyboard"
quantity: 1
}) {
id
userId
productName
status
}
}Response:
{
"data": {
"createOrder": {
"id": "x9y8z7",
"userId": "a1b2c3d4",
"productName": "Mechanical Keyboard",
"status": "PENDING"
}
}
}Request:
query {
listUsers {
id
name
email
}
}Response:
{
"data": {
"listUsers": [
{
"id": "a1b2c3d4",
"name": "Jane Doe",
"email": "jane@example.com"
}
]
}
}| Service | Exposes | Responsibilities | Protocol |
|---|---|---|---|
| API Gateway | :8080 (HTTP) |
Single entry point. Aggregates data via GraphQL resolvers. Maps GraphQL to gRPC. | HTTP/GraphQL |
| User Service | :50051 (gRPC) |
Manages User lifecycle, persistence, and queries. | gRPC |
| Order Service | :50052 (gRPC) |
Manages Order lifecycle. Validates relationships (e.g., User exists). | gRPC |
| Tracking Service | :50053 (gRPC) |
Manages shipping updates, geo-location state, and tracking statuses. | gRPC |
The project emphasizes immutable, production-ready containers.
- Multi-stage Builds: Every
Dockerfilecompiles the Go binary usinggolang:alpineand copies it into a lightweight, scratch/alpine image. - Security: Binaries are executed by an unprivileged
appuseruser rather thanroot. - Workspace Resolution: Docker build contexts are set to the root directory (
.) to allow the compiler to pull the sharedpkg/pbmodule effortlessly. - Internal Networking: Services communicate over Docker Compose's bridge network using internal DNS resolution (e.g.,
user-server:50051).
This project implements rigorous production-hardening standards:
- Graceful Shutdown: The API Gateway and gRPC servers intercept
SIGINT/SIGTERMto safely drain active requests before terminating. - Connection Pooling: PostgreSQL
*sql.DBinstances enforce explicit limits (SetMaxOpenConns,SetMaxIdleConns,SetConnMaxLifetime) preventing port exhaustion. - gRPC Health Probes: Backend services expose standard
grpc_health_v1endpoints for Kubernetes/Cloud Orchestrator liveness/readiness probes. - HTTP Server Timeouts: The Gateway's
http.Serverutilizes strictReadTimeout,WriteTimeout, andIdleTimeoutbounds to mitigate slowloris attacks. - gRPC Retries: Inter-service communication benefits from transparent, policy-driven gRPC retries.
While this is a robust foundation, a highly-scaled enterprise system would further introduce:
- Authentication & Authorization: Implement JWT validation at the API Gateway and pass claims via gRPC metadata.
- Caching: Introduce a
Redislayer in front of PostgreSQL for heavy read-path queries (likelistUsers). - Distributed Tracing: Integrate OpenTelemetry (
Jaeger/Zipkin) to trace requests as they jump between the Gateway and gRPC boundaries. - Message Broker (Event-Driven): Introduce
KafkaorRabbitMQ. (e.g., Creating an order publishes anOrderCreatedevent that the Tracking Service consumes asynchronously instead of blocking). - Metrics: Expose Prometheus metrics endpoints to monitor GraphQL latency and gRPC error rates via Grafana.
This project is deployment-ready and has been successfully validated in a local Docker Compose environment.
Cloud deployment is currently in progress while evaluating the most suitable platform for a production-style microservices architecture.
Once finalized, this section will include:
- Live GraphQL API endpoint
- Health endpoint
- Deployment architecture
- Production deployment guide
- Why a GraphQL Gateway? In an E-commerce domain, clients often need deeply nested data (e.g., A user, their orders, and the tracking status of each order). A REST API would either require multiple round-trips or a massive over-fetching monolithic endpoint. GraphQL solves this elegantly.
- Why gRPC internally? While HTTP/JSON is great for public APIs, it's inefficient for internal microservices. gRPC utilizes HTTP/2 and binary Protobuf serialization, making it incredibly fast and strongly typed, ensuring breaking changes are caught at compile time.
- Why Go? Go was built for network services. Its lightweight goroutines naturally handle high-concurrency RPC connections, and its fast compile times and statically linked binaries make Docker deployments trivial and extremely small.
- Why a Shared Protobuf Module? Eliminates code duplication. All microservices depend on a single source of truth for their data contracts, drastically reducing the chances of structural drift.
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Copyright (c) 2026 Shreyas.
Distributed under the MIT License. See LICENSE for more information.