liveBook · Manning

gRPC adapter

As explained in gRPC Microservices in Go

A gRPC adapter is an application-layer component that translates between gRPC requests and responses and an application's domain or port interfaces.

A gRPC adapter exposes an application’s operations to gRPC clients without making the application core handle gRPC request types. In an Order service, it accepts generated request objects, converts their data into domain objects, calls the APIPort application interface, and converts the result into a generated response. section 4.2.6

func (a Adapter) Create(ctx context.Context, request *order.CreateOrderRequest) (*order.CreateOrderResponse, error) {  #1
    var orderItems []domain.OrderItem
    for _, orderItem := range request.OrderItems {                     #2
        orderItems = append(orderItems, domain.OrderItem{
            ProductCode: orderItem.ProductCode,
            UnitPrice:   orderItem.UnitPrice,
            Quantity:    orderItem.Quantity,
        })
    }
    newOrder := domain.NewOrder(request.UserId, orderItems)            #3
    result, err := a.api.PlaceOrder(newOrder)                          #4
    if err != nil {
        return nil, err
    }
    return &order.CreateOrderResponse{OrderId: result.ID}, nil 
}

The Create handler maps each requested item to a domain.OrderItem, constructs an order, calls PlaceOrder, and returns the resulting order ID. An application error is returned to the client rather than converted into a success response. section 4.2.6

The adapter holds an APIPort and a listening port, and embeds the generated UnimplementedOrderServer. To run it, open a TCP listener, create a gRPC server, register the generated Order service, and serve requests. Reflection is enabled in the development environment; grpcurl can test the endpoint using reflection or the relevant .proto files. section 4.2.6

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()
}

Wire dependencies at startup: create the database adapter, pass it to the application, then pass the application and configured port to the gRPC adapter before calling Run. section 4.2.7

Keep subsequent business steps behind the application interface. When placing an order also charges a customer, PlaceOrder saves the order and invokes a Payment service through a payment adapter; the gRPC Create handler still calls PlaceOrder. A payment failure can reach the client as an error. Distinguishing errors would let a client decide whether to retry or treat the operation as failed, but that distinction is not implemented here. section 5.2.6

How gRPC Microservices in Go covers it

How deep it goes
Works through handler mapping, server startup, and dependency injection, but stops short of implementing differentiated client-facing payment errors.
Examples
Uses a Go Order service Create handler, a gRPC server, and startup wiring with a MySQL-backed application.
What it assumes
Assumes Go application interfaces and generated protocol-buffer service types, while showing how to wire and run their adapters.
What you can do after
Build it from scratch by mapping a generated gRPC request to a domain order, calling APIPort, and registering the server.
How it connects
Connects protocol buffers and APIPort to domain objects, dependency injection, database persistence, and a payment adapter.

This explainer was generated by Manning's knowledge graph from the text of gRPC Microservices in Go. The section links point to the parts of the book it draws on.