An adapter translates between an external technology and an application's ports. In hexagonal architecture, the application keeps business logic technology-agnostic; ports define contracts, and adapters provide concrete ways to use them. This boundary lets a service expose the same capabilities through different interfaces or connect to external systems without putting their details in the core. section 4.1.4 section 4.1
The direction of the request determines the adapter's job:
- A driving adapter turns an incoming, technology-specific request into an application call. A gRPC adapter can expose operations such as CreateProduct or GetProduct through an API port. section 4.1.4 section 4.2.1
- A driven adapter turns an application's technology-agnostic request into an operation on an external system. Database and payment adapters are examples. section 4.1.4 section 5.2.2
Persisting an order
An Order application accepts a DBPort dependency and calls its Save method when placing an order. A database adapter implements that contract using GORM and MySQL: it converts domain orders to database entities for saving and converts retrieved entities back to domain orders. Connection and migration errors are returned during adapter initialization, before the application starts serving requests. section 4.2.3 section 4.2.5
An adapter must satisfy its port's interface to be plugged in. For payment, the Order service can use a payment port with multiple possible adapter implementations; dependency injection selects the concrete implementation during initialization. Keep the contract in the port and the technology-specific work in the adapter. section 5.2.2 section 4.2.1
package main
import (
"github.com/huseyinbabal/microservices/order/config"
"github.com/huseyinbabal/microservices/order/internal/adapters/db"
"github.com/huseyinbabal/microservices/order/internal/adapters/grpc"
"github.com/huseyinbabal/microservices/order/internal/application/core/
api"
"log"
)
func main() {
dbAdapter, err := db.NewAdapter(config.GetDataSourceURL())
if err != nil {
log.Fatalf("Failed to connect to database. Error: %v", err)
}
application := api.NewApplication(dbAdapter)
grpcAdapter := grpc.NewAdapter(application, config.GetApplicationPort())
grpcAdapter.Run()
}
The application entry point creates the DB adapter, injects it into the core, then gives that core to a gRPC adapter and starts the server. This makes the wiring—and the database connection failure path—visible in one place. section 4.2.7








