Go powered (clean architecture inspired) RESTful Blog API with crud operations, caching features, authentication and authorization mechanisms, and more. It uses Postgresql for storage, Redis for caching, Swagger for documentation, etc.
- Features
- Directory Layout
- System Architecture Diagram
- Database Entity-Relationship Diagram
- Commands (CLI tools explanation)
- Setup and Test
- License
- Clean architecture inspired: this project's system design follows some basics principles (not all principles) of clean architecture to improve maintainability, make testing easier, increase flexibility and reusability, etc. (check System Architecture Diagram and Directory Layout sections below to see more details)
- JWT based authentication (implemented here - used in AuthMiddleware and AuthService)
- Hybrid RBAC-Ownership access control system (implemented in AccessControlMiddleware and used in routes).
brief explanation:- Admin or Superuser: user with all accessibility and permissions (to manipulate everything)
- Owner: only owner of each resource (posts, lists, comments, etc.) can manipulate (update or delete) that resource.
- Viewer: viewers can only read other's resources.
- Developed CLI tools to manage database migrations, server startup, etc. (powered by cobra) (implemented in cmd/commands/ - check Commands section below to see more details)
- Implemented constructor based dependency injection (check at internal/dependencies and internal/http/dependencies.go)
- Defined database schemas using raw SQL (check at migrations/) - see Database Entity-Relationship Diagram section below and review the Project's Database Design
- Implemented repository pattern to organization CRUD operations, avoid tight coupling and simplify repository mocking in unit tests (check these: repo interface definitions / dependency injector / services / tests)
- Implemented CRUD operations with standard and optimized database queries using raw SQL (check here)
- Defined custom database errors to simplify handling Postgresql related errors and translating them for application services (check here)
- Defined custom service errors to standardize application's error handling and generate proper message and code, to simplify making proper http-error-responses for Gin Handlers (here)
- Implemented GENERIC based Handlers, Services, and Postgres Repositories, to centralize code logic as much as possible (by summarizing repetitive operations to one GENERIC all-inclusive function, and following DRY -don't repeat yourself- principle) (check them at: GENERIC_HANDLERS / GENERIC_SERVICES / BASE_REPOSITORY)
- Designed
StandardResponseto generate and send all successful/error responses in one standard way - Implemented Validation Error Translation to convert input (request data) validation errors to human readable messages
- Designed and implemented Token Revocation strategy (backed by Redis) (implemented here - used in AuthService)
- blacklist/revoke used but non-expired JWTs (until they expire)
- blacklist-check for incoming JWTs (through cookie or Authorization header) to avoid abusing them
- Implemented UserInfoCache (backed by Redis) : caching essential and commonly used user-information to make user related operations (authentication, access control check, user info fetching, etc.) faster (implemented here - used in AuthMiddleware and AuthService and UserService)
- Included hashing features to improve security (like: PasswordHasher to store and verify hashed passwords instead of plain passwords, etc.)
- Added Swagger documentation (see Swagger Docs Preview section below)
- And more... (see below sections, and explore project's source code and discover other features!)
Go-Blog-API
│
├── assets/
├── cmd/
│ ├── commands/
│ │ ├── rootCmd.go # project's root command setup
│ │ ├── migrate.go # implements migration related commands to work with db migrations
│ │ ├── serve.go # implements `serve` command to init all dependencies and run server
│ │ └── superuser.go # implements `create-superuser` & `delete-superuser` commands
│ └── main.go # project entry point (setup above commands)
│
├── config/ # load and initialize all project configurations
├── docs/ # swagger documentation utilities
├── internal/
│ │
│ ├── application/ # [Business Logic Layer]
│ │ ├── service_errors/ # custom defined service error (standardize errors for response)
│ │ └── services/ # services (or usecases) implement business logic (layer
│ │ # between handlers and concrete repositories)
│ │
│ ├── dependencies/ # dependency injectors (based on the defined contracts in domain)
│ │
│ ├── domain/ # [Domain Layer]
│ │ ├── entity/ # database entity definitions
│ │ ├── repository/ # repository interfaces to organize working with db entities
│ │ ├── pagination.go # implements pagination logic for database queries
│ │ └── rules.go # implements some rules for some entity fields
│ │
│ ├── http/ # [Delivery Layer]
│ │ ├── dto/ # DTOs to handle data flow (request validation & response construction)
│ │ ├── generics/ # generic type interfaces used in GENERIC Handlers and services
│ │ ├── handlers/ # endpoint handlers (bind requests, call services, serialize responses)
│ │ ├── helpers/ # helpers for generating standard responses, etc.
│ │ ├── middlewares/ # api endpoint middlewares
│ │ ├── validations/ # validation error handling + custom defined validations
│ │ ├── dependencies.go # DependencyContainer includes all api endpoint dependencies (all
│ │ │ # repositories, services, handlers, infrastructure services, etc.)
│ │ ├── router.go # api endpoints and routes
│ │ └── server.go # main api server setup and initialization
│ │
│ └── infra # [Infrastructure]
│ ├── database/
│ │ ├── postgres_repository/ # concrete repository (CRUD) implementation for all entities
│ │ ├── errors/ # database error handling + custom defined DB errors
│ │ └── database.go # database (postgresql) connection setup
│ │
│ ├── redis/
│ │ ├── redis.go # redis connection setup
│ │ ├── token_revocation.go # blacklisting logic for used-JWTs to avoid abusing them
│ │ └── user_info.go # caching essential and mainly used user information
│ │
│ └── security/
│ ├── hashing/ # hashing features to improve security (like: PasswordHasher, etc.)
│ └── jwt/ # jwt service implementation
│
├── migrations/ # database migrations (table and column definitions using raw SQL)
├── pkg/
│ ├── constants/ # includes commonly used keys as constants
│ └── logging/ # logger setup
├── tests/ # ...
├── .gitignore
├── config.sample.yml
├── go.mod
├── go.sum
├── LICENSE
└── README.mdIncludes pure business objects that encapsulate enterprise-business rules which are independent of any external frameworks or technologies. This layer is the most stable and least likely to change.
Contains application-specific business rules. it orchestrates the flow of data between delivery and domain layers, and represents the application's behavior and specific actions a user can take.
This layer is responsible for providing the infrastructure and external tools that other layers depend on; including database connection setup and concrete repository implementations (postgres repositories), redis connection setup, (third-party) security services, and more. Implementations in infrastructure satisfies the interfaces defined in the domain layer.
This separation makes it convenient to change any infrastructure implementation at any time.
It's the outermost layer of the system, and contains main application entry point. this layer is responsible for receiving external requests, calling service layer, and returning responses to the outside clients.
the Dependency Rule of Clean Architecture: Source code dependencies can only point inward. An inner circle can know nothing about an outer circle.
This project's system design violates The Dependency Rule at one point. see application/ or [Business Logic Layer] in the Directory Structure section again and check its source code.
I use http Request DTOs directly in services, and return http Response DTOs directly from services; (in other words: application/service layer has one outward dependency and imports http layer DTOs) and this violates the Dependency Rule of Clean Architecture.
To fix that and follow Dependency Rule, I should:
- Define dependent Input & Output DTOs in application or service layer
- And define DTO Mappers to convert:
- http Request DTOs to service Input DTOs
- service Output DTOs to http Response DTOs
I think the decision in this situation is a tradeoff... defining dependent application layer DTOs and DTO Mappers adds 2 more steps to http handlers logic:
- mapping http Request DTO to service Input DTO before calling related service
- mapping service Output DTO to http Response DTO after getting related service's result
and I think these are 2 extra operations, and clutters the source code and increase performance cost. So in this situation, I preferred to violate the Dependency Rule on purpose, and keep system's performance more efficient, and the source code simpler... :)))
here's a brief description for all of the project's CLI commands
-
serve: init and run the api servergo run ./cmd serve
-
migrate: base command to handle database migrations-
up: apply all or N up migrationsflags:
-s,--stepsINT : number of steps for up migration (if not set: apply all up migrations)go run ./cmd migrate up # apply all up migrations go run ./cmd migrate up --steps 1 # apply 1 up migration
-
down: apply N down migrationsflags:
-s,--stepsINT : number of steps for down migration (required)go run ./cmd migrate down --steps 1 # apply 1 down migration go run ./cmd migrate down --steps 2 # apply 2 down migration
NOTE: you can't apply all down migrations at once, and
-sor--stepsflag is required for this command -
force: set version V but don't run migration (ignores dirty state)go run ./cmd force 7 # set migration version to 7 go run ./cmd force 4 # set migration version to 4
-
-
create-superuser: start an interactive prompt to create a superuser (a user with all accessibility and permissions)go run ./cmd create-superuser
-
delete-superuser: start an interactive prompt to delete a superusergo run ./cmd delete-superuser
Requirements: Docker
Guide for setting up the project using docker will be added soon!!!
Requirements: Go - Postgresql - Redis
-
1. Clone the repository:
git clone https://github.com/hamidgh01/Go-Blog-API.git
or download the zip file, and unzip
-
2. Install dependencies:
cd Go-Blog-API go mod tidy -
3. Set up your config file:
Copy
config.sample.ymltoconfig.ymlcp config.sample.yml config.yml
and fill in the needed field properly (JWT, postgres, redis, etc.).
-
4. Apply all database up migrations:
go run ./cmd migrate up
if migrations applied successfully, the result should be log messages like these:
2026/06/20 20:35:43 direction: UP 2026/06/20 20:35:43 all UP migrations applied successfully 2026/06/20 20:35:43 current migration version: 8 (dirty: false) 2026/06/20 20:35:43 migrate source and database closed
-
5. Run the api server:
go run ./cmd serve
Access the API docs here: http://127.0.0.1:8000/api/swagger/index.html (change the host:port based on your configurations in config.yml)
This project is licensed under the MIT License. See the LICENSE File for more details.
Developed by hamidgh01
