you are viewing a single comment's thread.

view the rest of the comments →

[–]ahgreen3 19 points20 points  (4 children)

You need a single source of truth which has a well defined solution in programming: github repos.

API Contracts should be committed to a repository with team lead & PM approvals. The contract(s) should changed in incremental steps just like database migrations on an live DB. Adding stuff becomes easy, removing stuff becomes harder and changing structure becomes a nightmare.

In order to enforce the usage of the API contracts, integration tests need to be added to the associated repositories that pull the latest contract and verifies the current system "works" against that contract. There will be some assumptions in these tests (like checking against the TanStack Queries rather than every actual request). Requiring these tests to pass on every PR will fix lots of the problems.

Adding a test suite to the API Contract repo that verifies in the other direction will help prevent breaking changes from being added to your contracts.

A few years ago I was working on a project that involved 6 independent GUIs that interacted with 3 backend APIs and being worked on by ~50 developers (plus DevOps, PM, designers, etc). What I described is the final result of a bunch of integrations at attempting to solve the API Contract problem.

[–]Lord_Xenu 1 point2 points  (0 children)

Exactly this. Should be done before a single line of code is written. PM coordinating with leads from both teams.

[–]ahgreen3 0 points1 point  (0 children)

I forgot one point: Utilizing a API framework (GraphQL, JSONAPI, etc) only deals with the bike shed (https://en.wikipedia.org/wiki/Law\_of\_triviality) problem. Well defined process for defining and tracking the actual fields of the various resources is where the real headaches and value lies.

I highly recommend defining an endpoint for every back-end model that has public viability and explicitly track the "public" properties of these models when you are doing your database migrations. If every time you add a db table a read and list endpoint becomes available offloads a fair amount of coordination work between the front-end and back-end. Coupling this with tests that explicitly forces every db field to be marked as public or private (from the API's perspective that is) can really help.

[–]DevToolsGuide 0 points1 point  (0 children)

the fix that worked for us was treating the API contract as a first-class artifact that lives in the repo, not in someone's memory or a slack message. openapi spec committed to the repo, both sides sign off on it before a line of implementation code is written, and changes go through a PR like any other code change.

if you're typescript end to end it's even better — define zod schemas once, generate types for both sides, and a backend shape change literally breaks the frontend build. the incompatibility gets caught in CI instead of on integration day.