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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
The OpenAPI Spec and Kitura: Getting Started
25 mins
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:
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:
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:
- To bring up the emoji picker on a macOS machine, press Control + Command + Space bar.
-
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 rawDate
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 viewDate
values as ISO8601 strings, instead of raw values.
Click the Execute button, and note how the UI updates:
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.
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:
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.
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:
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:
- The underlying HTTP request to generate your SDK is made via Alamofire, an extremely popular Swift networking library by Matt Thompson.
- 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!
- 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!