A REST API written in Go using the standard net/http library. No frameworks. Built around a school management domain with teachers, students, and executives as resources. The focus was on middleware design and understanding what a production-grade API setup looks like without reaching for Gin or Chi.
ProductionRESTAPI/
├── cmd/
│ └── api/
│ └── server.go # Entry point, TLS config, middleware chain
├── internal/
│ ├── api/
│ │ ├── handlers/
│ │ │ ├── root.go # GET /
│ │ │ ├── teachers.go # Full CRUD for /teachers/
│ │ │ ├── students.go # Stub handlers
│ │ │ └── execs.go # Stub handlers
│ │ ├── middlewares/
│ │ │ ├── cors.go # CORS with origin whitelist
│ │ │ ├── security_headers.go # OWASP security headers
│ │ │ ├── rate_limiter.go # IP-based rate limiting
│ │ │ ├── compression.go # gzip response compression
│ │ │ ├── hpp.go # HTTP Parameter Pollution protection
│ │ │ └── response_time.go # Response time logging
│ │ └── router/
│ │ └── router.go # Route definitions
│ ├── models/
│ │ ├── teacher.go
│ │ └── student.go
│ └── repository/
│ └── sqlconnect/
│ ├── sqlconfig.go # DB connection (singleton pool)
│ └── teacher_crud.go # All DB operations for teachers
└── pkg/
└── utils/
├── error_handler.go # Centralized error logging
└── middlewareutils.go # ApplyMiddlewares helper
- Go 1.21 or later
- MariaDB or MySQL
- A TLS certificate and key (
cert.pem,key.pem) in the project root — the server runs HTTPS only - A
.envfile in the project root
Create a .env file in the root of the project:
API_PORT=:8443
DB_USER=your_db_user
DB_PASSWORD=your_db_password
DB_NAME=your_db_name
DB_PORT=3306
HOST=localhostThe API expects a teachers table. Run this against your database before starting the server:
CREATE TABLE teachers (
id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(100) NOT NULL,
last_name VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL,
class VARCHAR(50) NOT NULL,
subject VARCHAR(100) NOT NULL
);The server will not start without a certificate. For local development, generate a self-signed one:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodesgit clone https://github.com/StupidAfCoder/ProductionRESTAPI.git
cd ProductionRESTAPI
go mod tidy
go run cmd/api/server.goOnly the /teachers/ resource has a complete implementation. Students and executives routes exist but are stubs that return plain text.
| Method | Endpoint | Description |
|---|---|---|
GET |
/teachers/ |
Get all teachers. Supports filtering and sorting via query params. |
POST |
/teachers/ |
Add one or more teachers. Accepts a JSON array. |
PATCH |
/teachers/ |
Partially update multiple teachers. Accepts a JSON array of objects with id. |
DELETE |
/teachers/ |
Delete multiple teachers. Accepts a JSON array of IDs. |
GET |
/teachers/{id} |
Get a single teacher by ID. |
PUT |
/teachers/{id} |
Replace a teacher record entirely. |
PATCH |
/teachers/{id} |
Partially update a single teacher. |
DELETE |
/teachers/{id} |
Delete a single teacher. |
Filter by field value:
GET /teachers/?first_name=John&subject=Math
Sort by one or more fields:
GET /teachers/?sortby=last_name:asc&sortby=subject:desc
Valid sort fields: first_name, last_name, email, class, subject
Valid sort orders: asc, desc
Teacher object:
{
"id": 1,
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@school.com",
"class": "10A",
"subject": "Mathematics"
}POST /teachers/ — add multiple teachers:
curl -k -X POST https://localhost:8443/teachers/ \
-H "Content-Type: application/json" \
-d '[{"first_name":"John","last_name":"Doe","email":"j.doe@school.com","class":"10A","subject":"Math"}]'GET /teachers/ — get all:
curl -k https://localhost:8443/teachers/PATCH /teachers/{id} — partial update:
curl -k -X PATCH https://localhost:8443/teachers/1 \
-H "Content-Type: application/json" \
-d '{"subject": "Physics"}'DELETE /teachers/ — bulk delete:
curl -k -X DELETE https://localhost:8443/teachers/ \
-H "Content-Type: application/json" \
-d '[1, 2, 3]'The middleware stack is composable via ApplyMiddlewares in pkg/utils. Each middleware wraps http.Handler — no third-party router required.
| Middleware | What it does |
|---|---|
Security_headers |
Injects OWASP-recommended response headers (CSP, HSTS, X-Frame-Options, etc.) |
Cors |
Validates Origin against a whitelist. Requests with no Origin header pass through. |
RateLimiter |
IP-based rate limiting with a configurable request limit and reset interval |
Compression |
gzip compression for clients that send Accept-Encoding: gzip |
Hpp |
HTTP Parameter Pollution protection — deduplicates repeated query/body params |
ResponseTimeMiddleware |
Captures response status codes for logging |
Currently only Security_headers is active in server.go. The others are implemented and tested but commented out while endpoints are being built.
- Students and executives are not implemented. The routes exist and return placeholder strings. Only teachers have actual database operations.
- No authentication. There is no token, session, or API key validation anywhere.
- No input validation beyond type checking. Fields like email are stored as plain strings with no format validation.
ResponseTimeMiddlewaredoes not log anything yet. It captures the status code but the logging side is unfinished.- Rate limiter uses
r.RemoteAddrfor IP detection. This breaks behind a proxy or load balancer — you would need to readX-Forwarded-Forinstead. - Requires TLS. There is no plain HTTP fallback. Running locally requires a self-signed certificate.
github.com/go-sql-driver/mysql— MySQL/MariaDB drivergithub.com/joho/godotenv—.envfile loading
MIT