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
JSONto 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.↩︎