It really depends on the language and framework you're using how convenient OpenAPI actually is to implement. In many cases there's a lot of additional manual effort involved if you can't auto generate a schema, or at least generate one that is good enough to then generate client libs from.
I've been disappointed with almost every OpenAPI spec I've come across for this reason. They're OK for documentation but can't auto generate clients due to errors.
There are three standard models of working with API schemas, in relation to the implementation:
* manual:
* schema is maintained manually, independent of the implementation
* usually an afterthought and used mainly for documentation
* implementation-first:
* schema is autogenerated from the code
* used as a reference, possibly to generate clients, and often to run tests
* probably the most common approach, supported by many frameworks
* schema-first:
* schema is maintained manually, with client and server code generated from it
* very rare, but the most correct approach
A common mistake I have noticed is that people identify API models with their business logic models. They may look similar, but they are very rarely identical, just as is the case with business logic models vs ORM models.
Unless your models are very simple, the best approach is to use three separate layers of model definitions:
* API models for serde and conversion of external requests
* business logic models that carry the actual internal functionality
* (optionally) ORM models to convert the data for persistence to a RDBMS
An even worse mistake is treating all three of those model layers as one and the same, which tools like Django REST Framework make it so easy to do. It all seems well and good for a while, as developers build up a big codebase with ease, but then are confronted with an almost insurmountable amount of work when the need to refactor arises.
The thing I’ve noticed when stepping into a codebase where this problem has been allowed to occur is the lack of layers of abstraction. Having those different models built up from the start allows for an application to shift along with the needs of the product. Having a single layer, with the endpoints talking literally directly to the ORM models, almost inevitably leads to calcification, spaghettification, and disastrous performance.