Stork is a lightweight library focused on making the flight from JSON to Types as smooth as possible. Stork believes in simplicity, explicitness, and control.
Based on functional programming principles and mildly inspired in Aeson, Stork is the middle sweet between JSON parsers such as Argo - full-fledged but requiring extra dependencies and too functional for some - and other parsers that require your types to be mutable, to throw on init
, or that take the control away from you.
To go from JSON to types, all you need to do is to state what fields you want to parse. Stork infers their type and parses them for you. To make that possible, your types must follow the FromJson
protocol.
protocol FromJson {
static func from(value: JsonValue) -> Self?
}
In practice, this means that for a type to be parseable from JSON, it needs to provide a way of being constructed from a JsonValue:
string
, number
, bool
, JSON
, or [JsonValue
].
At compile-time, Storks requires the types you want to get from JSON to be FromJson
compliant. Otherwise, you encounter the following compile error message on Xcode:
Generic parameter 'T' could not be infered
Say that we want to retrieve values of type User
from some JSON input, where User
and its nested types are defined as follows:
struct User {
let id: Int
let name: String
let email: String?
let country: Country?
let subscription: Subscription
let favouriteSongs: [Song]
}
enum Subscription: String {
case free
case bronze
case silver
case gold
}
enum Country: String {
case netherlands
case portugal
}
struct Song: Equatable {
let name: String
let band: String
}
With Stork, to go from JSON to this model all we need to do is to have these types complying to our FromJson
protocol.
extension User: FromJson {
static func from(value: JsonValue) -> User? {
return value.ifObject { json in
User(
id: try json .! "id",
name: try json .! "name",
email: json .? "email",
country: json .? "country",
subscription: try json .! "subscription",
favouriteSongs: (json ..? "favouriteSongs") ?? []
)
}
}
}
// That's all you need for String/Int RawRepresentable Enums!
extension Subscription: FromJson {}
// Or you get to say how it's done!
// In this case, the country in JSON is short-coded and
// thus needs to be translated to the right Country case.
extension Country: FromJson {
static func from(value: JsonValue) -> Country? {
return value.ifString { str in
switch str {
case "nl": return .netherlands
case "pt": return .portugal
default: return nil
}
}
}
}
extension Song: FromJson {
static func from(value: JsonValue) -> Song? {
return value.ifObject { json in
Song(
name: try json .! "name",
band: try json .! "band"
)
}
}
}
Now that we have everything, let's get Stork to deliver that baby:
// Single user
let maybeUser: User? = User.from(json: userJSON)
// Array of users
let users: [User] = [User].from(jsonArray: usersJSON)
See more, unit-tested examples at the Examples directory
You can add Stork as a dependency to your project via the following ways.
- To add Stork to your Xcode project using CocoaPods, add this line to your
Podfile
:
pod 'StorkEgg', '0.2.1'
Note: The pod name is StorkEgg
since Stork
was already taken.
- Then let CocoaPods fetch and install it for you:
pod install
- Finally, build your project and import Stork:
import Stork
# Add Stork as a git submodule to your repository
git submodule add [email protected]:NunoAlexandre/stork.git
# Get the most updated version of Stork
git submodule update --remote
Read more about Git Submodules here.
I plan to support Carthage
and the Swift Package Manager
.
Help is rather appreciated!