Protocol-Oriented-Networking in Swift

Join me for a Swift Community Celebration 🎉 in New York City on September 1st and 2nd. Use code NATASHATHEROBOT to get $100 off!

I recently gave a talk on Practical Protocol-Oriented-Programming(POP💥) in Swift. The video is still being made. Meanwhile, here is the written-up version of the POP Networking part of the talk for reference (for me and anyone else!).

The Usual Setup

Let’s say we have an app that displays pictures and information of food from around the world. Of course, it would have to fetch the information from the API. To do that, it is common to have an object that does the API request:

Since we’re making an asynchronous API call, we cannot use Swift’s built in Error Handling that either returns the correct response or throws an error. Instead, it is good practice to use the Result enum. You can read more about the Result enum here, but it is basically this:

When the API call is successful, a Success result with the correct payload of objects is passed into the completion handler – in the case of the FoodService, the successful result includes an array of Food objects. And if it’s unsuccessful, the Failure result is returned, with an error depending on the error that happened (e.g. 400).

The FoodService’s get function (to make the API call), is usually called in the ViewController, which decides how to handle the Result based on a Success or Failure scenario:

But there’s a problem…

The Problem

The Problem with the ViewController’s getFood() function is that it is the most important function in that ViewController. After all, it cannot display food on the screen if the correct API call is not made and the result (whether Success or Failure) is not handled correctly.

To make sure it does what it’s supposed to do (and that an intern or future you doesn’t accidentally change it to get deserts instead of all food), it is important to write tests for it. Yes, View Controller Tests 😱!

Seriously, it is not that bad… There is just this one weird trick to get your View Controller tests set up!

Ok, so we’re ready to test our View Controller. What’s next?!!!

Dependency Injection

To test the ViewController’s getFood() function properly, we need to inject the FoodService (the dependency) into it vs just calling it straight in the function!

This gives us at least a start to our tests:

Now, we need to have a lot more control over what result the FoodService actually returns…

Protocols FTW

So this is our current version of the FoodService:

For testing purposes, we need to be able to override the get function, to control which Result (success or failure) is passed to the ViewController, at which point we can then test how the ViewController handles a success vs failure.

Since FoodService is a struct, we cannot subclass it. Instead, you guessed it!, we can use protocols.

We can actually take out most of it’s functionality into a simple protocol:

Notice the associated type. This protocol will work for all our services. In this case we’re using it for FoodService, but of course you can use the same protocol for the CakeService or DonutService. By using this generic protocol, you’re adding very nice uniformity to all the services in your application.

Now, the only thing that changed in the FoodService, is that it conforms to the Gettable protocol. That’s it!

The other big benefit of using this approach is readability. By looking at the FoodService, you immediately see that it is Gettable. You can use this same pattern to also implement Creatable, Updatable, Delectable, etc, and you’ll immediately be able to see the service’s capabilities as soon as you look at it!

Using the Protocol 💪

So now, time to refactor! In the ViewController, instead of passing in the FoodService to the getFood method explicitly, we can constrain it to receive a Gettable that has [Food] as it’s associated type!

Now, we can easily test this!

Test All the Things!

To test the ViewController’s getFood function, we need to inject it with a Gettable that has [Food] as it’s associated type:

So now, we can just inject the Fake_FoodService to test that the ViewController does call a service that returns [Food] as a successful result and that it correctly assigns the [Food] as it’s data source for populating the TableView:

You can now of course also write a test for the different Failure scenarios as well (e.g. what error messages are displayed based on the ErrorType).


Using Protocols for the Networking layer makes your code UNIFORM, INJECTABLE, TESTABLE, and READABLE!

POP all the things!

Enjoy the article? Join over 20,000+ Swift developers and enthusiasts who get my weekly updates.

  • Pablo

    Hey Natasha! As usual, you’ve come up with a nice blog post, again.

    I really enjoy this idea of working around the protocol-oriented paradigm, and I’ve been facing this networking common situation in most of the projects I’ve been involved into. That’s why I decided to come up with some library to like “generalize” such common networking code for interacting with REST-like backends. I based my work on a previous library that had been written in Objective-C, but took advantage of all the cool features that Swift has got (e.g. protocol-oriented programming, generics, better error handling, optionals, etc.). So, I came up with Jayme…

    I’d love that you, and other Swifters visiting this site, take a look at it and give me some feedback on whether or not it can be useful for the community, and what features would be cool to add on it. It’s a little humble library with a tiny core. The idea is get the best of solid patterns and extensibility, encouraging the users to end up with well-designed architectures in their apps; it’s not meant to be a product that does everything for you. Jayme is still in his very first releases stage but I bet it can grow up.

    If you’re ever curious, here’s the announcement blog-post, explaining why we came up with Jayme:

    Any suggestion is welcome!
    Thanks for keeping the good work.
    Pablo. @pablolvillar

  • Excellent blog post. Concerning dependency injection, why not have FoodService in an initializer in your ViewController?

    • Ethan Sherr

      I think that’s problematic because you don’t necessarily have control over how a future develop initializes that view controller (aka was it through xib? or programmatically?).

  • Prajeet Shrestha

    The only thing FoodViewController needs to display list of foods is “array of food” here. So it’s the ultimate dependency rather than the FoodService(). Should view controller care about the different types of service that may be available for providing it the “array of food”? Or some outsider shall take care of that logic?

    • rydewnd2

      totally agree.

  • Joao Paulo

    Hello Natasha, thanks for the post. Do you have this source code in a project? I would love to download and take a look at how you organize the files in the project navigator. Thanks a lot!

  • loucimj

    Nice post!
    Here my 2 cents: the view controllers are handling the results from the service, I’ve been doing a thing similar to the example, but adding a protocol to avoid the handling of responses by the view controllers, and letting them know with the results for ok and not ok like this:

    protocol FoodHandler {
    func foodHasArrived( food:Array)
    func foodHadSomeProblem( error: String)

    extension FoodHandler {
    func getFood() {
    …. get the service and call foodHasArrived, or foodHadSomeProblem accordingly….

    class FoodLaLaViewController: FoodHandler {

  • Razvan Litianu

    Really good read!
    I tried this in Swift 4 and the syntax for the where clause changed to:
    func getRule(from service: Service) where Service.Data == Rule