The OpenAPI Spec and Kitura: Getting Started

Get started with the OpenAPI spec in this server-side Swift tutorial on using the Swagger API with Kitura to generate an SDK for your iOS app! By David Okun.

Leave a rating/review
Download materials
Save for later
Share

Time and experience have refined the principles of using REST, and most everyone who writes a REST API these days adheres to these common standards.

However, this standard leaves considerable room for variation. Developers tend to write RESTful APIs in their own style, and understanding the specifics of how a given back-end is structured can be difficult. Further, developers often take widely ranging approaches to documenting APIs, further adding to the difficulties awaiting you when encountering a new API.

In 2011, Tony Tam of the dictionary website wordnik.com encountered these very issues. He lamented the pain of needing to rewrite client-side SDKs every time developers updated a corresponding REST API. Necessity is the mother of invention, as the saying goes, and out of this pain the Swagger API project was born.

In this tutorial, you’ll get a quick overview of the history of this specification, and you’ll learn how you can use it to represent your Kitura API throughout the development of an iOS app named EmojiJournal!

By the time you finish this tutorial, you’ll be able to:

  • Visit a user-friendly website that documents your entire back-end.
  • Easily test all of your routes.
  • Generate an iOS SDK that just works with your API.

The Goals of Swagger

Building on Tony Tam’s trailblazing open-source project, other companies began contributing. Ultimately, the Linux Foundation assumed sponsorship of the project, changing its name to the OpenAPI Initiative. This broad support brings the OpenAPI Specification to a very prominent place in open-source software development.

When Tony began working on the Swagger API project, he defined three key goals:

  • API development
  • API documentation
  • API interaction

You might say that no one on the corner had swagger like Tony! :]

There’s no shortage of tooling available for testing your API — one popular tool you may be familiar with is the excellent Postman — and there are many other excellent dedicated tools in the this space as well. But the OpenAPI Initiative aimed to make the experience of developing, documenting and interacting with an API significantly easier and more predictable.

Consider an example from the EmojiJournal application for this tutorial. Since you already have a POST route set up, you could test this route with a simple cURL command from Terminal:

curl -X POST \
-H "Content-Type: application/json" \
-d '{"emoji":"😁", "date": 563725805.57661498}' \
http://localhost:8080/entries

This might feel pretty straightforward if you’re comfortable with cURL. You might even envision using cURL like this with real-world team projects. But in reality, you simply cannot guarantee that everyone on your team will know how — or choose – to use cURL as you do. An ad hoc approach like this won’t cut it in the real world.

The Swagger project addresses this by specifying a consistent, user-friendly user interface. By definition, an interface should always provide the following for each method available on the API:

  • The specific method (GET, POST, DELETE, etc.).
  • What to put in the body of the request.
  • Possible responses.

Here’s an example of what this might look like for a POST method using the KituraOpenAPI module:

KituraOpenAPI module

Notice that this page achieves all three goals of the Swagger project: You can develop your API quicker by interacting with your results as you write your code, and check its accuracy via the documentation it generates. This is really neat! While you may still see your peers developing APIs manually, having these powerful tools in your back pocket makes developing your Kitura APIs faster, more reliable and even… fun!

That’s pretty great, but… wait a minute! Exactly how does all of this get generated? How do your routes get converted to this friendly and powerful user interface? The answer lies in the specification itself.

Getting Started

Download the starter project materials using the Download Materials button at the top or bottom of this page.

To open the EmojiJournalServer starter project, first run the following in Terminal from the EmojiJournalServer directory:

swift package generate-xcodeproj

Then open the project via:

open EmojiJournalServer.xcodeproj

Open Package.swift and append the following to your list of dependencies:

.package(
  url: "https://github.com/IBM-Swift/Kitura-OpenAPI.git", 
  from: "1.1.1"),

Next, find the Application target within your targets array and append "KituraOpenAPI" to its dependencies array. Your targets section should now look this:

targets: [
  .target(
    name: "EmojiJournalServer", 
    dependencies: [
      .target(name: "Application"),
      "Kitura",
      "HeliumLogger"]),
  .target(
    name: "Application",
    dependencies: [
      "Kitura", 
      "CloudEnvironment", 
      "SwiftMetrics", 
      "Health", 
      "KituraOpenAPI"]),
  .testTarget(
    name: "ApplicationTests", 
    dependencies: [
      .target(name: "Application"), 
      "Kitura", 
      "HeliumLogger"]),
]

Save your Package.swift file.

Now, open Terminal and navigate to the root directory of EmojiJournalServer.

Enter the command swift package update. This will tell Swift Package Manager to examine the manifest and search for new dependencies, resolve a new dependency graph and download what it needs.

After this finishes, enter swift build to rebuild your project.

Finally, enter swift package generate-xcodeproj to generate an Xcode project file (if it doesn’t already exist) and update it with your new dependencies.

Note: You can do all this with the command swift package generate-xcodeproj. When you do this, the Swift Package Manager will handle all of the package resolution and building for you! The reason you just performed each of these three steps manually was to make clear what’s happening under the hood. We’ll typically use this single shorthand command moving forward.

Open your newly generated Xcode project, and go to Sources/Application/Application.swift. Scroll to the top of the file, and append the following after your current import statements:

import KituraOpenAPI

You’ll likely notice that Xcode doesn’t auto-complete doesn’t recognize this module and you’ll probably also see a “No such module ’KituraOpenApi’” warning from Xcode. No worries — this happens because you haven’t yet built your project in Xcode itself.

Build your project now. It should build without errors, demonstrating that you’ve updated your project’s dependencies to include the new package you specified in your Package.swift file a moment ago. Sweet!

Next, scroll down to your postInit() method and append this to it:

KituraOpenAPI.addEndpoints(to: router)

Build and run your project. Now, open a web browser and navigate to http://localhost:8080/openapi. You should see something like this:

OpenAPI route

What you’re seeing is a description of the API you’ve built so far, following the OpenAPI Specification. What’s fairly amazing is that all you needed to do to make this happen was to add a single project dependency, one import statement and one line of code. With these lightweight pieces in place, Kitura automatically took care of everything else needed to create this description of your API on your behalf!

Next, let’s walk through some components of this specification to clarify how this can help you develop, document and interact with your API in practice.

Examining Your Specification

Start by looking at the very top of your JSON spec:

{
"schemes" : [
  "http"
],
"swagger" : "2.0",
"info" : {
  "version" : "1.0",
  "title" : "Kitura Project",
  "description" : "Generated by Kitura"
},

This is metadata describing your project. Consider that one purpose of this specification is to allow other people to easily understand your API’s structure and purpose. This is where human-readable metadata comes in handy.

Right after this metadata, you’ll find the “paths” node. This contains an array of “/entries” describing each of the endpoints you’ve created so far. Find the “get” entry within this:

"get": {
  "responses": {
      "200": {
         "schema": {
           "type": "array",
              "items": {
                "$ref": "#\/definitions\/JournalEntry"
              }
            },
       "description": "successful response"
     }
  },
  "consumes": [
    "application\/json"
  ],
  "produces": [
    "application\/json"
  ]
}

The top of this snippet indicates that you are looking at a GET route for the path “/entries”. Three sub-nodes describe this route:

  • “responses” provides an array of responses a user can receive.
  • “consumes” specifies the data type this method must be given.
  • “produces” describes the type of data the response will contain.

Next, still within the “/entries” node, find your POST route. Note that in comparison to the GET route you just saw, this contains an additional sub-node:

"parameters" : [
  {
    "in" : "body",
    "name" : "input",
    "required" : true,
    "schema" : {
      "$ref" : "#\/definitions\/JournalEntry"
    }
  }
]

As you can see, when you write a POST route, the spec generator automatically adds information about the body of the request you need to send to yield a successful response.

Take a moment to scroll through the rest of your currently available methods and take note of the similar properties and formats shared across each method.

You’re seeing the consistent sets of data defined by the OpenAPI Specification that will enable the generated UI to test each method you write. Now, scroll down to the “definitions” node:

"definitions": {
  "Status": {
    "type": "object",
    "required": ["timestamp","details","status"],
    "properties": {
      "status": {"type":"string"},
      "details": {"items":{"type":"string"},"type":"array"},
      "timestamp": {"type":"string"}
    }
  },
  "JournalEntry": {
    "type": "object",
    "required": ["emoji","date"],
    "properties": {
      "id": {"type":"string"},
      "emoji": {"type":"string"},
      "date": {"type":"number"}
    }
  }
}

Focus on the JournalEntry node, here. You have a Swift model object named JournalEntry in Source/Models that is representable as JSON. The KituraOpenAPI module has automatically added it to your project spec!

This is a nice demonstration of how the KituraOpenAPI module dynamically observes the types of your JournalEntry object and automatically constructs a reference for them in your specification.

Here’s the really great thing about all this: You now have living, breathing documentation of your API. As you continue to build out your app, be sure to check back and see how this specification grows and changes automagically!

Using the Kitura OpenAPI UI

Make sure your EmojiJournalServer app is still running in Xcode, then open a browser and go to http://localhost:8080/openapi/ui. You should see a page like this:

OpenAPI UI

You’ve just learned how this information is created under the hood. Now it’s time to learn how to explore and interact with your API.

Click on the POST route. Notice how the route’s description expands:

POST route

Each component of your JSON is clearly represented, here. Even better, your entire API is now fully explorable!

Click the Try it out button at the top of this expanded page.

Because a POST route requires input, the interface pauses to let you enter this, displaying the input types required.

In the main text area (underneath the Edit Value | Model caption), enter the following:

{
  "emoji": "🤓",
  "date": 563725805.57661498
}

Before continuing, two notes about this:

  1. To bring up the emoji picker on a macOS machine, press Control + Command + Space bar.
  2. The date here is represented as a number that doesn’t really seem to mean anything. Don’t worry — this is just how Swift stores raw Date values under the hood. As is, this will work fine with your iOS app. It’s also possible to add a custom decoder so you can pass and view Date values as ISO8601 strings, instead of raw values.

Click the Execute button, and note how the UI updates:

Executing the POST

Remember that inscrutable cURL command you’ve been using? This page shows you the exact cURL syntax needed to test any route you select! This can be very helpful in cases where you need to do a quick and dirty test — or if you just can’t convince a stubborn teammate how useful this module really is!

Also, notice that you received a “201” response and that the object you created is echoed back to you for your inspection. As expected, your POST route works! You can also easily see the headers of your response, which can be very helpful if you run into issues later on.

Note: Under the Server response header is the actual response you received from trying out the API. Underneath that is a “Responses” header that was part of the documentation before you tested out the API. One is the actual response, the other the documentation of what a response should look like. Hopefully this helps you understand the difference.

Now, scroll to your GET /entries route. Take a moment to familiarize yourself with the contents of the page, then click Try it out and then Execute:

Executing the GET

As expected, your GET route returns the JournalEntry object that you created with your POST request. You also get other key information returned with that response in an easily digestible UI. Is this UI nice or what?

Feel free to test the rest of the Kitura OpenAPI UI at your leisure. Now it’s time to give your iOS app a little love!

Generating an SDK for Your iOS App

The last thing you’re going to do with the OpenAPI Specification is so awesome that it just might become your very favorite!

One of the auxiliary toolsets within the OpenAPI Initiative is the swagger-codegen tool, which lets you generate a client SDK in up to 30 different programming languages! I encourage you to play around with this tool and try generating some other SDK’s in other languages (we’ll stick with Swift, here).

For the last part of this tutorial, you’ll need to make sure that your system has Docker up and running. The instructions in the tutorial Docker on macOS: Getting Started should be enough to get you going with Docker. To ensure that you are ready to go, open Terminal and type in docker version. If you see output telling you that you are running version 18.09.0 or better, then you’re all set.

Note: If you’d rather install this codegen tool through Homebrew — you can! We’ve chosen not to go that route in this tutorial so that you don’t need to install Java (a requirement of the codegen tool) directly onto your machine, since Java can be a bit of a lightning rod for many developers. By installing codegen in Docker, you’re shielded from having to worry about any potential harms of Java.

In Terminal, type the following command:

docker pull swaggerapi/swagger-codegen-cli

Once the image and all of its dependencies are done installing on your machine, enter this command in Terminal:

docker run --rm -v ${PWD}:/local \
  swaggerapi/swagger-codegen-cli langs

If you are somewhat familiar with Docker, then you may notice that you are specifying a volume to mount into this image. This is so that the codegen tool has a reference back to your local directory when it takes the parameters it needs. The output of this command should look like similar to this:

Available languages: [ada, ada-server, akka-scala, android, apache2, apex, aspnetcore, bash, csharp, clojure, cwiki, cpprest, csharp-dotnet2, dart, elixir, elm, eiffel, erlang-client, erlang-server, finch, flash, python-flask, go, go-server, groovy, haskell-http-client, haskell, jmeter, jaxrs-cxf-client, jaxrs-cxf, java, inflector, jaxrs-cxf-cdi, jaxrs-spec, jaxrs, msf4j, java-pkmst, java-play-framework, jaxrs-resteasy-eap, jaxrs-resteasy, javascript, javascript-closure-angular, java-vertx, kotlin, lua, lumen, nancyfx, nodejs-server, objc, perl, php, powershell, pistache-server, python, qt5cpp, r, rails5, restbed, ruby, rust, rust-server, scala, scala-gatling, scala-lagom-server, scalatra, scalaz, php-silex, sinatra, slim, spring, dynamic-html, html2, html, swagger, swagger-yaml, swift4, swift3, swift, php-symfony, tizen, typescript-aurelia, typescript-angular, typescript-inversify, typescript-angularjs, typescript-fetch, typescript-jquery, typescript-node, undertow, ze-ph, kotlin-server]

The starter project directory for this tutorial has an EmojiJournalMobileApp directory to get you started. Still in Terminal, navigate to the root folder of EmojiJournalMobileApp. Create a new directory to store your generated SDK, and a local file for your specification:

mkdir GeneratedSDK
touch specification.json

Even though the specification is live for you at http://localhost:8080/openapi, the Docker container you are about to run can’t easily access that URL outside of its own environment. You could monkey around with container network settings, but for simplicity you’ll take a simpler approach.

Open specification.json in a text editor. Copy the contents of http://localhost:8080/openapi from your browser and paste them into specification.json. Save your file.

Here comes the magic! Enter the following command:

docker run --rm -v ${PWD}:/local \
 swaggerapi/swagger-codegen-cli generate \
 -i /local/specification.json -l swift \
 -o /local/GeneratedSDK

Open your GeneratedSDK folder and take a look at its newly created contents:

GeneratedSDK folder

With a single CLI command, you’ve just created a fully functional Swift SDK that can handle all of your network communications with this specific server. Think of the time you’ll save with all the code you will no longer have to write!

We’re big fans of small commands that yield big output, and this is an especially sweet example of that! Let’s take a moment to understand what the codegen tool has given you in a bit more detail:

  1. The underlying HTTP request to generate your SDK is made via Alamofire, an extremely popular Swift networking library by Matt Thompson.
  2. You get both Cartfile and .podspec files to implement this SDK. This means you can choose either Carthage or Cocoapods to integrate your SDK. Either way, you won’t have to drag and drop all the files into your project over and over!
  3. Everything is documented!

Open up GeneratedSDK/SwaggerClient/Classes/Swaggers/APIs/DefaultAPI.swift in a text editor. Locate the method entriesPost — line 93 at the time this was written:

public class func entriesPost(input input: JournalEntry, 
  completion: ((data: JournalEntry?, error: ErrorType?) 
  -> Void)) {
    entriesPostWithRequestBuilder(input: input)
      .execute { (response, error) -> Void in
        completion(data: response?.body, error: error);
    }
}

This method is your entry point to sending a new JournalEntry to your server! This means that you can use the following code to create a new JournalEntry object and send it to your server:

let newEntry = JournalEntry(id: nil, emoji: "😍", date: Date())
DefaultAPI.entriesPost(input: newEntry) { data, error in
  // handle response here
})

Nice and simple! This gives you a quick sample of how useful codegen can be as you develop your Kitura apps. You’ll likely find that being able to automatically generate client APIs — in a very wide array of languages and directly from your server code — will be incredibly useful. In practice, this can not only save time and get you up and running quickly, it can also save errors and prove especially helpful for folks who aren’t (gasp) working in Swift!

Where to Go From Here?

You can download the finished project for this tutorial using the Download Materials button at the top or bottom of this page.

Hopefully, by now, you can see clearly how powerful and effortless Kitura’s OpenAPI support is. In practice, you’ll likely find this an invaluable tool within your team, especially for testing your API. Over time, you’ll also likely find these tools especially valuable to developers outside your team, as they seek to understand and interact with your API in a platform-neutral, standards-compliant way.

While Kitura provides fantastic tools for exploring and documenting your JSON APIs, it also shields you from working directly with these within your Swift code — via an SDK called KituraKit. You can find out more about KituraKit on its GitHub page.

As you’ll see, this gives you the best of both worlds: Kitura’s amazing OpenAPI support and tools make it super easy for developers of all persuasions to understand your public APIs. At the same time, thanks to KituraKit, you’ll be able to ignore JSON implementation details and focus on clean, native Swift types in your code. It’s a huge win-win!

If you ran into any difficulties along the way, feel free to check out the final projects for this tutorial. (Remember that you’ll need to run swift package generate-xcodeproj in Terminal before working with any starter or final project in Xcode).

If you have any comments or questions about this article, feel free to ask them in the comments below!