Parsing Swagger Specifications

It's pretty old, but it's still important.

Before we jump into the code, let’s get some context around Swagger with a very short history lesson.

The API wars

Swagger (Or now known affectionately as OpenAPI 2) first came onto the scene in 2012, which in tech years would make Swagger look like something built in the early 1900s.

Swagger/OpenAPI 2.0 emerged around 2014 and in 2015/2016 we saw a battle emerge between two competing standards, one is RAML (which was a product from MuleSoft) and the other was Swagger (which is a product from SmartBear).

Both RAML and Swagger went head to head with each other.

RAML had better features and a more elegant DSL, Swagger had better tools and a better community.

VHS vs. Betamax

The industry spoke loud and clear, we overwhelmingly chose Swagger. The wider reach and larger community of Swagger drove the adoption of the standard.

Swagger is reborn as OpenAPI

Because the industry settled on OpenAPI, we turned it into an actual standard called the OpenAPI initiative, separate from SmartBear.

OpenAPI 3.0 was the first release, it cleaned up a ton of mess from the legacy of Swagger’s design and aligned much closer with another community standard JSON Schema,


Parsing a Swagger Specification

libopenapi contains two models, one for Swagger and one for OpenAPI. This is because they are so fundamentally different in many places. To keep things cleaner we wrote separate Swagger models where they deviated from OpenAPI.

import (
  "fmt"
  "github.com/pb33f/libopenapi"
  "github.com/pb33f/libopenapi/datamodel/high/v2"
  "io/ioutil"
)

func main() {
  // How to read in a Swagger / OpenAPI 2 Specification, into a Document.

  // load a Swagger specification from bytes
  petstore, _ := ioutil.ReadFile("petstorev2.json")

  // create a new document from specification bytes
  document, err := libopenapi.NewDocument(petstore)

  // if anything went wrong, an error is thrown
  if err != nil {
      panic(fmt.Sprintf("cannot create new document: %e", err))
  }

  // define variables to capture the v2 model, or any errors thrown
  var errors []error
  var v2Model *libopenapi.DocumentModel[v2.Swagger]

  // because we know this is a v2 spec, 
  // we can build a ready to go model from it.
  v2Model, errors = document.BuildV2Model()

  // if anything went wrong when building the v2 model, 
  // a slice of errors will be returned
  if len(errors) > 0 {
      for i := range errors {
          fmt.Printf("error: %e\n", errors[i])
      }
      panic(fmt.Sprintf("cannot create v3 model from " +
          "document: %d errors reported", len(errors)))
  }

  // get a count of the number of paths and schemas.
  paths := len(v2Model.Model.Paths.PathItems)
  schemas := len(v2Model.Model.Definitions.Definitions)

  // print the number of paths and schemas in the document
  fmt.Printf("There are %d paths and %d schemas" +
      " in the document", paths, schemas)
  
}

Which will output:

There are 14 paths and 6 schemas in the document

Some friendly advice

Even though libopenapi supports Swagger, we don’t recommend using it. It’s ancient and suffering from bitrot in lots of tools the support it (not our tools of course)

Use, or start with OpenAPI instead of Swagger.