How to Generate OpenAPI Definitions From Code
In this post we take a look at how to leverage your API code to generate OpenAPI definitions. After all, who doesn't like free documentation?
Join the DZone community and get the full member experience.Join For Free
An API lifecycle, just like any other product lifecycle, starts with the design phase. During this stage, the API is devised based on the needs of actual or potential API consumers, while taking other factors, such as business decisions about product scope or company-wide API design guidelines, into account. The team involved in the design phase then formalizes the results of their work into an OpenAPI definition file.
This is done by using more or less technical design tools (two of which we've previously covered on our blog, Swagger Editor and Apicurio Studio). The definition file subsequently becomes the input for the next step of the API lifecycle. This so-called schema-first or definition-driven approach is the ideal "textbook solution" that successful companies, from Adidas to Zalando, have implemented and put down as part of their API design guidelines, and that API evangelists and consultants would ask you to implement.
The real world, however, often differs from idealized workflows. Let's be honest here: many companies “do APIs” without any awareness of the importance of an API-first mindset and the best practices that fit into it. Smaller Agile teams may not have (or think they do not have) the resources to do it in this way, while larger companies may sit on legacy code and practices. Web APIs developed in such teams are not really designed, they're simply built as needed by developers directly in their codebase. Since there is no formal specification for these APIs, OpenAPI benefits, such as the ability to test the API against it, are not accessible.
Teams that have APIs that have grown organically without a specification, and most likely without any good documentation at all, have two possibilities: they can have someone sit down, take a look at their API and manually transform it into an OpenAPI definition. This is tedious work that takes time. Also, there's the question of whose responsibility this work is. Developers may not like it because it feels like an unnecessarily doubled effort having to maintain two artifacts. Technical writers or other team members can do it, but their work always needs to keep up with the implementation and, without a proper lifecycle in place, can quickly become outdated.
The other option is to make a step towards developers and accept their code as the single source of truth for the API and build a toolchain to convert the implementation into an OpenAPI definition. At a recent conference on API documentation in Amsterdam, representatives of companies such as MongoDB and Adyen talked about their choice of this "path of least resistance" for their API documentation strategy. Consequently, even though this is not the preferred schema-first approach everyone talks about, it is much more than a foul compromise and may actually be the best workflow for your own API team, especially if it's small and wants to act as quickly and flexible as possible. So, how can this work?
Based on our research, tools and libraries for OpenAPI exist for literally every programming language and can be roughly classified into two categories. The first set contains libraries that allow OpenAPI definitions to be written in a format that is native to the programming language or a common extension, such as annotations. When using these, developers still have to write most of the definition, but instead of being a single artifact, such as a YAML or JSON file, the definition is spread throughout the codebase and always very close to its implementation. Developers could, for example, take a database entity, model, or bean class that describes one of the domain concepts of their codebase (for example, a user, a post or a comment) and add the JSON Schema model directly to this class. While API operations are not converted to their OpenAPI equivalent automatically with this approach, the advantage, however, is that it works with every codebase independent of the framework that was used to build the API, because all the relevant information is maintained separately in annotations. For legacy code, this may be the only option.
The second set of libraries is dependent on specific frameworks but is much more magical, because it requires very little double effort. The same information is used, for example, to configure the API routes for the implementation as well as to generate the documentation of these routes. These tools can generate an almost complete specification with all routes together with their inputs and outputs with zero additional information. Developers can still add a human-readable description of each operation and give additional hints to their documentation tool through comments, annotations, or parameters.
We've collected some of the interesting libraries for each of the common programming languages used to build Web APIs.
The swagger-php library gives PHP developers the ability to express the entire OpenAPI specification in PHP annotations. Bindings for frameworks like Lumen, Laravel, or Silex are available, however, this library belongs to the first category and requires developers to explicitly add definitions for API operations to their code. Developers building projects with the popular Symfony framework can install the Nelmio ApiDoc bundle. This bundle automates as much as possible by collecting information from various sources throughout the project, such as route method definitions, project configuration, and annotations, and incorporates them into the specification. If you are starting a new API project in PHP you may want to have a look at API Platform, an open source project for building self-documented APIs with all the bells and whistles, such as hypermedia, on top of its support for OpenAPI.
In Java, Web APIs are often a part of an application built with the Spring MVC framework, or they are built with JAX-RS, a standard for RESTful Web Services in Java, for example using a framework such as Jersey, JAX-RS' reference implementation. Spring developers can use springfox, while JAX-RS developers can leverage swagger-core. The Swagger Maven Plugin even works with both.
Applications built in Node frequently use Express or HAPI as their framework. Third-party modules called swagger-express and hapi-swagger are available for those. Swagger-express supports writing OpenAPI definitions as annotations or in an external file and then leverages those to configure the framework, which means that there's little duplication of effort but developers work very closely with the OpenAPI format. HAPI-swagger is very simple to use and include in an existing HAPI project, it is often enough to add an 'api' tag to a route to have it included in the documentation.
Common frameworks for building APIs in Python are the Django Rest Framework and Flask-RESTPLUS. Django developers can add the django-rest-swagger module via pip, whereas Flask-RESTPLUS has Swagger support built in. Both are very powerful in terms of automation, so they do not require a lot of configuration. Django Rest Swagger utilizes Python Docstrings for the human-readable part of the OpenAPI definition and Flask-RESTPLUS presents a lot of opportunities to apply configuration, for example, for input validation, that serves both implementation and specification.
Ruby developers have some choices when it comes to integrating OpenAPI into their applications. There are gems such as swagger-docs, which is unfortunately stuck at Swagger 1.2 format, and openapi-rails for those using Ruby on Rails. Developers looking for a less powerful but framework-independent solution may like swagger-blocks. The best OpenAPI support seems to be available for Grape. The grape-swagger gem provides full OpenAPI support and works well with other gems, such as grape-entity. With the latter, it is possible to define models and use them in the specification as well as for input validation.
Goswagger is available for all the Go developers out there. It is a large package that is not limited to the use-case of self-documenting APIs but allows all kinds of work with Swagger and OpenAPI definitions in Go.
The Microsoft world supports OpenAPI, too. ASP.NET developers can install the Swashbuckle package and easily generate a specification for their APIs.
Virtually all the packages listed above allow for the conversion of your code, configuration, and annotations into an OpenAPI definition in real time and add an endpoint to the web server that distributes this file in JSON or YAML format. Furthermore, the packages come bundled with SwaggerUI, the browser-based interactive API playground from the Swagger project. This is fantastic during development because you basically have to only install the respective package, add a few lines of code, and, finally, open your local development web server on a URL such as http://localhost/swagger-ui/. There, you can immediately test drive your API while you're working on it and see how it looks for your API consumers. Every change of implementation is reflected immediately after refreshing the page in the browser.
While in production, you may want to reconsider if you want to serve your definition and SwaggerUI from the same endpoint where the API is hosted, or, rather, move those to a different location, such as your developer portal, or use a different console instead of SwaggerUI. It is also unnecessary to generate the definition every time that someone comes to view it. And even though those auto-generated OpenAPI definitions are complete and almost all metadata can be provided in your application's code, you may still want to do some manual edits to the definition. Of course, it is possible to disable the respective endpoints in production. You can download the autogenerated OpenAPI definition from your local web server, make your edits, and then upload it to its final destination, or provide it to third-party tools.
Many of the packages listed above also include the ability to trigger the OpenAPI conversion process from the command line or can be configured to do so. Your build process in your continuous integration (CI) environment, e.g. a tool like Jenkins or a service like Travis, is the best place to get your code transformed into an OpenAPI definition and deploy this specification wherever you need it or feed it into automated tests.
The power of OpenAPI is not limited to those who build their APIs with a schema-first approach. With plenty of tools available for developers in every programming language to integrate OpenAPI into the software development itself, there is really no excuse to not use it. Happy coding!
Published at DZone with permission of Lukas Rosenstock, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.