software engineering Aug 20, 2018

How to Make Swagger Codegen Work for Your Team

Swagger Codegen, the open source API client code generator, can be an extremely powerful, timesaving collaborative tool for your team. And like most powerful tools, it may not perfectly fit your needs right out of the box. In order to really make Swagger Codegen work for you and your team, it’s helpful to understand how Swagger Codegen works. But, first you might be asking, why?

The Virtue of “Laziness”

We will encourage you to develop the three great virtues of a programmer: laziness, impatience, and hubris.
- LarryWall, ProgrammingPerl (1st edition), O’Reilly and Associates

In a discussion of code generation tools, I’d be remiss to start without mentioning Larry Wall’s “three virtues of a programmer.” There might be a case to be made for Swagger Codegen in all three of these virtues, but I think the strongest case can be made for laziness.

Laziness, in this context, is explained by Larry Wall in the glossary of his famous book Programming Perl as, “The quality that makes you go to great effort to reduce overall energy expenditure. It makes you write labor-saving programs that other people will find useful…”

Now, when Larry Wall praises the virtue of laziness as a programmer, he’s not referring to cutting corners and doing lazy things like not writing unit tests. Larry Wall’s definition of laziness should in no way be taken as a defense of laziness in general. But if you’re doing “laziness“ right, and hopefully after reading this article you will be, using Swagger Codegen should mean not just less energy expenditure for yourself, but for all the members of your team.

You don’t need to write, maintain, or worry about the consistency of code that was generated automatically! You can save your labor and energy for tasks like writing blogs about code generation. 😇

But wait, before we get to generating code out of thin air we have to talk about what we need to get there as a team.

The OpenAPI Specification

The OpenAPI Specification (formerly known as the Swagger Specification) is a “language-agnostic interface to RESTful APIs” that enables developers of all kinds, versed in different programming languages, to discuss REST APIs in a way everyone understands. The specification allows developers to create a contract that defines how the API will work and what it should do before anyone has written a single line of code. This allows developers who will create and maintain the API and their clients to agree on a very specific contract and to say “If I post this body with these headers to this endpoint then I expect a response in this format.”

To take a specific example, I invite you to look at this OpenAPI Specification for a Pet Store app. The Pet Store example is one you will become very familiar with as you learn more about the OpenAPI Specification. This is the reference point every developer uses when they implement the code generation rules for every new language. Integration tests are always performed against OpenAPI specifications in the OpenAPI Initiative’s Github Repo.

After a brief review of the `petstore.yaml` we can see that a simple, but complete, API has been defined. Based on the requirements defined in this specification we could implement a backend service that returns a list of all pets in the database, or writes a new pet to the database, that was posted to the API. On the frontend side, we could then build the models we need to interact with the API and implement the correct services we could use to call the endpoints to fetch new pets or post new ones.

We could do all of that… but as “lazy” programmers we could use Swagger Codegen to do it instead!

Getting Started With Swagger Codegen

Before you can use Swagger Codegen you’ll need to install it locally. There are many different ways to install and use Swagger Codegen. In order to have the maximum amount of control to modify the project to fit our needs — and in order to follow along with this blog — the best way to get Swagger Codegen is to clone the whole repo: https://github.com/swagger-api/swagger-codegen. Once you have the project locally, you’ll need to run mvn clean package. If this completes successfully, you’ll see the swagger-codegen-cli.jar created in the directory modules/swagger-codegen-cli/target/.

Note — You can find instructions for downloading and installing Maven here if the `mvn` command line tool is not available in your environment.

This .jar file is a command line tool that provides the only interface you’ll need for using Swagger Codegen once you’re ready to generate code. Let’s take a simple example and generate the Swift client models for interfacing with the Pet Store API we looked at earlier.

Let’s create a clean working directory for our experiments:

mkdir ~/PetStoreApp; cd ~/PetStoreApp; open .;

Copy the swagger-codegen-cli.jar file into the PetStoreApp folder and download the petstore.yaml file to the same folder (right click the webpage in your browser > Save As…)

You should now have two files in your PetStoreApp folder.

Screenshot of the two files in a folder

Generating Code

In your terminal, ensure you are in the /PetStoreApp directory and run the following command:

java -jar swagger-codegen-cli.jar generate -i petstore.yaml -l swift4 -Dmodels

The whole breakdown of all the options you can use to generate code can be found here. You can also use the `help generate` command with the .jar file for additional details around this command. But for now, let’s break down the simple command above:

java -jar swagger-codegen-cli.jar

The java command line tool allows us to pass a Java ARchive (JAR) file and execute it in the command line. In this way we can run the Swagger Codegen command line tool.

generate

Generate is the command passed to the Swagger Codegen CLI tool. This is the main way to invoke the tool, everything else passed to the CLI tool are options that modify the execution of the generate command.

-i petstore.yaml

This is the input specification file. In this example we’ve passed in the Pet Store API yaml file. Swagger Codegen will use this specification file to generate our code.

-l swift4

Here we specify that we want Swagger Codegen to generate client-side Swift code for our app. We specified Swift 4, but Swagger Codegen has support for Swift 2, and Swift 3 as well.

-Dmodels

This final option specifies that we only want to generate model files for our API. This includes the models defined in the “definitions” section of the OpenAPI Specification at the bottom of the specification. Swagger Codegen can generate mock implementations of network code for you on the client. To keep this blog simple, I’ll be restricting our discussion to the generated models only and leave the generated networking code for another blog. Maybe 😀

After running the above command from the PetStoreApp directory, here is what you should see:

Screenshot showing the files in the appropriate folders

Note that the only files that Swagger Codegen has generated for us this time are model files. These are the model files defined in the `definitions`section of the `petstore.yaml` file we referenced in the generate command that was used to generate these models. As noted above, the `-Dmodels` flag we used is what signals to the Swagger Codegen Tool that we only want models generated. Generating models alone is a very powerful feature of Swagger Codegen because it allows us to do a few things.

  1. It allows us the freedom to use any networking library in our app. Swagger Codegen supports building all of the network request management code for RXSwift, Alamofire and PromiseKit.
  2. Generating models reduces the human error that could occur when defining shared models on the backend and frontend of a service. Even if you misspell a property name you can guarantee it’s misspelled in exactly the same way on both ends of the network request!
  3. If your app uses a lot of different models to communicate with your backend service, or if those models change often, you can significantly reduce the amount of time and effort required to maintain or to write those models from scratch. This is especially true if your frontend and backend services are implemented in different languages.

YAML to Swift

Swagger Codegen has created three new files for us based on the petstore.yaml file we passed in as our input specification. Let’s take a closer look at the Pet.swift file.

public struct Pet: Codable {
  public var _id: Int64
  public var name: String
  public var tag: String?
  public init(_id: Int64, name: String, tag: String?){
    self._id = _id
    self.name = name
    self.tag = tag
}
   public enum CodingKeys: String, CodingKey {
     case _id = “id”
     case name
     case tag
   }
}

When we compare this generated Swift model to the original definition in the OpenAPI Specification we’ll see the relationship clearly. The original OpenAPI Specification for this object looks like this:

Pet:
   required:
     - id
     - name
   properties:
    id:
    type: integer
    format: int64
   name:
    type: string
   tag:
    type: string

Even though the format of the data is in a slightly different form, all of the information we need to build the Swift object (or an object in any other language) is present in the OpenAPI Specification. However, the OpenAPI Specification is not the data from which the Swift object is ultimately generated. There is an intermediate state that Swagger Codegen generates based on the OpenAPI Specification prior to creating an object in a particular language.

An Intermediate Representation

While still in the /PetStoreApp directory we can run a command similar to the one we just ran, but this time we’ll pass a command to show us that intermediate state.

java -jar swagger-codegen-cli.jar generate -i petstore.yaml -l swift4 -DdebugModels

Passing the -DdebugModels flag will dump a lot of data to the terminal. In order to center yourself, you can search for this string in the terminal ”importPath” : “/Models.Pet”

This is the intermediate data object generated to represent the Pet model from the above OpenAPI Specification. You’ll notice that this has the same information as the OpenAPI Specification, but in a slightly different format. This data has been formatted in a way that we could easily use to generate a Swift class. For example, you’ll see one of the properties on this data object is an array of variables. Each of these variables is a property on our Pet class, and this object gives us lots of very specific information about these variables. Here is the data we can see about just the id property alone:

…
“vars” : [ {
   “baseName” : “id”,
   “getter” : “getId”,
   “setter” : “setId”,
   “datatype” : “Int64”,
   “datatypeWithEnum” : “Int64”,
   “dataFormat” : “int64”,
   “name” : “_id”,
   “defaultValueWithParam” : “ = data.id;”,
   “baseType” : “Int64”,
   “jsonSchema” : “{\n \”type\” : \”integer\”,\n \”format\” : \”int64\”\n}”,
   “exclusiveMinimum” : false,
   “exclusiveMaximum” : false,
   “hasMore” : true,
   “required” : true,
   “secondaryParam” : false,
   “hasMoreNonReadOnly” : true,
   “isPrimitiveType” : true,
   “isContainer” : false,
   “isNotContainer” : true,
   “isString” : false,
   “isNumeric” : true,
   “isInteger” : false,
   “isLong” : true,
   “isNumber” : false,
   “isFloat” : false,
   “isDouble” : false,
   “isByteArray” : false,
   “isBinary” : false,
   “isFile” : false,
   “isBoolean” : false,
   “isDate” : false,
   “isDateTime” : false,
   “isUuid” : false,
   “isListContainer” : false,
   “isMapContainer” : false,
   “isEnum” : false,
   “isReadOnly” : false,
   “vendorExtensions” : {
    “x-swift-optional-scalar” : true,
     “x-codegen-escaped-property-name” : true
    },
    “hasValidation” : false,
    “isInherited” : false,
    “nameInCamelCase” : “Id”
    “isXmlAttribute” : false,
    “isXmlWrapped” : false
   }
…

There is some magic going on here that some very helpful Swift developers have created for us. One particular example is the “name“ property. You’ll notice that the “name” is “_id”, but the “baseName” is “id”. This is helpful because id is a reserved keyword in Obj-C.

To make this generated code more interoperable with Obj-C, you’ll notice if you scroll up, that even though our Pet model is defined as having a property name of “id”, that case has been safely handled in the generated Swift class. That way, when we use the object on the client-side, we’ll reference the property as “_id”. However, anytime the object is serialized into JSON to be sent to the server, the correct “id” property name will be used.

But there still seems to be something missing here… How do we go from an OpenAPI Specification, to this large and unwieldy JSON blob, to a perfectly rendered Swift class? The answer is mustache templating!

Mustache Templating

The mustache templating system is used to insert variable values into a static text template. In the simplest possible example from the Mustache Documentation, it’s clear how the mustache templating system gets its name. The myriad sideways mustache-looking curly braces are used to identify the variable value that should be replaced.

Template:
{{#person?}}
  Hi {{name}}!
{{/person?}}
Hash:
{
 “person?”: { “name”: “Jon” }
}
Output:
Hi Jon!

Using this same system, we not only can generate models for a mobile app written in Swift, but we can generate code for every language we could possibly want. Sticking with the Swift example a bit longer, let’s investigate how you might create a template for a Swift object using the mustache template system.

Try it Yourself!

The Swagger Codegen implementation of a Swift 4 model object can be found here. But let’s make a simple version to illustrate some of the basics:

Template:
import Foundation
public class {{classname}}: Codable {
{{#vars}}
public var {{name}}: {{{datatype}}}{{^required}}?{{/required}}{{#defaultValue}} = {{{defaultValue}}}{{/defaultValue}}
{{/vars}}
init({{#vars}}{{name}}: {{{datatype}}}{{^required}}?{{/required}}{{^isFinal}},{{/isFinal}} {{/vars}}) {
    {{#vars}}
    self.{{name}} = {{name}}
    {{/vars}}
  }
}
Hash:
{
“classname”: “Pet”,
 “vars”: [
  {
   “name”: “_id”,
   “datatype”: “Int64”,
   “required”: true,
   “defaultValue”: 1
  },
  {
   “name”: “name”,
   “datatype”: “String”,
   “required”: false,
   “isFinal”: true
  }
 ]
}
Output:
import Foundation
public class Pet: Codable {
public var _id: Int64 = 1public var name: String?
init(id: Int64, name: String? ) {
       self._id = _id
       self.name = name
       }
}

I suggest taking the above template and JSON hash and inserting them into the simple Mustache demo app. Here you can play around with modifying the values of the hash or alter the mustache template to see if you can improve on, or create, new functionality. How could you re-create the coding keys enum seen in the Swift object at start of this blog? How could you modify the mustache template so that all of the data models created with this template conformed to the equatable or hashable protocols? If you can answer those questions then you’re well on the way to being the kind of “lazy” programmer who might never need to write or update another data model ever again!

Standard Swagger Codegen Customization

Most users of Swagger Codegen never need to modify the mustache templates that underlie the Swagger Codegen library itself as most use cases have been covered by the default implementation of each language’s mustache templates. However, there are also other ways to modify the output of Swagger Codegen without ever needing to modify the mustache templates. The default way to modify the behavior of the different language templates is to pass in a configuration object.

You can find out what configuration properties each language supports with this command:

java -jar swagger-codegen-cli.jar config-help -l <language (e.g. swift4, kotlin)>

Optionally use libraries to manage response. Currently PromiseKit, RxSwift are available.

responseAs
      Optionally use libraries to manage response. Currently PromiseKit, RxSwift are available.
    unwrapRequired
      Treat ‘required’ properties in response as non-optional (which would crash the app if API returns null as opposed to required option specified in json schema
 ```

To use these properties, you’ll need to create a new file where you can create a JSON object to pass as a new parameter to the Swagger Codegen CLI tool. While still in the PetStoreApp folder you created earlier, you can run the following command to create a JSON object that specifies RxSwift as the library for handling HTTP responses:

echo {“responseAs”:”RxSwift”} > config.json

Now you can pass this config.json file into the original CLI command to generate our code, while removing the directive -Dmodels and allowing Swagger Codegen to generate the full range of files beyond just data models:

java -jar swagger-codegen-cli.jar generate -i petstore.yaml -l swift4 -c config.json

Conclusion

Now you should have a pretty good understanding of not just what Swagger Codegen tools can do, but how to use them to embody the virtue of “laziness”. However, we’ve still only barely scratched the surface of the amazingly powerful tool that is Swagger Codegen and how it can help you reduce overall energy expenditure ala Larry Wall.

Swagger Codegen is under extremely active development and has an involved community so definitely check out their Github page for the latest on Swagger Codegen. Also, there are some other great codegen tools out there in addition to Swagger Codegen. I’d love to hear about other tools you like or your experiences with them. Feel free to reach out to me on Twitter for any questions or comments.

David Norman
Mobile Developer
@1DavidNorman

DISCLOSURE STATEMENT: These opinions are those of the author. Unless noted otherwise in this post, Capital One is not affiliated with, nor is it endorsed by, any of the companies mentioned. All trademarks and other intellectual property used or displayed are the ownership of their respective owners. This article is © 2018 Capital One.