Scalable, maintainable, and production-ready microservices in Go, powered by Clean Architecture & DDD.
- π§Ή Clean Architecture: Handlers β Services β Models
- ποΈ Domain-Driven Design (DDD): Modular, business-focused code
- π¦ Scalable Structure: Add new domains/services with zero coupling
- π Flexible Integration: REST, gRPC, GraphQL ready
- π§ͺ Testable Services: Clear boundaries for easy testing
- β‘ Minimal Boilerplate: Production-ready from the start
flowchart TD
%% --- AWS Services Layer ---
subgraph AWS["AWS Managed Services"]
Cognito["Cognito (User Authentication)"]
APIGW["API Gateway (Entry Point)"]
end
%% --- Lambda Layer ---
subgraph Lambda["AWS Lambda (Custom Code)"]
Route["Route"]
Handler["Handler"]
Validator["Validation"]
Service["Service Layer"]
Repo["Repository Layer"]
end
%% --- Databases ---
DynamoDB[("DynamoDB")]
OpenSearchDB[("OpenSearch DB")]
%% --- Client/User ---
User["User / Client"]
%% --- Flows ---
User -->|Sign in| Cognito
User -->|API call with JWT in header| APIGW
APIGW -->|Invoke Lambda for Users Service| Route
APIGW -->|Invoke Lambda for Items Service| Route
%% Inside Lambda execution path
Route --> Handler
Handler --> Validator
Validator --> Service
Service --> Repo
%% Repos to DBs
Repo --> DynamoDB
Repo --> OpenSearchDB
How it works:
- Users authenticate with Cognito and receive a JWT token.
- API requests include the JWT in the Authorization header.
- API Gateway forwards requests to the appropriate Lambda (users/items).
- Each Lambda's main.go calls the internal route, which calls the handler.
- The handler validates/authenticates the JWT, then calls the service layer for business logic.
- The service layer calls the repo layer for DB operations (DynamoDB for users, OpenSearch for items).
cmd/
βββ users/
βββ main.go # Entry point for Users microservice
internal/
βββ users/
βββ routes.go # Routes & handler mapping
βββ handler.go # HTTP handlers
βββ service.go # Business logic
βββ model.go # Domain models/entities
βββ repo.go # crud operations for db
βββ type.go # request response types for validation
- main.go: Lambda entry point, loads config, sets up router, and starts the service.
- routes.go: Registers endpoints and maps them to handlers.
- handler.go: Processes requests, extracts and validates JWT from headers, and calls the service layer.
- type.go: Contains request/response DTOs for validation.
- service.go: Contains business logic and orchestrates workflows.
- model.go: Defines domain entities and data structures.
- repo.go: Handles DB operations (DynamoDB for users, OpenSearch for items).
- Language: Go (Golang)
- Cloud: AWS (tested with Cognito, Api gateway and lambdas)
- Architecture: Clean Architecture + DDD
- Routing: chi
- Persistence: Extendable (DynamoDB)
- Validation: go-playground/validator
- Authentication: using jwt for extracting userId
- β Single Responsibility: Each layer does one job
- β Dependency Inversion: Inner layers never depend on outer
- β Explicit Boundaries: Clear contracts between layers
- β Scalability: Easily add new domains
- Create an AWS Account if you don't have one.
- Install Go (1.22+ recommended).
- Install AWS CLI and configure your credentials:
aws configure
- Cognito: Create a User Pool and an App Client (enable USER_PASSWORD_AUTH). Quickstart Guide
- Add a test user via AWS Console or CLI.
- Use the AWS Console or AdminCreateUser CLI.
- Get a JWT token for your test user:
curl -X POST -H "Content-Type: application/x-amz-json-1.1" \ -H "X-Amz-Target: AWSCognitoIdentityProviderService.InitiateAuth" \ -d '{"AuthParameters": {"USERNAME": "<your_email>", "PASSWORD": "<your_password>"}, "AuthFlow": "USER_PASSWORD_AUTH", "ClientId": "<your_cognito_app_client_id>"}' \ https://cognito-idp.<region>.amazonaws.com/
- Copy the
IdTokenfrom the response and use it as your JWT in API requests.
- Copy the
- DynamoDB: Create a Table (e.g.,
users). - Lambda: Deploy your Go binary as a Lambda function if you want to run on AWS. You can also run locally with
go run ./cmd/users/main.gofor quick testing and development. - OpenSearch (optional, for items service): Create a domain and index. Warning: OpenSearch can incur significant costs if not managed carefully. Use the free tier or development domains for testing.
Note: You do NOT need to set up API Gateway to test locally or to deploy your Lambda if you are invoking it directly or using the AWS Lambda console. API Gateway is only needed if you want to expose your Lambda as a public HTTP endpoint.
Create a .env file in your project root with:
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_REGION=your-region
USERS_TABLE=users
LOCAL=true
OPEN_SEARCH_END_POINT=https://your-opensearch-endpoint
OPEN_SEARCH_INDEX=your-index
β οΈ Warning: Never commit your.envfile or secrets to version control.
# Clone repo
git clone https://github.com/usman250994/go-serverless-microservices.git
# Run users service locally
cd cmd/users
go run main.go
# Run items service locally (requires OpenSearch setup)
cd ../items
go run main.go-
Get a JWT token (see Cognito curl above).
-
Call the test endpoint:
POST
http://localhost:8080/userHeaders:
Authorization: Bearer <your_id_token>Content-Type: application/json
Body (JSON):
{ "name": "john", "email": "doe@gmail.com", "ratings": 25.0, "userType": "renter" }π§βπ» This is a test API in this boilerplate. Fork and extend for your own product!
- Build your Go binary for Linux:
GOOS=linux GOARCH=amd64 go build -o main ./cmd/users/main.go zip deployment.zip main # Upload deployment.zip to Lambda via AWS Console or CLI - Set environment variables in the Lambda console to match your
.envfile. - Connect your Lambda to API Gateway for public access.
OpenSearch can incur significant costs if not managed carefully.
- Use the free tier or development domains for testing.
- Delete unused domains promptly.
- Monitor your AWS billing dashboard regularly.
- ποΈ Database Abstraction: Internal package for DynamoDB accessβcleaner, decoupled repo logic.
- π‘ Event Streaming: Integrate AWS SNS, SQS, and DynamoDB Streams for real-time event sourcing.
- π Query Wrapper: Generic query builder to simplify and standardize DynamoDB queries.
Contributions are welcome! Open issues or PRs to improve structure or add features.
MIT License β use this boilerplate for your own projects.