Agent Graph Engineering, Part 3: Why Your WebSocket Clients Need Generated Types
Three services in two languages means three seams, and a hand-maintained seam is a slow leak.
Three services in two programming languages create three potential boundaries, which is where systems often fail silently. By declaring the data structures once on the server side and generating the remaining code, developers can eliminate the need for manual maintenance of these boundaries. OpenAPI shapes REST clients, AsyncAPI shapes WebSocket clients in TypeScript and Python. This ensures that any discrepancies between the frontend and backend are caught by the compiler, rather than by a user.
The same declarations also create a formal approval form, so reviewers cannot approve calls with fields they were never shown. Splitting the agent from the business introduces a boundary where codebases can drift apart. This post explains how to prevent this drift by declaring shapes on the server and generating everything else.
In a WebSocket message exchange between a browser and backend, the backend sends {ticket_id, content}, while the frontend reads {ticketId, body}. The resulting empty space in the UI where a message should appear is due to a field being undefined in JavaScript. The REST world solved this problem a decade ago by using a single schema and generating clients from it. However, WebSocket message shapes are still often hand-written, with a code review being the only thing keeping them consistent.
Typing and generation are design stances that should be adopted before a second codebase exists. Once two processes need to agree, they become mandatory. The demo application contains three services and two programming languages, resulting in three places where shapes can cross boundaries. By generating on the server and using generated code everywhere else, developers can avoid having to write the same shape twice.
The generated Python code for a ticket feed shows how the structure of the system can be declared once and then generated for other codebases. The type system preserves which fields cross boundaries, ensuring that adding or removing a field results in a compile error in the corresponding frontend branch. This eliminates the need to write the same shape twice and prevents silent discrepancies between codebases.
Written by urgent.news from HackerNoon's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.