JSON From Swift Types
When you end up dealing with nested data types, you’re only away from converting those data types to JSON1. We can pretty easily add some data to our custom types allowing them to automatically be serialized to JSON.
The Data Model
We’re going to stay in Stripe Data Model Land for our JSON conversion, but we’re going to use a new StripeMiniCard
type with only five properties defined. The reduced property count will make following along easier.
The Scaffolding
The one trick to make the entire to-JSON conversion process work is one tiny protocol:
1 2 3 4 |
|
The protocol ReadableAsJson
says: any type implementing the protocol must define two methods. jsonName
returns the name of the field for the type and jsonValue
returns the value of the field.
The Data Type Implementations
First, we add ReadableAsJson
to our base class StripeIdentifier
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Since every subclass of StripeIdentifier
stores data in id
, subclasses only need to override
the jsonName
function to set their proper field name.
Speaking of identifiers, let’s jump into StripeCardId
:
1 2 3 4 5 6 7 8 |
|
Note the use of the keyword override
when we actually override a parent class function in a subclass.
Now let’s try some enums:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
Notice how each enum has default raw value strings. We can just return toRaw()
as our JSON value.
Moving on to two quick structs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Pretty simple. Each struct provides a name and JSON string value so they conform to the ReadableAsJson
protocol.
Now let’s try an enum with no default raw values:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Since StripeObjectType
had no raw values, we switch
on ourself and return the proper String
. The decision to put the values in a switch
inside jsonValue
is a pure design choice. We could have just as easily set the strings as default raw values like we did with StripeCardBrand
or StripeCheckResult
.
Creating JSON From Instance Properties
All property types have been conformed to our ReadableAsJson
protocol, so it’s time to tie it all together.
First, we import Foundation
so we can access the Cocoa JSON serializer:
1 |
|
The NSJSONSerialization
class provides a very simple way to generate JSON from a Swift dictionary type. All we need to do now is iterate over all properties of our StripeMiniCard
, read JSON field name and value, then store the name as a key in our Swift dictionary along with it’s value.
After the dictionary is created, we can call NSJSONSerialization.dataWithJSONObject()
to convert our dictionary to JSON.
Let’s define our StripeMiniCard
with toJson()
capability:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
Notice how the array evaluate
is defined as an array of ReadableAsJson
. We don’t care about the actual type of our array elements. All we care about is if each element implements our two JSON reading requirements.
After we populate our dictionary, we use built in libraries to convert the dictionary to JSON. But, the library returns an annoying NSData
, so we need to convert the NSData
back to an acceptable String
type (NSString
bridges to Swift String
, so there’s no casting or manual conversion required).
So what’s the final result?
1 2 3 4 5 |
|
From those tiny lines card.toJson()
printed:
1 2 |
|
…which is pretty darn good considering we just made up our entire data retrieval and JSON creation scheme out of nowhere.
Obviously the actual StripeCard
type has many more fields, but populating more fields using this method is just a matter of time and effort.
Also note how, by using custom types even for something simple like encapsulating only one String
(see: StripeFingerprint
), we are able to attach more metadata to our types than if we used raw String
or Int
types in isolation.
-
Plus, everybody knows if you’re a company, and you add
JSON
to your feature checklist, the company is immediately becomes worth $200 to $800 million more than before you added those four simple letters to your feature checklist.↩