loading...
Cover image for Why document a REST API as code?

Why document a REST API as code?

rolfstreefkerk profile image Rolf Streefkerk ・9 min read

TL;DR

If you're already familiar with OpenAPI and its place in the application life-cycle, skip to the tooling chapter which is the core of this blog post.

Stay tuned for the next article. I'll discuss implementation with OpenAPI, and Terraform support tooling.

Thanks for reading!

Topic break-down

Why document a REST API as code?

There are many ways to create API's these days, through the use of frameworks such as Express (Node environment), Java Spring, or Cloud native solutions such as API Gateway from Amazon Web Services.

The overarching problem I see with using these solutions solely is that they do not describe "API as Code". You might wonder, why should I care? here's a few reasons why:

  • The ability to generate server and client side code from a programming language agnostic REST API definition file (OpenAPI).
  • As a communication tool, it is the basis of documentation that is readable by both front-end, business, third parties (public API's), and back-end developers alike.
  • Follows the Infrastructure as Code paradigm, we can test and validate our REST API definitions (endpoint, models, security, and input & output) more easily. We can version control our API definitions.
  • Development environment friendly, easy to generate REST API stubs and have front / back end developers program against a specification.
  • Supports a formal Object Model specification (e.g. JSON Schema) that specifies inputs and outputs of API endpoints.
  • Keeps your implementation and formal API specification document in sync. It is rare that documentation keeps in sync with the real world situation. We usually forget to update our documentation throughout all the changes.

Having said that, how does OpenAPI propose to solve this?

What is OpenAPI?

Good design and programming practices recommend the use of interface definitions. An interface definition defines what a system or a piece of code (module etc) is doing from a high level standpoint, and then you program against that interface.

This achieves decoupling of the actual implementation code from the interface code (the outside world in a broad sense). We're free to choose how we implement against the contract as long as we satisfy it. Furthermore, we're simplifying application design by abstracting away as much of the implementation details as we can (black box principle).

OpenAPI does exactly that, it provides an interface definition that bridges the front-facing application and the back-end "processing / data storage" part of the application (typical 3-tier architecture situation).

How it does that is through a REST API specification document that defines in code (YAML or JSON) API endpoints and data models (JSON Schema) amongst other things. With this programming language agnostic API definition file you can generate code across application tiers (front-end and back-end), and validate input and output against its JSON Schema definition.

A good and well documented design of this interface will therefore benefit the whole application development life-cycle.

There are a few steps involved in getting this all working together. What we will cover in brief is:

I won't cover the structure of the language in depth just yet, I'll do that in later blog posts with a sample application. For now, review this short explanation to get an idea.

Where does OpenAPI fit in?

Broadly we can identify these application development phases, and I'll put several together to condense the discussion:

  • Requirements, Analysis and Design; What are we building?
  • Code & Test, We're building building and testing it.
  • Production & Maintenance, It is in production and running

Here we can have several iterations of phases depending upon project management style (Agile, Waterfall etc.) Again, a very broad topic. For now let's consider these phases, where does OpenAPI fit in?

Requirements, Analysis and Design

In this phase OpenAPI will be used by front and back-end developers to agree on what is required at both sides to satisfy business and architectural requirements. This in itself is a very expansive discussion, what OpenAPI does is formalize the output of that design process into code that can be used in subsequent development phases.
OpenAPI can also formalize security concepts, such as publicly accessible or requiring authenticated access, as well as extensions.

Extensions (e.g. Google Cloud Endpoints, AWS API Gateway) enable vendors or companies to add "features" to the API specification. For instance, AWS API Gateway has developed extensions to codify its integration with backend services. That means an endpoint, e.g.

GET /customer/2

, can be directly integrated with a DynamoDB database through a Velocity template. Or, with a code execution service such as Lambda.

All of this formalized into a document that satisfies both the why and the how of the API. Which brings us to the next steps, code and test.

Code and Test

In this stage normally the Tester will have a document that outlines the test cases from the business requirements side, but it will have to wait to do any contract testing before an API is available to do so. With an OpenAPI document you get a head start, tests can be generated from the specification (up to a certain point).

On the developer side, the API can already be generated as a client and server side stub from the OpenAPI document. That facilitates independent client and server side development.

Developers and testers can iteratively work through testing and developing contracts in a much more rapid pace than before. Furthermore, both client and server side can leverage the validation of data models through the use of the included JSON Schema definition.

Production and Maintenance

Once the application hits the production & maintenance phase the specification is effective for:

  • Verification, here we verify the OpenAPi specification document is the same as what is deployed. Tooling such as Dredd can help here
  • Testing, what we intend to deploy to production, does it operate according to the specification?
  • Documentation, answering such questions as;
    • what has been built,
    • how can developers, internally and potentially externally, implement against the API specification.

Tooling?

Now we're getting to the meat and bones of OpenAPI and why I love to use it, the tooling!

dilbert

It may take a few thousand lines of code to specify every single thing about your API, but then the automation you have unleashed makes this a productivity booster you wouldn't believe.

So lets have a look shall we.

Design and Development

  • Swagger hub and Swagger Editor, Swagger generally (as creators of Swagger/OpenAPI) provide tooling across the application life-cycle. I particularly like their Editor to validate the specification on the fly, and as a documentation/code generation tool.
  • Visual Studio Code. This editor has a lot of plugins that simplify editing large OpenAPI documents, the plugins I use:

Implementation frameworks

A few of the major frameworks, and cloud native solutions that I have used:

  • AWS API Gateway, you can either use IAC tooling or the GUI to import a Swagger/OpenAPI document and it will create the endpoints automatically. There are specific AWS Extensions to the OpenAPI specification that will add Authentication, and Integration with AWS Lambda for instance.
  • Java Spring Boot / Maven integration, this article describes a possible integration between the two.
  • Node/ExpressJS
    • OpenAPI Enforcer has a specific side project that will generate the endpoint in your Express app automatically. It also included data validation via the JSON Schema definitions in the OpenAPI document, see the validation sub-section.

Code generation

Both of these provide a similar set of client and server generator output

Languages / Frameworks
API clients ActionScript, Ada, Apex, Bash, C, C# (.net 2.0, 3.5 or later, .NET Standard 1.3 - 2.0, .NET Core 2.0), C++ (cpp-restsdk, Qt5, Tizen), Clojure, Dart (1.x, 2.x), Elixir, Elm, Eiffel, Erlang, Go, Groovy, Haskell (http-client, Servant), Java (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client, MicroProfile Rest Client), Kotlin, Lua, Nim, Node.js/JavaScript (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types), Objective-C, OCaml, Perl, PHP, PowerShell, Python, R, Ruby, Rust (rust, rust-server), Scala (akka, http4s, scalaz, swagger-async-httpclient), Swift (2.x, 3.x, 4.x, 5.x), Typescript (AngularJS, Angular (2.x - 8.x), Aurelia, Axios, Fetch, Inversify, jQuery, Node, Rxjs)
Server stubs Ada, C# (ASP.NET Core, NancyFx), C++ (Pistache, Restbed, Qt5 QHTTPEngine), Erlang, F# (Giraffe), Go (net/http, Gin), Haskell (Servant), Java (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, Jersey, RestEasy, Play Framework, PKMST, Vert.x), Kotlin (Spring Boot, Ktor, Vertx), PHP (Laravel, Lumen, Slim, Silex, Symfony, Zend Expressive), Python (Flask), NodeJS, Ruby (Sinatra, Rails5), Rust (rust-server), Scala (Finch, Lagom, Play, Scalatra)
Languages / Frameworks
API clients ActionScript, Ada, Apex, Bash, C# (.net 2.0, 3.5 or later), C++ (cpprest, Qt5, Tizen), Clojure, Dart, Elixir, Elm, Eiffel, Erlang, Go, Groovy, Haskell (http-client, Servant), Java (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured), Kotlin, Lua, Node.js (ES5, ES6, AngularJS with Google Closure Compiler annotations) Objective-C, Perl, PHP, PowerShell, Python, R, Ruby, Rust (rust, rust-server), Scala (akka, http4s, swagger-async-httpclient), Swift (2.x, 3.x, 4.x, 5.x), Typescript (Angular1.x, Angular2.x, Fetch, jQuery, Node)
Server stubs Ada, C# (ASP.NET Core, NancyFx), C++ (Pistache, Restbed), Erlang, Go, Haskell (Servant), Java (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, RestEasy, Play Framework, PKMST), Kotlin, PHP (Lumen, Slim, Silex, Symfony, Zend Expressive), Python (Flask), NodeJS, Ruby (Sinatra, Rails5), Rust (rust-server), Scala (Finch, Lagom, Scalatra)

Validation and Testing

  • Dredd is a CLI tool / Javascript Library that can validate your specification against a running Server. OpenAPI 3 support is still experimental (!)
  • OpenAPI Enforcer, validation library for server side Node (optionally Express).
  • Swagger Test generation automatically creates test cases for specific HTTP status codes and it can also do load testing.
  • JSON Schema validators / generators / testing, a lot of tooling exists to validate, generate, and test based on JSON Schemas.

What's next?

Next week I'll demonstrate with Terraform, and AWS API Gateway how we can use an OpenAPI specification to create a server side REST API with validation.

Let me know in the comments below if this article was useful for you and what else you'd like to read about.

If you're already using OpenAPI, please tell me in the comments what your experiences are with it.

Thanks for reading and till next week!

Further reading

Discussion

pic
Editor guide
Collapse
miniscruff profile image
miniscruff

For Python; Fast API, flask-rest-api and Django rest framework all support open API.

Collapse
dvddpl profile image
Davide de Paolis

wow. very nice series of post! incredibly useful!