DEV Community

Cover image for Structuring a Go API Like Laravel (Controller, Service, Repository)
Ahmed Raza Idrisi
Ahmed Raza Idrisi

Posted on

Structuring a Go API Like Laravel (Controller, Service, Repository)

If you're coming from Laravel, one thing feels missing in Go:

πŸ‘‰ Structure

By default, Go gives you freedomβ€”but no clear architecture.

So in this post, we’ll structure a Go API like Laravel:

  • Controller β†’ Handle request
  • Service β†’ Business logic
  • Repository β†’ Database

🧠 Why Structure Matters

Without structure:

  • Code becomes messy quickly
  • Hard to scale
  • Difficult to debug

With structure:

  • Clean separation of concerns
  • Easier testing
  • Production-ready codebase

πŸ“ Folder Structure

project/
 β”œβ”€β”€ main.go
 β”œβ”€β”€ controller/
 β”œβ”€β”€ service/
 β”œβ”€β”€ repository/
 β”œβ”€β”€ model/
Enter fullscreen mode Exit fullscreen mode

🧱 Model (model/user.go)

```go id="6pn1u5"
package model

type User struct {
ID int json:"id"
Name string json:"name"
}




---

## πŸ—„οΈ Repository Layer

Handles database queries



```go id="aq1u8u"
package repository

import (
    "database/sql"
    "yourapp/model"
)

type UserRepository struct {
    DB *sql.DB
}

func (r *UserRepository) GetAll() ([]model.User, error) {
    rows, err := r.DB.Query("SELECT id, name FROM users")
    if err != nil {
        return nil, err
    }
    defer rows.Close()

    var users []model.User

    for rows.Next() {
        var user model.User
        rows.Scan(&user.ID, &user.Name)
        users = append(users, user)
    }

    return users, nil
}
Enter fullscreen mode Exit fullscreen mode

βš™οΈ Service Layer

Handles business logic

```go id="qf1kmz"
package service

import (
"yourapp/model"
"yourapp/repository"
)

type UserService struct {
Repo *repository.UserRepository
}

func (s *UserService) GetUsers() ([]model.User, error) {
return s.Repo.GetAll()
}




---

## 🌐 Controller Layer

Handles HTTP requests



```go id="n8t1rn"
package controller

import (
    "encoding/json"
    "net/http"
    "yourapp/service"
)

type UserController struct {
    Service *service.UserService
}

func (c *UserController) GetUsers(w http.ResponseWriter, r *http.Request) {
    users, err := c.Service.GetUsers()
    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }

    json.NewEncoder(w).Encode(users)
}
Enter fullscreen mode Exit fullscreen mode

πŸš€ main.go (Wire Everything)

```go id="b4r8f2"
package main

import (
"database/sql"
"log"
"net/http"

_ "github.com/lib/pq"

"yourapp/controller"
"yourapp/repository"
"yourapp/service"
Enter fullscreen mode Exit fullscreen mode

)

func main() {
db, _ := sql.Open("postgres", "your_connection_string")

repo := &repository.UserRepository{DB: db}
service := &service.UserService{Repo: repo}
controller := &controller.UserController{Service: service}

http.HandleFunc("/users", controller.GetUsers)

log.Println("Server running on :8080")
http.ListenAndServe(":8080", nil)
Enter fullscreen mode Exit fullscreen mode

}




---

## πŸ”₯ What You Achieved

* Clean architecture like Laravel
* Separation of concerns
* Scalable Go backend structure

---

## 🧭 When to Use This

Use this structure when:

* Building real APIs
* Working in teams
* Scaling projects

---

## πŸ’¬ Final Thought

Go doesn’t force structure…

πŸ‘‰ But professionals create one.

If you combine Go performance with Laravel-style architecture, you get the best of both worlds.

---

## πŸš€ Coming Next

πŸ‘‰ Add middleware (logging, auth)
πŸ‘‰ Add validation layer
πŸ‘‰ Dockerize Go + PostgreSQL

---

#golang #backend #architecture #programming #webdev
Enter fullscreen mode Exit fullscreen mode

Top comments (0)