← Back to articles
Technology

Change APIs in 3 Safe Steps

Change APIs in 3 Safe Steps

"I only renamed a column." "I only added one required field." Small changes like these can break old app screens and queued jobs. This article is about the design phase: how to plan data and API changes in three steps instead of one.

Why a single-step change breaks things

At the moment of the change, old and new coexist:

  • Mobile app versions that haven't been updated from the store yet
  • Jobs enqueued by the old code that haven't run yet
  • Cached data in browsers and CDNs that still has the old shape

A deploy does not make them disappear. The design has to assume a period where both shapes exist.

Three steps: expand, migrate, contract

1. Expand

Only add the new shape; keep the old one. To rename name to display_name, first add display_name. Write to both, and read the new one first, falling back to the old one.

2. Migrate

Backfill existing data into the new shape. Work in small batches that can resume after a failure. When done, compare counts and missing values before and after.

3. Contract

Remove the old column or field only after you've confirmed nothing still uses it. This is the riskiest step, so decide the criteria in advance.

What to check at each step

  • Expand: do old clients still work if they ignore the new field?
  • Migrate: do counts match after migration, and is re-running safe (no double writes)?
  • Contract: has old-client traffic dropped enough, and is the dual read/write period defined?

Example criteria: "requests from old versions are under 1% of traffic for the last two weeks" and "dual support lasts at least one release cycle." Pick numbers that fit your service. Deciding them up front is what matters.

Example: adding a required field to an API

Suppose you add a required severity field to a report API.

// Bad: make it required right away
// Old apps don't send severity, so every request gets a 422

// Good: three steps
// 1. expand  : severity is optional; store "normal" when missing
// 2. migrate : backfill existing rows with "normal"
// 3. contract: make it required once old-version traffic is low

A failure example: after renaming a column directly, jobs queued before the deploy kept reading the old name and failed silently. Job queues are a classic place where old and new mix around a deploy.

Design-time checklist

  • Is the change finished in a single deploy?
  • Is the period where old and new coexist written down in days?
  • Have you listed old clients, queued jobs, and caches?
  • Is the removal decision based on numbers?

Putting it into practice with Bugoon

Compatibility problems show up right after a change as reports like "that screen is broken." With the Bugoon widget embedded in your site, each report automatically includes a screenshot, the steps taken, and environment details such as browser and screen size. Reports from the iOS and Android apps work the same way. When a user on an old version reports a problem, you can confirm the environment without back-and-forth. Reports connect to GitHub Issues, and you can track pre-contract checks on the kanban board.

Streamline bug reporting for your team.

Bugoon is free to get started. Add one line of code to your site and transform how your team handles bugs.

Get Started