swift-json
is a pure-Swift JSON parsing library designed for high-performance, high-throughput server-side applications. When compared using the test data captured.json
, swift-json
is nearly 7 times faster than Foundation.JSONDecoder
(see benchmark source code). This library is powered by swift-grammar
!
Importing this module will expose the following top-level symbol(s):
enum JSON
The JSON
module in swift-json
enables you to express JSON parsing tasks as constructive parsers. This makes the JSON
module very flexible without requiring much configuration from users who simply want to parse a JSON message from a remote peer.
To parse a complete JSON message, use its init(parsing:)
initializer, or for more flexibility, the JSON.Rule<Location>.Root
parsing rule:
import JSON
struct Decimal:Codable
{
let units:Int
let places:Int
}
struct Response:Codable
{
let success:Bool
let value:Decimal
}
let string:String =
"""
{"success":true,"value":0.1}
"""
let decoder:JSON = try .init(parsing: string.utf8)
let response:Response = try .init(from: decoder)
print(response)
$ swift run DecodingWithCodable
Response(success: true, value: Decimal(units: 1, places: 1))
The rule is called “Root
” because it will match only complete JSON messages (objects or arrays).
Like most swift-grammar
-based parsers, JSON.Rule
is generic over its input, which means you can parse directly from some Collection
of UInt8
.
swift-json
’s constructive parsing engine also allows you to get diagnostics for invalid JSON messages:
import Grammar
import JSON
let invalid:String =
"""
{"success":true,value:0.1}
"""
do
{
let _:JSON = try JSON.Rule<String.Index>.Root.parse(diagnosing: invalid.utf8)
}
catch let error as ParsingError<String.Index>
{
let annotated:String = error.annotate(source: invalid,
renderer: String.init(_:),
newline: \.isNewline)
print(annotated)
}
$ swift run ParsingDiagnostics
UnexpectedValueError: (no description available)
{"success":true,value:0.1}
^
note: while parsing pattern 'DoubleQuote'
{"success":true,value:0.1}
^
note: while parsing pattern 'StringLiteral'
{"success":true,value:0.1}
^
note: while parsing pattern '(Pad<Comma, Whitespace>, Item)'
{"success":true,value:0.1}
^~
note: while parsing pattern 'Object'
{"success":true,value:0.1}
^~~~~~~~~~~~~~~~~
note: while parsing pattern 'Root'
{"success":true,value:0.1}
^~~~~~~~~~~~~~~~~
You can be more selective about the form of the JSON you expect to receive by using one of the library’s subrules:
The JSON
module supports parsing arbitrary JSON fragments using the JSON.Rule<Location>.Value
rule.
The nature of constructive parsing also means it is straightforward to parse multiple concatenated JSON messages, as is commonly encountered when interfacing with streaming JSON APIs.
swift-json
as a dependencyTo use swift-json
in a project, add the following to your Package.swift
file:
let package = Package(
...
dependencies:
[
// other dependencies
.package(url: "https://github.com/kelvin13/swift-json", from: "0.4.0"),
],
targets:
[
.target(name: "example",
dependencies:
[
.product(name: "JSON", package: "swift-json"),
// other dependencies
]),
// other targets
]
)
swift-json
is DocC-compatible. However, its documentation is a lot more useful when built with a documentation engine like swift-biome
.
swift-json
uses the swift-package-catalog
plugin to gather its documentation.
Run the catalog
plugin command, and store its output in a file named Package.catalog
.
$ swift package catalog > Package.catalog
The catalog file must be named Package.catalog
; Biome parses it (and the Package.resolved
file generated by the Swift Package Manager) in order to find swift-json
’s symbolgraphs and DocC archives.
swift-biome
swift-biome
is a normal SPM package. There’s lots of ways to build it.
$ git clone [email protected]:kelvin13/swift-biome.git
$ git submodule update --init --recursive
$ cd swift-biome
$ swift build -c release
$ cd ..
Don’t forget the git submodule update
!
preview
serverswift-biome
includes an executable target called preview
. Pass it the path to the swift-json
repository (in this example, ..
), and it will start up a server on localhost:8080
.
$ cd swift-biome
$ .build/release/preview --swift 5.6.2 ..
The --swift 5.6.2
option specifies the version of the standard library that the Biome compiler should link against.
Note: if you run the
preview
tool from outside theswift-biome
repository, you will need to specify the path to theresources
(sub)module. For example, if you did notcd
intoswift-biome
, you would have to add the option--resources swift-biome/resources
.
Navigate to http://127.0.0.1:8080/reference/swift-json
in a browser to view the documentation. Make sure the scheme is http://
and not https://
.
link |
Stars: 47 |
Last commit: 1 week ago |
swift-json
v0.3.0 is finally here!
version 0.2 of swift-json
modeled objects (things written in curly braces {}
) as dictionaries of String
keys and JSON
values:
case array([Self])
case object([String: Self])
this is the most obvious representation for a JSON value, it’s convenient for many use cases, and it dovetails nicely with the JSON.array(_:)
enumeration case. however, this representation also comes with some functional and performance issues, so we have replaced this representation with a array-based [(key:String, value:JSON)]
representation. this matches APIs vended by Dictionary itself.
case object([(key:String, value:Self)])
to convert an object to a Dictionary
, use one of the as(_:uniquingKeysWith:)
methods on JSON
.
previously, users of swift-json
had to choose between a slow but ergonomic Decodable
-based API, and a fast but extremely verbose direct decoding API. swift-json
v0.3 comes with a much more ergonomic API for high-performance decoding.
to decode objects, you can now use the LintingDictionary
abstraction, and to decode arrays, you can now use swift-json
’s Array
extensions. in addition to being faster, using these decoding interfaces also gives better error diagnostics when decoding fails.
for an example of how to use LintingDictionary
, see its associated snippet.
RawRepresentable
convenience APIsswift-json
v0.3 comes with a handful of new convenience APIs for decoding RawRepresentable
types directly from JSON messages:
func `as`<StringCoded>(cases: StringCoded.Type) throws -> StringCoded
func `as`<CharacterCoded>(cases: CharacterCoded.Type) throws -> CharacterCoded
func `as`<ScalarCoded>(cases: ScalarCoded.Type) throws -> ScalarCoded
func `as`<IntegerCoded>(cases: IntegerCoded.Type) throws -> IntegerCoded
func `as`<UnsignedIntegerCoded>(cases: UnsignedIntegerCoded.Type) throws -> UnsignedIntegerCoded
swift-grammar
directlyversion 0.2 of swift-json
re-exported Grammar
’s entire API, and expected users to invoke swift-grammar
parsing rules directly. this was done to reduce the amount of “magic” in the parser, and guide users towards the lowest-overhead parsing configurations needed for their use case, which was important back when swift-json
was a closed-source library primarily used for fintech applications. however it also made for a very complex API that was hard to learn if you were not already familiar with how swift-grammar
works.
version 0.3 of swift-json
now comes with a simplified init(parsing:)
initializer, which takes UTF-8-encoded input, and just “does the right thing” by default.
ExpressibleBy_Literal
conformancesthe JSON
type now conforms to ExpressibleByArrayLiteral
,ExpressibleByBooleanLiteral
, ExpressibleByDictionaryLiteral
, ExpressibleByExtendedGraphemeClusterLiteral
, ExpressibleByStringLiteral
, and ExpressibleByUnicodeScalarLiteral
.
swift-json
supports swift 5.3 ... 5.8 nightly, and has official CI coverage for linux, macOS, iOS, watchOS, tvOS, and windows.
swift-json
has a fully-green build matrix on the swift package index.
we have expanded swift-json
’s documentation, and published it on swiftinit.
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics