Today I traced the full call flow of GetRoute — the function that sits at the core of trip previewing. Walking through each layer made the architecture concrete in a way that reading the files in isolation didn’t.

Request Flow

When a client wants to preview a trip, the request passes through three distinct layers before hitting the external routing API:

Client
  POST /trip/preview  {userID, pickup, destination}
  │
  ▼
api-gateway/http.go : handleTripPreview
  - validates userID is present
  - re-serializes body as JSON
  - POST http://trip-service:8083/preview  ──────────────────────┐
  - wraps response in contracts.APIResponse{Data: ...}           │
  - returns 201                                                   │
                                                                  ▼
                              trip-service/infrastructure/http/http.go : HandleTripPreview
                                - decodes previewTripRequest {userID, pickup, destination}
                                - calls s.Service.GetRoute(ctx, pickup, destination)
                                │
                                ▼
                              trip-service/service/service.go : GetRoute
                                - builds OSRM URL with lon/lat coords
                                - GET http://router.project-osrm.org/route/v1/driving/...
                                - unmarshals JSON into OsrmApiResponse
                                - returns routes {distance, duration, geometry{coordinates}}
                                │
                                ▼
                              back to HandleTripPreview
                                - writeJSON 200 with OsrmApiResponse

Layer Responsibilities

Each layer has a clear, single responsibility:

LayerFileResponsibility
Edgeapi-gateway/http.goInput validation, forwarding, unified response envelope
HTTP adaptertrip-service/infrastructure/http/http.goTranslate HTTP → domain call, serialize result
Servicetrip-service/service/service.goBusiness logic, calls external OSRM API
Domaintrip-service/domain/trip.goDefines the TripService interface
Typesshared/types/types.goShared data shapes (OsrmApiResponse, Coordinate)

What I Learned

  • The gateway and the service have different jobs. The API gateway handles the user-facing contract (validation, envelope), while the trip service handles the domain logic. Keeping these separate means either can change without breaking the other.
  • The HTTP adapter is just translation. HandleTripPreview doesn’t make decisions — it decodes a request, calls the service, and serializes the result. All actual logic lives in GetRoute.
  • External calls belong in the service layer. The OSRM API call lives in service.go, not in the HTTP handler. This keeps the infrastructure layer thin and makes the service testable with a mock HTTP client.