Skip to content

Blog Article

Mismatch Detection: Catching Frontend-Backend Drift Automatically

AppHandoff's scanner compares frontend API calls against backend specs on every push. Here's how it works under the hood.

EngineeringFeature

Frontend-backend drift is the most common source of integration bugs. Not logic errors. Not performance issues. Simple disagreements: the frontend calls an endpoint that doesn't exist, expects a field that's not there, or sends a parameter the backend doesn't recognize. We built a scanner that catches these automatically — here's exactly how it works.

What Is a Mismatch?

A mismatch is any place where the frontend's expectations don't match the backend's reality. It's the gap between 'what the frontend code says it needs' and 'what the backend code actually provides.' Each mismatch is a potential integration bug — something that works in isolation on each side but breaks when the two sides talk to each other.

We categorize mismatches into five types, each with a different severity level and fix pattern. In our data across hundreds of projects, the distribution is remarkably consistent.

# Mismatch categories and frequency:

Missing Endpoint (34%):
  FE calls GET /api/teams/:id/members
  BE has no route matching that path
  Severity: Critical — page will show an error or blank

Shape Mismatch (28%):
  FE expects: { user: { name: string, avatar: string } }
  BE returns: { name: string, avatar_url: string | null }
  Severity: High — data renders incorrectly or crashes

Auth Gap (18%):
  FE calls endpoint without auth header
  BE requires Authorization: Bearer <token>
  Severity: High — 401 errors in production

Pagination Drift (12%):
  FE expects: Project[]
  BE returns: { data: Project[], meta: { page, total } }
  Severity: Medium — first page works, pagination breaks

Enum Disagreement (8%):
  FE uses: 'active' | 'inactive'
  BE uses: 'ACTIVE' | 'INACTIVE'
  Severity: Low — conditional logic silently fails

How the Scanner Works

The scanner runs in two phases. Phase 1 extracts contracts from both codebases. Phase 2 compares the contracts and flags mismatches. Both phases are triggered automatically on every push to either repo, but you can also trigger a manual scan from the dashboard or via the MCP server (/mcp-server).

Phase 1 — Contract Extraction — reads the frontend repo and finds every API call: fetch(), axios, custom API clients, React Query hooks. For each call, it records the HTTP method, URL path, request body shape, expected response shape, and any auth headers. On the backend side, it reads the OpenAPI spec (if present) or scans route handler files directly, recording the same information from the server's perspective.

Contract Extraction in Detail

The frontend scanner uses AST parsing — not regex. It builds an abstract syntax tree of each file and walks it to find API call sites. This handles all the ways developers call APIs: direct fetch, axios wrappers, custom hooks, React Query queries, SWR hooks. The scanner resolves variable references, follows imports, and reconstructs the full URL path even when it's built from template literals and constants.

// Frontend code the scanner analyzes:
const { data } = useQuery({
  queryKey: ['project', projectId],
  queryFn: () => api.get(`/projects/${projectId}`)
});

// Scanner extracts:
// {
//   method: 'GET',
//   path: '/projects/{id}',
//   responseShape: inferred from 'data' usage downstream,
//   auth: inferred from api client configuration
// }

// Backend OpenAPI spec the scanner reads:
// paths:
//   /projects/{id}:
//     get:
//       parameters: [{ name: id, in: path, required: true }]
//       responses:
//         200:
//           content:
//             application/json:
//               schema: { $ref: '#/components/schemas/Project' }

// Phase 2 comparison:
// FE expects response with 'members' array
// BE Project schema has no 'members' property
// → MISMATCH: Shape mismatch on GET /projects/{id}

The backend scanner supports OpenAPI 3.x specs (JSON or YAML), Next.js API routes, Express route handlers, and Fastify routes. If your framework isn't supported yet, the OpenAPI spec path covers most cases — and we're adding framework support continuously.

What a Mismatch Ticket Looks Like

When the scanner finds a mismatch, it creates a ticket on the shared Kanban board (/shared-kanban-humans-bots) with all the context needed to fix it. No vague descriptions. No 'something seems wrong with the API.' Every ticket has concrete details:

# Mismatch ticket example:

Title:    Shape mismatch on GET /api/projects/:id
Severity: HIGH
Type:     shape_mismatch

Frontend expectation:
  File: src/hooks/useProject.ts:24
  Expects: { id: string, name: string, members: Member[] }

Backend reality:
  File: app/api/projects/[id]/route.ts:18
  Returns: { id: string, name: string, created_at: string }

Missing in backend response:
  - members: Member[] (array of team members)

Extra in backend response:
  - created_at: string (not consumed by frontend)

Suggested fix:
  Option A: Add 'members' join to backend query
  Option B: Remove 'members' expectation from frontend

AI Plan: Add members relation to Project query,
         include in API response with Member[] shape.
         Estimated: 1 route file + 1 test file changed.

The ticket includes file paths and line numbers on both sides, so whoever picks it up — human or bot — can go directly to the relevant code. No treasure hunt. No reading Slack threads to figure out what changed.

Continuous Detection vs. One-Time Audits

Some teams run integration audits before big releases. That catches mismatches, but only at the end of the cycle when fixes are expensive and time-pressured. AppHandoff's scanner runs on every push — so a mismatch introduced at 10am on Tuesday is detected at 10:01am on Tuesday, not three weeks later during release prep.

We tracked the average cost of fixing a mismatch based on when it was detected. Mismatches caught by the scanner within an hour of introduction: average fix time 15 minutes. Mismatches caught during manual staging tests: average fix time 2 hours. Mismatches caught in production: average fix time 4 hours. The fix is the same — the debugging time is what changes.

Real Examples from Production

Here are three real mismatches we caught in our own codebase that would have been production bugs without the scanner.

First: a Lovable iteration added a 'team members' section to the project detail page. The frontend started calling GET /api/projects/:id/members — an endpoint that didn't exist. The scanner flagged it as a missing endpoint within 30 seconds of the push. A bot scaffolded the endpoint, we reviewed and merged the PR, and the feature worked end-to-end.

Second: a backend migration renamed user.avatar to user.avatar_url. The frontend still read user.avatar. The scanner caught the shape mismatch. Fix: one line in the frontend component. Without the scanner, this would have shown as broken avatars in production.

Third: we added rate limiting middleware that required an API key header on certain endpoints. The frontend didn't send the header. Scanner caught 4 auth gap mismatches. We updated the API client to include the header. Four potential 401 errors prevented.

Getting Started with Mismatch Detection

Connect your repos to AppHandoff and run the first scan. That's it. No configuration, no annotations, no contract files to maintain. The scanner extracts contracts from your existing code. The MCP for Lovable page (/mcp-for-lovable) has the step-by-step setup, and the pricing page (/pricing) covers scan volume limits per plan.

Every team that connects a Lovable frontend to a production backend for the first time finds mismatches. That's not a failure — it's the scanner doing its job. The mismatches were always there. Now they're visible, tracked, and fixable before they hit users.