Requirements & API: Interface Definition Languages (IDL)
In the previous chapter, we examined the OpenAPI specification (OAS) as a tool for designing a RESTful API request for a Web application. In this chapter, we will explore several languages that help formalize the API definition and automate development.
IDL stands for Interface Definition Language. It is a formal specification language used to define the structure and behavior of software interfaces.
During my workshop, I like to tell the audience that "IDL is DSL" (Domain-specific language, by the way), confusing them with the abbreviations. Then I mention "used for the interface definition."
As it is very typical with DSLs, plenty exists for various purposes. And the very question is which one will get public recognition and strive for global adoption. Only very few (if not the one) get the prize.
Let's get started with the undisputed leader...
OpenAPI
We continue using the "Retrieve Customer details" example from the Legacy CRM API, but some fixes are required to make it a proper schema.
The significant change is that now we distinguish Models (Customer, Address) from an API operation (GET /customer/{customerId}
), allowing reusing such models across other operations without duplication.
That also contributes to readability, even though the number of lines hasn't increased much, and my trick with examples
is not helping. OpenAPI can be expressed with JSON, so you can imagine how huge a schema can become with opening and closing square brackets.
Extensiveness is the critical point of OAS for historical reasons: it must cover as many possible use cases as possible while maintaining backward compatibility with tooling. The specification's main advantage is the tool ecosystem, which makes it unreachable for opponents.
As a side effect, first-hand API design in a code editor becomes challenging. The infamous "PetStore" is too simple compared to real enterprise APIs with extended and complex models with hundreds (if not more) operations.
I saw people trying to provide manually-written OpenAPI specs as requirements for API attached to a Jira ticket. Those might be fun to write but not to maintain thousands-lines YAML files.
That can be mitigated with low- or no-code tools (here is my article on the topic from 2022). However, this approach has many side effects, including vendor lock and inflexibility.
Now, let's turn to some competitors.
TypeSpec
It is the most prominent OpenAPI's rival with a super-powerful backer: Microsoft. They are attempting to challenge a position in API design-first language, and they do an excellent job.
TypeSpec does not just sound like TypeScript. It has a TypeScript-like syntax with strong typification (or type safety, as they call it). It is less verbose, more precise, and modular.
That similarity with TypeScript is a very good move, giving front-end developers the ability to define API in a manner closer to them. For full-stacks, that is also about streamlining the development process.
Let's convert our example to TypeSpec:
If you are familiar with OpenAPI, here is the guide on how OAS components map to the TypeSpec's ones.
Also, you can use the playground to convert my TypeSpec schema to OpenAPI and see how things are mapped. The result of OpenAPI will differ from the original one.
What I found interesting:
- You need to
import
TypeSpec libraries and apply theusing
statement that creates a shorthand for referencing a namespace from an imported module. For me, that is unusual and was confusing at first. - All properties are required by default if not stated otherwise via
?
. - Putting descriptions as comments above properties improves readability a lot.
- A mass of decorators (starting with
@
) complicates things visually. - You define models and operations in the order you need, so there is no strict structure.
- Even though a model definition is straightforward, the operation's response body was tricky for me. I found different ways of handling response status codes, and I am unsure which one I used is the best solution.
- You don't need to define HTTP errors manually; just mentioning a status code would imply using a default error message.
- You can omit using an HTTP method (verb): if you name an operation as
read
, it will be considered asGET
by default. I used the@get
decorator just because it was unnatural for me (an OpenAPI person) to skip the method. - I haven't found a way to provide an example for
createdDate
.
My transition from OpenAPI to TypeSpec was not smooth. It took me time to get through the documentation and examples (I don't trust ChatGPT; none of the chat-generated examples worked). However, I am amazed by the versatility of TypeSpec, and it is a broader application than its "parent."
TypeSpec is both-way compatible with OpenAPI. That means the people behind TypeSpec are not planning to fight with OpenAPI dominance in a plain field. Instead, leverage its infrastructure and target some use cases, formats, and protocols OpenAPI can't cover.
By the way, Amazon has a similar solution called Smithy. But I haven't heard much about it outside the AWS world.
JSight
There are a bunch of less prominent OpenAPI rivals. JSight is my favorite one of all.
Let's translate our OpenAPI example to JSight:
What I found interesting:
- Inline descriptions of model attributes.
- All items are required by default.
- Excellent readability with fewer lines of code
- It is not possible to define an attribute without an example.
- You need to put a comma with metadata before a comment.
- There is a "macro" feature (not used in my example) allowing the reuse of different pieces of code (here is how it works).
- If you don't need to define huge models that are not reusable, you insert a JSON (even nested one) into a request and response body. See an example from my online workshop. It is advantageous.
JSight can also be converted to OpenAPI, but not vice versa. You can copy-paste my example to their playground to see how they map on each other.
Final Thoughts
There are as many IDLs as other DSLs, probably the same number as the stars in the night sky.
If you are dealing with API design, you are obliged to be somehow proficient in OpenAPI specification, but you are not obliged to use it. With the wide variety of tools, whether another IDL or node-code solution, you don't need to write hundreds of lines of code in YAML and JSON.
I used a JSight-like syntax to design API contracts on an actual project. It was clear and straightforward, even to people unfamiliar with API specifics.
In the next and last chapter of the series, we will look into more specialized DSLs to describe a flow that considers calling several API endpoints.