Inter-Service Communication
Call other services by logical name with ctx.CallService, with automatic resolution, trace propagation and async fire-and-forget support.
Ginboot provides a high-level, protocol-agnostic service-to-service communication layer. Developers can invoke other microservices or serverless functions using logical service identifiers directly on ginboot.Context without handling transport details, JSON serialization, or header propagation manually.
1. Developer API
ginboot.Context provides two primary invocation modes:
Synchronous Request-Reply (ctx.CallService)
Performs a blocking request to the target service and automatically unmarshals the response payload into a target struct.
func (c *OrderController) GetOrderDetails(ctx *ginboot.Context) (*OrderDetailsDTO, error) {
userID := ctx.Param("userId")
// Synchronous call to user-service
var user UserResponseDTO
err := ctx.CallService("user-service", "/api/v1/users/"+userID, nil, &user)
if err != nil {
return nil, ginboot.NewApiError(404, "User details could not be retrieved")
}
return &OrderDetailsDTO{
OrderID: "ord-99",
User: user,
}, nil
}Non-blocking Fire-and-Forget Async (ctx.CallServiceAsync)
Executes a non-blocking asynchronous call in the background without waiting for a response or blocking the caller HTTP context.
func (c *OrderController) CreateOrder(ctx *ginboot.Context, req CreateOrderRequest) (*OrderResponseDTO, error) {
order, err := c.orderService.CreateOrder(req)
if err != nil {
return nil, err
}
// Fire-and-forget async notification (non-blocking)
_ = ctx.CallServiceAsync("notification-service", "/api/v1/notifications/send", map[string]interface{}{
"type": "ORDER_CREATED",
"order_id": order.ID,
"user_id": order.UserID,
})
return order, nil
}2. HTTP Method Overrides
The default verb is POST
CallService and CallServiceAsync issue a POST unless you say otherwise. Read-only calls
should use the WithMethod variants below, or you'll POST to a GET endpoint and get a 405.
You can specify a custom HTTP method (GET, PUT, DELETE, PATCH) using:
// Synchronous GET
err := ctx.CallServiceWithMethod("GET", "user-service", "/api/v1/users/"+id, nil, &user)
// Asynchronous DELETE
err := ctx.CallServiceAsyncWithMethod("DELETE", "cache-service", "/api/v1/cache/purge", nil)3. Dynamic Service Name Resolution (ServiceResolver)
Target endpoints are resolved automatically at runtime using ServiceResolver:
ginboot.ymlMapping: Reads endpoint URLs configured underginboot.services.<service-name>.url— see Configuration for the full file layout.- Ginboot Cloud UI & Environment Variables: Automatically checks environment variable
SERVICE_<NAME>_URL(e.g.SERVICE_USER_SERVICE_URL=https://user-service.cloud.internal). - Local Fallback: Defaults to
http://<service-name>:8080for local Docker/K8s development.
4. Context & Header Propagation
ServiceClient automatically propagates essential request context headers across downstream HTTP requests:
- OpenTelemetry Tracing: Formats and injects W3C trace context headers (
traceparent,tracestate) to preserve distributed tracing spans across service boundaries. - Request Identification: Propagates
X-Request-ID. - Authentication Context: Forwards user credentials and authorization claims (
Authorization,X-User-ID,X-User-Roles).