You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+8-8Lines changed: 8 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -27,7 +27,7 @@ A library for decoding and encoding json, built on top of @pointfreeco's [Parsin
27
27
28
28
## Introduction
29
29
30
-
As mentioned above, this library is built using the [Parsing](https://github.com/pointfreeco/swift-parsing) library, which is a library that provides a consistent story for writing _parsing_ code in Swift, that is, code that turns some _unstructured data_ into more _structured data_. You do that by constructing _parsers_ that are generic over both the (unstructured) _input_ and the (structued) _output_. What's really great is the fact the these parsers can be made _invertible_ (or bidirectional), meaning thay can also turn structured data _back_ into unstructed data, referred to as _printing_.
30
+
As mentioned above, this library is built using the [Parsing](https://github.com/pointfreeco/swift-parsing) library, which is a library that provides a consistent story for writing _parsing_ code in Swift, that is, code that turns some _unstructured data_ into more _structured data_. You do that by constructing _parsers_ that are generic over both the (unstructured) _input_ and the (structued) _output_. What's really great is the fact the these parsers can be made _invertible_ (or bidirectional), meaning they can also turn structured data _back_ into unstructured data, referred to as _printing_.
31
31
32
32
The *JSONParsing* library provides predefined parsers tuned specifically for when the _input is json_, giving you a convenient way of writing parsers capable of parsing (decoding) and printing (encoding) json. This style of dealing with json has a number of benefits compared to the *Codable* abstraction. More about that in the [Motivation](#motivation---why-not-use-codable) section.
33
33
@@ -145,7 +145,7 @@ Or perhaps:
145
145
"205,99,138"
146
146
```
147
147
148
-
The truth is, both representations are reasonable (as well as many other possibilities), and it's possible that you might have one API endpoint returning RGB colors in the first format, and another in the second format. But when using Codable, you would have to choose one of the formats to be the one used for the `RGBColor` type. To handle both variants, you would have to define two separate types, something like `RGBColorWithObjectRepresentaion` and `RGBColorWithStringRepresentation`, and conform both of them to `Codable`, with the different decoding/encoding strategies.
148
+
The truth is, both representations are reasonable (as well as many other possibilities), and it's possible that you might have one API endpoint returning RGB colors in the first format, and another in the second format. But when using Codable, you would have to choose one of the formats to be the one used for the `RGBColor` type. To handle both variants, you would have to define two separate types, something like `RGBColorWithObjectRepresentation` and `RGBColorWithStringRepresentation`, and conform both of them to `Codable`, with the different decoding/encoding strategies.
149
149
150
150
Using the *JSONParsing* library, you can easily just create two separate parsers, one for each alternative:
Codable has the really cool feature of being able to automatically sythesize the decoding and encoding implementations for Swift types, thanks to integration with the Swift compiler. Unfortunately, in practice, the automatically synthesized implementations will often not be correct for your usecase, because it assumes that your json data and your Swift data types _exactly_ match each other in structure. This will often not be the case, for various reasons. First, you might be dealing with JSON APIs that you don't own yourself and therefore might deliver data in a format that isn't ideal to your usecase. But even if you do own the API code, it might be used by multiple platforms, which means you can't tailor it specifically to work perfectly with your Swift code. Also, Swift has some features, such as enums, that simply _can't_ be expressed equivalently in json.
287
+
Codable has the really cool feature of being able to automatically synthesize the decoding and encoding implementations for Swift types, thanks to integration with the Swift compiler. Unfortunately, in practice, the automatically synthesized implementations will often not be correct for your use case, because it assumes that your json data and your Swift data types _exactly_ match each other in structure. This will often not be the case, for various reasons. First, you might be dealing with JSON APIs that you don't own yourself and therefore might deliver data in a format that isn't ideal to your use case. But even if you do own the API code, it might be used by multiple platforms, which means you can't tailor it specifically to work perfectly with your Swift code. Also, Swift has some features, such as enums, that simply _can't_ be expressed equivalently in json.
288
288
289
289
So in practice, when using Codable, you will often have to implement the decoding and encoding logic manually. And the problem in that situation, is that they have to be implemented _separately_. This means that, whenever the expected json format changes in any way, you have to remember to update both the `init(from:)` (decoding) and the `encode(to:)` (encoding) implementations accordingly.
290
290
291
291
With *JSONParsing* on the other hand, you can write a single json parser that can take care of both the decoding and the encoding (as was shown in the [Quick start](#quick-start) section). What this means is that you are guaranteed to always have the two transformations kept in sync as your json API evolves.
292
292
293
293
### Custom String parsing
294
294
295
-
Recall how we previously defined a json parser for the `RGBColor` type, where the json representation was a comma seperated string. It looked like this:
295
+
Recall how we previously defined a json parser for the `RGBColor` type, where the json representation was a comma separated string. It looked like this:
296
296
297
297
```swift
298
298
extensionRGBColor {
@@ -539,7 +539,7 @@ public enum JSONValue: Equatable {
539
539
540
540
So when we call the `decode(_:)` and `encode(_:)` methods on the parsers, the decoding and encoding happens in two steps: the json data is transformed to/from the `JSONValue` type, and the `JSONValue` type is in turn transformed to/from the result type using the `Parser.parse`/`ParserPrinter.print` methods.
541
541
542
-
The primary usecase for the `JSONValue` type is just to act as this middle layer, to simplify the implementations of the various json parsers that ship with the library. However, it can actually be useful on its own. For instance, you might have code like this today:
542
+
The primary use case for the `JSONValue` type is just to act as this middle layer, to simplify the implementations of the various json parsers that ship with the library. However, it can actually be useful on its own. For instance, you might have code like this today:
543
543
544
544
```swift
545
545
let json: [String: Any] = [
@@ -591,7 +591,7 @@ let json: [String: Any] = [
591
591
592
592
This library ships with a number of json parsers, that can be composed together to deal with more complex json structures. As mentioned in the previous section, they all take values of the custom type `JSONValue` as input, so when using the `parse`/`print` methods, they convert to/from that type.
593
593
594
-
When you want to use them to decode/encode json _data_ (which is likely to be the most common usecase) you just use the `decode`/`encode` methods defined on them instead, which does the converting to from data for you.
594
+
When you want to use them to decode/encode json _data_ (which is likely to be the most common use case) you just use the `decode`/`encode` methods defined on them instead, which does the converting to from data for you.
Instead of treating an abscent value as `nil`, you can optionally provide a `default` value, to use as a fallback:
1064
+
Instead of treating an absent value as `nil`, you can optionally provide a `default` value, to use as a fallback:
1065
1065
1066
1066
```diff
1067
1067
struct Person {
@@ -1141,7 +1141,7 @@ extension Person {
1141
1141
1142
1142
### Integrating *JSONParsing* into *Codable* code
1143
1143
1144
-
So that's one part of the equation, when it comes to integration with Codable. But what about the other way around? What if we actually _do_ have a json parser capable of decoding `Movie`s, and we're using Codable for the `Person` type instead. For that usecase, the library comes with overloads of the various methods on the decoding/encoding containers, that take a json parser as input. Let's see what it looks like to use this, by conforming the `Person` type to both the `Decodable` and the `Encodable` protocol:
1144
+
So that's one part of the equation, when it comes to integration with Codable. But what about the other way around? What if we actually _do_ have a json parser capable of decoding `Movie`s, and we're using Codable for the `Person` type instead. For that use case, the library comes with overloads of the various methods on the decoding/encoding containers, that take a json parser as input. Let's see what it looks like to use this, by conforming the `Person` type to both the `Decodable` and the `Encodable` protocol:
0 commit comments