Summary
The Matcher's Fetcher HTTP client (internal/discovery/adapters/fetcher/client.go + types.go) is 100% misaligned with the real Fetcher API. 5 of 6 routes return 404, required headers are never sent, and DTOs silently parse into empty/wrong values. E2E tests pass because the mock (tests/e2e/mock/fetcher_server.go) mirrors the Matcher's expectations, not the real Fetcher.
Route mismatches (all return 404 in prod)
| Matcher calls |
Fetcher actual |
GET /api/v1/connections |
GET /v1/management/connections |
GET /api/v1/connections/{id}/schema |
GET /v1/management/connections/:id/schema |
POST /api/v1/connections/{id}/test |
POST /v1/management/connections/:id/test |
POST /api/v1/extractions |
POST /v1/fetcher |
GET /api/v1/extractions/{jobId} |
GET /v1/fetcher/:id |
Only GET /health is correct.
Missing headers
X-Organization-Id (required on ALL protected routes) — never sent
X-Product-Name (required on CreateConnection, optional on List) — never sent
- The
?orgId= query param sent in ListConnections is ignored by the Fetcher
DTO mismatches
ListConnections
Fetcher returns {"items": [...], "page", "limit", "total"} (Pagination). Matcher expects {"connections": [...]}. Result: always empty list.
ConnectionResponse
Matcher reads databaseType → Fetcher sends type. Field always empty.
TestConnection
Fetcher returns {status (string), message, latencyMs}. Matcher expects {connectionId, healthy (bool), latencyMs, errorMessage}. The validateFetcherResourceID check always fails because connectionId is absent.
Schema
Fetcher returns id (not connectionId), tables use name (not tableName), columns are fields []string (not columns []{name,type,nullable}). ID validation always fails.
Extraction submit
Completely different contracts. Matcher sends {connectionId, tables}. Fetcher expects {dataRequest: {mappedFields: {datasource: {table: [fields]}}}}.
Extraction status
Fetcher returns id (not jobId). Status values differ: Fetcher uses processing/completed (lowercase), Matcher expects RUNNING/COMPLETE.
Health check
Fetcher returns plain text "healthy". Matcher tries JSON parse {"status": "healthy"} → always fails → IsHealthy() = false.
Mock vs Real Fetcher
The mock server (tests/e2e/mock/fetcher_server.go) uses the same wrong routes and wrong DTOs as the client. Tests are green but prod is 100% broken.
Files to fix
internal/discovery/adapters/fetcher/client.go — routes, headers, request building
internal/discovery/adapters/fetcher/types.go — all DTOs
internal/discovery/adapters/fetcher/config.go — health check plain text handling
tests/e2e/mock/fetcher_server.go — align with real Fetcher contract
Context
Found during Console ↔ Matcher ↔ Fetcher integration work by @augustoalvarenga.
Full field-by-field audit report available on request.
Summary
The Matcher's Fetcher HTTP client (
internal/discovery/adapters/fetcher/client.go+types.go) is 100% misaligned with the real Fetcher API. 5 of 6 routes return 404, required headers are never sent, and DTOs silently parse into empty/wrong values. E2E tests pass because the mock (tests/e2e/mock/fetcher_server.go) mirrors the Matcher's expectations, not the real Fetcher.Route mismatches (all return 404 in prod)
GET /api/v1/connectionsGET /v1/management/connectionsGET /api/v1/connections/{id}/schemaGET /v1/management/connections/:id/schemaPOST /api/v1/connections/{id}/testPOST /v1/management/connections/:id/testPOST /api/v1/extractionsPOST /v1/fetcherGET /api/v1/extractions/{jobId}GET /v1/fetcher/:idOnly
GET /healthis correct.Missing headers
X-Organization-Id(required on ALL protected routes) — never sentX-Product-Name(required on CreateConnection, optional on List) — never sent?orgId=query param sent in ListConnections is ignored by the FetcherDTO mismatches
ListConnections
Fetcher returns
{"items": [...], "page", "limit", "total"}(Pagination). Matcher expects{"connections": [...]}. Result: always empty list.ConnectionResponse
Matcher reads
databaseType→ Fetcher sendstype. Field always empty.TestConnection
Fetcher returns
{status (string), message, latencyMs}. Matcher expects{connectionId, healthy (bool), latencyMs, errorMessage}. ThevalidateFetcherResourceIDcheck always fails becauseconnectionIdis absent.Schema
Fetcher returns
id(notconnectionId), tables usename(nottableName), columns arefields []string(notcolumns []{name,type,nullable}). ID validation always fails.Extraction submit
Completely different contracts. Matcher sends
{connectionId, tables}. Fetcher expects{dataRequest: {mappedFields: {datasource: {table: [fields]}}}}.Extraction status
Fetcher returns
id(notjobId). Status values differ: Fetcher usesprocessing/completed(lowercase), Matcher expectsRUNNING/COMPLETE.Health check
Fetcher returns plain text
"healthy". Matcher tries JSON parse{"status": "healthy"}→ always fails →IsHealthy()= false.Mock vs Real Fetcher
The mock server (
tests/e2e/mock/fetcher_server.go) uses the same wrong routes and wrong DTOs as the client. Tests are green but prod is 100% broken.Files to fix
internal/discovery/adapters/fetcher/client.go— routes, headers, request buildinginternal/discovery/adapters/fetcher/types.go— all DTOsinternal/discovery/adapters/fetcher/config.go— health check plain text handlingtests/e2e/mock/fetcher_server.go— align with real Fetcher contractContext
Found during Console ↔ Matcher ↔ Fetcher integration work by @augustoalvarenga.
Full field-by-field audit report available on request.