Using Typescript Types Generated from OpenAPI Schemas

An important part of my previous project was manually writing OpenAPI schemas for the APIs we were developing. This task was often done as an afterthought. We didn’t carefully deliberate on model names and lacked a consistent naming strategy. Even worse, property names would sometimes be misspelled or even forgotten entirely. For the most part, these little inaccuracies seemed trivial to us.

Flash forward to my current project, where we are using the openapi-typescript package. We use this tool to generate TypeScript types from the OpenAPI schema of one of the APIs we use. You can imagine how uneasy I felt when I realized that the types we use throughout our application would depend on the quality of an OpenAPI schema.

Using the OpenAPI generated types hasn’t been an entirely negative experience. They bring a certain convenience factor. Having the type definitions available without having to manually copy them in has helped speed up development. In addition, it’s trivial to fetch an updated OpenAPI schema version and re-generate the types. From there, it is easy to identify and fix any areas impacted by a change to the API.

But, there have also definitely been a number of pain points I have felt when using these types generated from swagger definitions. Here are a few examples:

Unfortunate Model Names

Because the API we are using is written in Java, a lot of the models in the OpenAPI schema have names like RuleItemDetailConfigSummaryModelResponse. Clearly, I am being a little dramatic here, but the main takeaway is that model names included in this schema are often long and meaningless. In the context of a frontend for this API, such a complicated name makes it less clear what the entity actually represents. Names such as these should not leave the API layer. As a result, I often feel the urge to rename these kinds of model or field names.

Missing/Inaccurate Fields

Another recurring issue is misspelled property names or ones that are excluded from the schema definition. Minor inaccuracies in the OpenAPI schema means having to update the generated type definitions by doing things like:


type ActualThing = ApiThing & {missingField: string};
type RealItem = Omit<ApiThing, "inaccurateField"> & {inaccurateField: number};

Having to do this has frustrated me for a couple of reasons. First, it means we are inconsistent with when we use a generated API type vs. one that we have modified. Further, having to overwrite these types also defeats the purpose of using the generated types in the first place (that is, helping to ensure that the types used are up to date with what is documented).

Optional vs. Required Fields

Another issue occurs when fields are not marked as required on the OpenAPI schema or the generated types. All fields being technically optional means that there is no issue with the following:


type User = { id?: number; displayName?: string };
type Program = { id?: number; programName?: string };

const createUser = (user: User) => {
  UserService.createUser(user);
};

const program: Program = { id: 3, programName: 'my good program' };
createUser(program);

So, if using request body types generated using the openapi-typescript package as a function parameter, it is really easy to entirely provide the wrong arguments.


As you can see, most of these complaints can be attributed to the quality of the OpenAPI spec. If it is one you know to be highly accurate, or one you are able to update yourself, then these might all be non-issues for you.

Otherwise, you should consider ways to minimize these issues. Each of these issues is easily avoidable with disciplined usage of the generated types. Limiting which segments of your code are allowed to use these generated types could certainly help. It definitely provides more control over things like model/property names and required vs. optional fields.

Have you had a more positive experience when using TypeScript types generated from OpenAPI schemas? If so, I would be interested to know what different tools/strategies you used to achieve that.

Conversation

Join the conversation

Your email address will not be published. Required fields are marked *