DEV Community

Bilal Shemsu
Bilal Shemsu

Posted on

πŸš€ Building a Production-Ready REST API in Go (Without Any Framework)

 Most tutorials teach Go APIs using frameworks.

I wanted to understand what really happens under the hood.

So I built a fully working blog API using only Go’s standard library (net/http), SQLite, and a simple deployment pipeline.

No frameworks. No magic. Just clean fundamentals.


🧠 Why I Built This

As a developer coming from frameworks like Laravel, I kept asking:

  • What does a framework actually do for me?
  • Can I build a clean API without one?
  • How does Go handle HTTP and concurrency at a low level?

This project is my answer.


βš™οΈ Tech Stack

  • Go (net/http) β€” raw HTTP handling
  • SQLite (modernc.org/sqlite) β€” no external dependencies, pure Go
  • sqlx β€” cleaner database interactions
  • Nginx β€” reverse proxy
  • systemd β€” process management
  • GitHub Actions β€” CI/CD automation

πŸ“ Project Structure

.
β”œβ”€β”€ main.go
β”œβ”€β”€ database/
β”‚   └── db.go
β”œβ”€β”€ models/
β”‚   └── post.go
└── .github/
    └── workflows/
Enter fullscreen mode Exit fullscreen mode

Key Idea:

Separate HTTP logic from database logic β€” even without a framework.


🌐 API Endpoints

Method Endpoint Description
GET / Welcome message
GET /posts List posts
POST /posts Create post
GET /posts/{id} Get one
PUT /posts/{id} Update
DELETE /posts/{id} Delete

πŸ”₯ What Makes This Interesting?

1. No Router Library

Routing is handled manually:

  • One handler per path
  • switch r.Method handles multiple HTTP verbs
  • URL params are extracted manually

This shows you what frameworks like Gin or Echo abstract away.


2. Manual JSON Handling

json.NewDecoder(r.Body).Decode(&post)
json.NewEncoder(w).Encode(post)
Enter fullscreen mode Exit fullscreen mode

You control everything:

  • Input validation
  • Response format
  • Error handling

3. Clean Separation of Concerns

Even without a framework:

Handler β†’ Model β†’ Database
Enter fullscreen mode Exit fullscreen mode
  • Handlers = HTTP logic
  • Models = SQL queries
  • Database = storage

4. SQLite Without CGO 🀯

Using:

modernc.org/sqlite
Enter fullscreen mode Exit fullscreen mode

Means:

  • No C dependencies
  • Easier deployment
  • Works perfectly in CI/CD

5. Production-Style Deployment

This is where most tutorials stop β€” but this project goes further.

πŸ” Deployment Flow

git push origin main
       ↓
GitHub Actions
       ↓
SSH into VPS
       ↓
git pull + build
       ↓
systemctl restart
       ↓
Live πŸš€
Enter fullscreen mode Exit fullscreen mode

⚑ What I Learned

🧩 1. Frameworks Hide Complexity

Things Laravel does automatically:

  • Routing
  • Request parsing
  • Validation
  • ORM abstraction

In Go, you do it yourself β€” and that’s how you really learn.


🧠 2. net/http Is More Powerful Than Expected

With just:

http.HandleFunc()
http.ListenAndServe()
Enter fullscreen mode Exit fullscreen mode

You can build a complete API.


⚠️ 3. You Must Be Careful

No framework means:

  • You handle errors manually
  • You manage structure yourself
  • You enforce best practices

πŸš€ 4. DevOps Matters More Than Code

The biggest upgrade in this project wasn’t CRUD.

It was:

  • systemd auto-restart
  • Nginx reverse proxy
  • CI/CD pipeline

That’s what makes it real-world ready.


πŸ“Œ If I Improve This Further

Next steps I would take:

  • Add middleware (logging, auth)
  • Use a router (like chi or gin)
  • Add validation layer
  • Introduce environment configs
  • Add Docker support

πŸ’‘ Final Thoughts

If you're learning Go:

πŸ‘‰ Don’t start with frameworks
πŸ‘‰ Start with net/http

Because once you understand this level…

You can use any framework with confidence.


πŸ‘¨β€πŸ’» Source Code

(You can link your GitHub repo here)


πŸ™Œ Let’s Connect

If you're also learning Go or building APIs, I’d love to hear how you're approaching it.


⭐ If this helped you, consider sharing it!

Top comments (0)