Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Hexagonal Architecture in Go

A minimal Go service that demonstrates Hexagonal Architecture (also known as Ports and Adapters). The application exposes a simple REST API to create and retrieve "items" and keeps the core logic independent of HTTP and storage details.

What is Hexagonal Architecture?

Hexagonal architecture puts business logic at the centre and defines ports (interfaces) for all input and output. Adapters implement those interfaces, so you can change how users call the app (HTTP, gRPC, CLI) or where data lives (memory, PostgreSQL, APIs) without touching the core.

  • Domain – Entities and rules; no dependencies on frameworks or I/O.
  • Ports – Interfaces: inbound (how the app is driven) and outbound (what the app needs from the outside).
  • Application – Use cases that orchestrate the domain and use outbound ports.
  • Adapters – Implementations of ports: inbound adapters call the application; outbound adapters (e.g. repositories) are called by the application.

Dependencies point inward: adapters depend on ports, the application depends on ports and domain, and the domain depends on nothing.

                    ┌─────────────────────────────────────────┐
                    │              Inbound Adapters            │
                    │  (HTTP, gRPC, CLI, … drive the app)      │
                    └────────────────────┬────────────────────┘
                                         │
                                         ▼
┌──────────────┐    ┌─────────────────────────────────────────┐    ┌──────────────┐
│   Outbound   │    │  Inbound Ports    │   Application       │    │   Outbound   │
│   Adapters   │◄───│  (interfaces)     │   (use cases)       │───►│   Ports      │
│ (DB, APIs…)  │    │                   │   + Domain          │    │ (interfaces) │
└──────────────┘    └─────────────────────────────────────────┘    └──────────────┘
                                         ▲
                                         │
                    ┌────────────────────┴────────────────────┐
                    │  Dependency injection (e.g. in main)    │
                    └─────────────────────────────────────────┘

Directory Layout

hexagonal/
├── cmd/
│   └── service/
│       └── main.go              # Wiring: builds adapters and app, injects ports
├── internal/
│   ├── domain/                  # Core entities and logic (no I/O)
│   │   └── item.go
│   ├── ports/                   # Inbound and outbound interfaces
│   │   ├── inbound.go           # ItemService – how use cases are invoked
│   │   └── outbound.go          # ItemRepository – what the app needs from storage
│   ├── application/            # Use case implementations (depend only on ports + domain)
│   │   └── item_service.go
│   └── adapter/
│       ├── inbound/             # Driving adapters (call into the app)
│       │   └── http/            # REST handler and router
│       └── outbound/            # Driven adapters (implement outbound ports)
│           └── persistence/
│               └── memory.go    # In-memory ItemRepository
├── go.mod
└── README.md

Layer roles

Layer Role
domain Item entity. Pure business data; no references to HTTP, DB, or frameworks.
ports ItemService (inbound): “create item”, “get by ID”. ItemRepository (outbound): “save”, “find by ID”.
application ItemService implementation: create with ID, persist via ItemRepository; get by ID via repository. Depends only on port interfaces and domain.
adapter/inbound/http HTTP handler: parse request → call ItemService → write response. Depends on inbound port.
adapter/outbound/persistence In-memory map implementing ItemRepository. Can be replaced by a PostgreSQL adapter without changing app or domain.
cmd/service Constructs repository and application, injects them, then starts the HTTP server with the handler.

Run the service

go run ./cmd/service

Example requests

Create an item:

curl -X POST http://localhost:8080/items -H "Content-Type: application/json" -d '{"name":"My Item"}'

Get by ID (use the id from the create response):

curl http://localhost:8080/items/<id>

Extending this implementation

  • New inbound side: Add another adapter (e.g. internal/adapter/inbound/grpc) that implements the same ports.ItemService calls. No changes to domain or application.
  • New outbound side: Implement ports.ItemRepository with a real DB (e.g. internal/adapter/outbound/persistence/postgres.go) and swap it in main.go; application and domain stay unchanged.
  • New use cases: Add methods to the inbound port and implement them in the application layer; then expose them in HTTP (or other) adapters.

This keeps the core testable with mocks (fake repositories, fake services) and keeps technology choices at the edges.

About

A simple hexagonal architecture implementation

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages