
Generic JSON parsing using Protocol Oriented Programming
Clarification:
The article’s purpose isn’t to replace the new Codable, this article is about implementing an architecture that can go along with Codable or whatever you might choose
Every (Swift) software developer will eventually need to parse a JSON for his/her iOS app (or macOS).
Throughout my career I have seen many architecture methodologies of how to parse a JSON.
You should always ask yourself (for any functionality you develop):
- Does the architecture you have build is an evolutionary system that can adapt (if not, it’s not agile..) for any given change without modifying base code/class/struct ?
- If your methodology is based on OOP, do you keep the SOLID principles intact ?
- Does the service is loose coupling ?
In a recent meet-up I have attended too regarding architecture methodologies and principles, they showed a slide with the quote:
A developer knows what can be done.
An architect knows what should be done.
So what should be done … ?
Let’s break JSON parsing down, what is involved in parsing a JSON:
- Invoking a request to the server and obtaining the response from a closure (for example).
- In most projects, the server side responds in a different legality to our requests thus, we need a validator that validates the legality of the JSON response regardless of the actual data that we need to parse.
Of course, if the server response status code isn’t 4xx we can validate the JSON, otherwise, we will return the error.
At this point we can assess if our next step is to: - Parse the JSON and deserialise relevant object(s)
or - return the relevant error from the validator.
Nothing new here, plain and simple :)
First step — Building the parse protocol:
Our main objective is to write down a small and concentrated code that decouples every of the above steps and of course do it the POP way (protocol oriented programming).
I am a huge fan of Alamofire so lets assume that the response is the standard DataResponse<Any>:
Alamofire.request(...).responseJSON { (resp: DataResponse<Any>) in ... }We need a protocol that will describe the set of methods we broke down earlier. We will be needing 3 methods:
- A method that encapsulate the actual logic that runs the whole “show”.
- A method that validates the JSON — this method will return the inner JSON (an example will be shown later).
- A method that will parse our data and create the actual objects that should be somewhere inside the inner JSON.
public protocol ParseProtocol {
func validateData(response : DataResponse<Any>) -> ?
func parseData(withValue value : ?) -> ?
}extension ParseProtocol {
func begin(forResponse response: DataResponse<Any>) -> ?
}
What about the return type ?
Since the method begin will encapsulate the “entire” logic, it should return our parsed object(s) and also an Error type, then how about returning a tuple:
func begin(forResponse response: DataResponse<Any>) -> (value : Any?, error : Error?)At this moment, we will use the type of the returned parsed object(s) as Any.
If you already noticed the need for associatedtype you are correct, we will handle this feature later
If begin will return the above tuple then obviously parseData will return the exact same tuple because begin is the entry point and parseData is the exit point, thus, we will define typealias:
typealias ReturnedValueErrorTuple = (value : Any?, error : Error?)Two more types to resolve, parseData signature parameter and the validateData returned type. As discussed earlier, validateData will parse the JSON by checking custom specific keys that represent the server response, for example:
{
"status": true,
"data": {
// Some data to parse...
}
}In this example, we will want to check what is the status key value is, if it’s true then we will parse the JSON from the data key giving us the inner JSON that is ready to be parsed to concrete object(s), thus, it could return anything from a Dictionary type to an Array type so for now, Any will be a good choice.
What about if the status value is false ? we will want to extract the error message to show the user, for example:
{
"status": false,
"statusText": "The machines are digging and your data is doomed"
}So in addition to the Any type that represent the inner JSON, we will also need to return an Error type that will represent the reason why things got screwed up. Sounds like another tuple that will be represented by another typealias:
typealias ValueErrorTuple = (value : Any?, error : Error?)Those with quick perception already noticed that if the inner JSON is represented as Any type thus, parseData signature parameter should also be Any.
Note: validateData returns object of type Any thus, parseData should receive it

Finally, our new protocol:
Notice the new addition: able suffix in the protocol name; Parseable who used to be ParseProtocol — it’s because it has a new implementation:
The new implementation is the first of the 3 methods we mentioned above.
Method begin, encapsulates a concentrated logic that will never have to change.
At this point, we have a working parse protocol with a default implementation that:
- Validates the data
- Given no error, it parse the data and return the parsed object(s)
- Or, returns the error
Which means that if now, I want to create a parser for my Feed scene I will have to implement the Parseable protocol and implement the methods:
- validateData
- parseData
Thats it.
This means that from this point and through your whole project, every time you will need to parse new objects the only thing you will have to do is create a new object that implements Parseable protocol
If you made it this far you deserve an example
Second step — Creating a parseable object:
For the sake of the example let’s imagine we have a FeedViewController that contains a table view, the table view, present Feed type models. The JSON structure is the same as I’ve mentioned above.
Let’s create our concrete FeedArrayParser:
Side Note: The force casting I am doing here is defiantly not safe and of course dangerous — Please avoid that by conditional binding
Pay attention to line 10, it returns our inner JSON that parseData receives and will eventually create our object(s). The rest of the code inside method validateData should basically create errors for us.
What did we achieve here:
- We decoupled the Feed model from the parsing logic — also achieving SRP
- Everything that is parsing related is divided into two methods:
validateData — which validates the data (lines 2–21)
parseData — which parse and creates our custom object(s) (lines 23–34) - More to come…
Third step — Using the parseable object
The usage of Parseable object may be quite advanced
The main usage of Parseable object is based on injecting Parseable concrete instance to an asynchronous (escaping closure) generic method that has type constrain. Confused ? Good! Let’s see an example, method signature will look like this:
Let’s break it down:
- The method is generic with type constraint to our Parseable type — it means you can only inject Parseable concrete instances for the parameter name: parser.
- First parameter is our Parseable concrete instance type — because someone need to invoke the begin method.
- Second parameter is our escaping closure which is the tuple from our Parseable protocol — ReturnedValueErrorTuple
Implementing the method:
A sweet outcome is that lines 19 & 20 are written once and will never be written again.
It means that every time we will need something from our server, eventually we will invoke requestParseableData that will do the request for us and will return back the resultBlock. For example, if we will need another server request: fetchUserData, will invoke (of course) requestParseableData.That’s it. (Reminds me of SoC…)
No need to care about the method begin or when does the Parseable instance will end his life time. We know what will happen and when. Always.

Forth step — Consuming the generic method
We will create a data controller struct that will hold our array and a method that will invoke our AWESOME fetchFeedObjects method. Most importantly, we will now inject the instance of our Parseable object (FeedArrayParser) into the method parameter:
It looks pretty cool but take a look at line 7, we are force casting to [Feed] and broke the type system — lets improve that!
Last step — Improving Parseable
Making Parseable even more generic & dynamic
Defaulting the validateData method
We parsed our Feed models and we are good to go for our (imaginable) next scene, Our next scene contains another model type which is Video.
What do we need to do now:
- Create a struct Video that conforms to Parseable.
- Implement validateData — Wait what ?
- Implement parseData
As long as we will invoke methods for our default server URI, validateData will always have the same logic. You’re thinking what I am thinking ? Good!
Let’s default validateData:
What did we do (and achieve):
- Using POP, we created another protocol: JSONParseable that extends Parseable
- We added to it a default implementation: the method validateData
- From now on, every time we will need our default validateData logic, we will just need to implement JSONParseable (and not Parseable).
Our new (and awesome) FeedArrayParser struct:
FeedArrayParser implements JSONParseable, leaving him with a simple implementation which is the parsing logic.
Defining generic types for the return and response type
If you remember, I mentioned something about associatedtypes.
Most of the mobile apps usually have 1 server they communicate with, it means that our protocol JSONParseable will be sufficient.
What about if our app communicates with Facebook for SSO and of course, we need to parse the Facebook user for profile image, age etc.
In addition, what if your app actually have more then 1 server it communicates with ?
It sounds like we have more then 1 type for the response and of course the return type.
In these situations we usually use associatedtype, we actually tell the compiler “Don’t worry about the type bro, it will be determined later”.
Using an associatedtype inside a protocol is also know as PAT (Protocol with associatedtype).
“The actual type to use for that associated type isn’t specified until the protocol is adopted” — Apple documentation
Let’s take a look at our new and final version of Parseable:
- As discussed, we added 2 associatedtypes: returnedType & responseType
- We updated the typealias returnedTypeErrorTuple value parameter with our brand new type returnedType
- Signature for methods begin and validateData updated with their new parameter type responseType
Final round →
Let’s see our (final) cascade of changes:
We updated the JSONParseable with our new associatedtype which is DataResponse<Any> from Alamofire:
Yes, we defined our associatedtype inside our protocol. How cool is that ?
Finally, we will update our FeedArrayParser with his new associatedtype:
and finally, our requestParseableData method:
Notice the change in line 10, also the side note (again..).
Let’s take a look the change in the consuming part:
Unlike the cast we made earlier to [Feed] we now know exactly its type as it was defined in the FeedParserArray. We just need to unwrap it :)
Look at that generic awesomeness…

Now, in order to create different Parseable object with a different logic regarding validateData, we will simply implement Parseable and write our own validateData method using our associatedtypes for example: Facebook or different server request.

For those who prefer it the UML way:

In conclusion:
- By implementing Parseable protocol
- Creating async methods with constraint type <T : Parseable>
- Not forgetting that all async methods at the end, lead to the same requestParseableData which initiate the begin method
- We can inject our concrete Parseable instance into the async method
This architecture which is based on POP, is really powerful and most importantly, robust.
There are many ways that one can parse a JSON, I am not here to tell you that the POP way is the best option but it is certainly a powerful choice we should pay attention too.

If you have any question/comment/enlightenment or anything related I’d be happy to discuss it with you on Twitter or even here at the comments section.
Don’t hesitate :)
