Generate and test RESTful APIs in Swift

Generate and test RESTful APIs in Swift

Work smarter to create a networking API for a (mock) backend

Β·

5 min read

Don't spend hours writing code for a client API to interact with a server. Writing such code is tedious and repetitive if you support various clients in different programming languages.

Don't wait to start developing against a service that may not yet exist or for which you are waiting to get access.

You can create a fully functional client API and test it with a mocked backend literally in minutes with the help of some excellent open-source tools!

Tools

Based on a real-life example, using the existing IP geolocation API, I will explain and show you how to

  1. Get a RESTful API definition of the backend
  2. Mock the backend
  3. Generate a Swift client library
  4. Use the Swift client library in an application

Get a RESTful API definition of the backend

RESTful APIs can be described in a standard, language-agnostic way. This allows both humans and computers to discover and understand the service's capabilities without access to source code, documentation, or through network traffic inspection. This standard is called OpenAPI specification, previously known as Swagger. Today, the term Swagger is still around but describes a set of tools for implementing the OpenAPI specification, e.g.

  • Swagger Editor: lets you edit OpenAPI specifications in YAML inside your browser and preview documentation in real-time.
  • Swagger Codegen: Allows generation of API client libraries (SDK generation), server stubs, and documentation based on an OpenAPI Spec.

Browse through a repository of existing RESTful API definitions. You can also contribute to this "Wikipedia for Web APIs" as the folks of API gurus published it on GitHub.

OpenAPI Directory from apigurus.com

As an example, I will take this particular specification of an IP geolocation API. The folks from AbstractAPI allow developers to retrieve the region, country, and city behind any IP worldwide. No Swift client library exists yet.

IP geolocation API]

Let's open the specification in the browser through Swagger Editor.

swagger-editor.png

A single HTTP GET request for the v1 endpoint allows us to retrieve a bunch of geolocation information based on an IP address.

I haven't signed up, so I don't have access to the backend.

Mock the backend

Mockoon is a great application to run mock APIs locally easily. No remote deployment is needed, no hassle with account management. And it is open source with multi-platform support:

  • Windows
  • Linux and
  • macOS

You can download it from mockoon.com. Mockoon is also available through Homebrew brew install --cask mockoon.

Once installed, you can import an OpenAPI spec.

mockoon-import.png

Per default, the mocked service is using Mokoon's templating system to create dynamic responses.

Running a mocked server with Mockoon

So you can start your server and test it straight away. For simple HTTP requests, you can use curl. For more complex HTTP requests I recommend an app like Postman or Paw

Testing mocked server with curl

In this particular example, I did a minor change manually to improve the mocked response. I leveraged Faker.js with Handlebars to mock address-related information, e.g. "city": "{{faker 'address.city'}}"

Generate a Swift client library

There are multiple options to generate a client library for a backend service conveniently.

  • Swagger Codegen: Model and API generation from Swagger 2.0 or OpenAPI 3.0 spec. Dependency to popular networking library Alamofire
  • SwagGen: command-line tool that generates code from a OpenAPI/Swagger 3.0 spec. It is an alternative to the official Swagger-Codegen Java code generator and "adds some improvements such as speed, configurability, simplicity, extensibility, and an improved templating language".

I'll use usw Swagger Codegen as the generation is possible through the Swagger Editor in the browser. No tools are needed to install on my local machine :)

Swagger Codegen use in browser

Even if you are not a Swift developer, there is a pretty good chance that Swagger Codegen can speed up your development process. Because the generation of API client libraries and server stubs are possible in multiple languages, e.g. C#, C++, Go, Java, Python, and many more.

But I understand that Swagger Codegen might not suit your needs due to the dependency on Alamofire. In fact, when writing this article, Swagger Codegen relies on Alamofire 4.x, and using the Alamofire 5.x (released February 2020) would require you to fix the generated code to make it compatible with Alamofire 5.x.

If you don't have an Open API specification and simply a JSON representing the model of the HTTP response, then use quicktype. Try it in the browser or as a command-line tool, and it will generate strongly typed models and serializers in Swift for you. Also, here multiple target languages are supported.

Use the Swift client library in an application

The following steps are needed to use such a generated client library by Swagger Codegen:

  • Add Alamofire 4.x to your Xcode project, e.g. through Swift Package Manager
  • Unzip, copy and add the Swagger Client folder to your Xcode project
  • Use the desired APIs and their models located in the APIs and Models folder

For the IP Geolocation API the generated API code looks as follow

open class DefaultAPI1 {
    /**

     - parameter apiKey: (query)
     - parameter ipAddress: (query)  (optional)
     - parameter fields: (query)  (optional)
     - parameter completion: completion handler to receive the data and the error objects
     */
    open class func v1Get(apiKey: String,
                          ipAddress: String? = nil,
                          fields: String? = nil,
                          completion: @escaping ((_ data: InlineResponse200?,_ error: Error?) -> Void)) {
        // ..
    }
}

And here is the response model:

public struct InlineResponse200: Codable {

    public var city: String?
    public var cityGeonameId: Int?
    public var connection: InlineResponse200Connection?
    // ...
    public var region: String?
    public var regionGeonameId: Int?
    public var regionIsoCode: String?
    public var security: InlineResponse200Security?
    public var timezone: InlineResponse200Timezone?

To connect to the mock server, powered by Mockoon, you have to replace the basePath in SwaggerClientAPI.

open class SwaggerClientAPI {
    public static var basePath = "https://ipgeolocation.abstractapi.com"
    // ...
}

And there is the final example of how to invoke the client API to trigger an HTTP request to the mocked backend and receive a response.

SwaggerClientAPI.basePath = "http://localhost:3000"
DefaultAPI.v1Get(apiKey: "fakeApiKey", ipAddress: "fakeIpAddress") { possibleResponse, possibleError in
  if let error = possibleError { self.error = error }
  guard let response = possibleResponse else { return }
  // e.g. print(response.city)
}

All source code, included in a SwiftUI application, can be found on GitHub.

Did you find this article valuable?

Support Marco Eidinger by becoming a sponsor. Any amount is appreciated!