A robust, production-ready RESTful API designed for content management, built with Go, Gin, and PostgreSQL.
π Background:
This project was originally developed as a comprehensive implementation of the backend challenges from roadmap.sh, specifically combining concepts from the Blogging Platform API and Todo List API projects. It has since evolved into a well-structured boilerplate demonstrating modern Go practices.
- Clean Architecture: Strict separation of concerns across
handlers,repository, andmodels. - Advanced Security:
bcryptpassword hashing, JWT Access & Refresh token rotation, and strict resource ownership validation. - Robust Database: PostgreSQL integration using
pgxpoolfor optimal connection pooling and/migrationsfor reliable schema management. - High Reliability: Includes comprehensive Integration Tests to ensure production readiness.
- Developer Experience: Fully containerized with Docker, automated tasks via
Makefile, and auto-generated Swagger OpenAPI docs. - Content Management: Full CRUD operations with pagination (
limit/offset) and text search.
| Component | Technology |
|---|---|
| Language | Go (Golang) |
| Web Framework | Gin |
| Database | PostgreSQL |
| DB Driver | pgxpool |
| Auth | JWT (Access & Refresh) + bcrypt |
| Documentation | Swagger (swaggo) |
| Infrastructure | Docker & Docker Compose |
| Testing | Go testing + Integration Tests |
gin-content-api
β
βββ auth/ # Authentication utilities
β βββ password.go # Bcrypt password hashing and validation
β βββ token.go # JWT Access and Refresh token generation/parsing
β
βββ db/ # Database configuration
β βββ database.go # pgxpool connection initialization
β
βββ docs/ # Auto-generated Swagger OpenAPI documentation
β βββ docs.go
β βββ swagger.json
β βββ swagger.yaml
β
βββ handlers/ # Controllers handling HTTP requests and responses
β βββ auth.go # Login, Register, Refresh endpoints
β βββ me.go # Get current authenticated user profile
β βββ ping.go # Health check endpoint
β βββ posts.go # CRUD handlers for content
β
βββ integration/ # E2E & Integration tests
β βββ setup_test.go # Test DB setup and teardown logic
β βββ ..._test.go # API endpoint tests
β
βββ migrations/ # SQL files for database schema migrations
β βββ 001_...sql # Users table migration
β βββ 002_...sql # Posts table migration
β
βββ models/ # Domain models and request/response structs
β βββ post.go # Post structures
β βββ user.go # User structures
β
βββ repository/ # Data access layer (PostgreSQL queries)
β βββ posts_repo.go # Database operations for posts
β βββ users_repo.go # Database operations for users
β
βββ router/ # Gin router configuration and middleware
β βββ middleware.go # JWT validation middleware
β βββ router.go # API route registration
β
βββ .env.example # Example environment variables template
βββ .gitignore # Git ignore rules
βββ docker-compose.yml # Container orchestration (API + DB instances)
βββ Dockerfile # Instructions to build the Go app container
βββ Makefile # Automation commands (run, test, migrate)
βββ main.go # Entry point: wires up DB, repos, handlers, and starts server
First, clone the repository to your local machine:
git clone https://github.com/GanFay/gin-content-api.git
cd gin-content-apiThe easiest way to get the API and the database running together is via Docker Compose.
# Start the application and database in the background
make dev
# OR
docker compose up --build -d
migrate -path migrations -database ${your_db_url} up- The API will be available at:
http://localhost:8080 - Swagger UI will be at:
http://localhost:8080/swagger/index.html
If you prefer to run the Go app directly on your machine, you must set up the database manually.
- Start PostgreSQL: You can run just the database container or use a native local installation.
docker-compose up -d postgres # OR locally run postgresql - Install Dependencies:
go mod tidy
- Environment Variables: Create a
.envfile in the root directory based on.env.example. - Apply Migrations: Ensure your DB schema is up to date using the
/migrationsfolder.
make migrations-up
# OR
migrate -path migrations -database ${your_db_url} up- Run the Application:
make run-app # OR go run main.go
To execute all tests, ensure your database is running and execute:
go test ./... -vCreate a .env file in the root of your project:
# Full database connection string
DB_URL=postgres://your_user:your_password@localhost:5432/your_db_name?sslmode=disable
# JWT secrets for authentication (replace with secure random strings)
JWT_SECRET_ACCESS=your_strongest_jwt_access_key
JWT_SECRET_REFRESH=your_strongest_jwt_refresh_key
# Individual database credentials (must match the values in DB_URL)
PG_USER=your_user
PG_PASSWORD=your_password
PG_DB=your_db_name| Method | Endpoint | Description |
|---|---|---|
GET |
/ping |
Health check |
POST |
/auth/register |
Register a new user |
POST |
/auth/login |
Login user (returns Access & Refresh tokens) |
GET |
/auth/refresh |
Refresh an expired access token(require a cookie token) |
Header: Authorization: Bearer <access_token>
| Method | Endpoint | Description |
|---|---|---|
GET |
/users/me |
Get current authenticated user details |
POST |
/auth/logout |
Logout user (invalidates refresh token) |
POST |
/posts |
Create a new post |
GET |
/posts |
Get all posts (supports limit and offset) |
GET |
/posts/:id |
Get post by ID |
PUT |
/posts/:id |
Update post (Author only) |
DELETE |
/posts/:id |
Delete post (Author only) |
- Login: Send
POST /auth/loginwithemailandpassword. The API returns anaccess_tokenandrefresh_token. - Access API: Attach
Authorization: Bearer <access_token>to protected requests. - Refresh: When the
access_tokenexpires, send a request toGET /auth/refreshusing your refresh token to obtain a new pair. - Logout: Send
POST /auth/logoutto securely revoke tokens.
The /posts endpoint supports query parameters for pagination and filtering:
GET /posts?limit=10&offset=0&term=golang| Parameter | Type | Description |
|---|---|---|
limit |
int | Number of records to return (e.g., 10) |
offset |
int | Number of records to skip |
term |
string | Search posts by text (title/content) |
The schema is strictly managed via the /migrations directory.
| Column | Description |
|---|---|
id |
Primary Key |
username |
Unique username |
email |
Unique email |
password_hash |
Bcrypt hashed password |
created_at |
Account creation timestamp |
| Column | Description |
|---|---|
id |
Primary Key |
author_id |
Foreign key referencing users(id) |
title |
Post title |
content |
Post body |
category |
Category tag |
tags |
Associated tags array |
created_at |
Creation timestamp |
updated_at |
Last update timestamp |
This project is licensed under the MIT License.