{"id":18801225,"url":"https://github.com/ptsochantaris/trailer-json","last_synced_at":"2025-04-13T17:32:00.815Z","repository":{"id":179542997,"uuid":"663660169","full_name":"ptsochantaris/trailer-json","owner":"ptsochantaris","description":"A feather-weight JSON decoder in Swift","archived":false,"fork":false,"pushed_at":"2024-11-05T19:19:30.000Z","size":602,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-27T08:58:15.259Z","etag":null,"topics":["ios","json","macos","performance","swift","watchos"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ptsochantaris.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ptsochantaris"}},"created_at":"2023-07-07T20:17:01.000Z","updated_at":"2024-10-20T00:42:48.000Z","dependencies_parsed_at":"2024-11-07T22:26:04.070Z","dependency_job_id":"e4f7509a-c22a-4545-b702-347143a8665d","html_url":"https://github.com/ptsochantaris/trailer-json","commit_stats":null,"previous_names":["ptsochantaris/trailer-json"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ptsochantaris%2Ftrailer-json","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ptsochantaris%2Ftrailer-json/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ptsochantaris%2Ftrailer-json/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ptsochantaris%2Ftrailer-json/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ptsochantaris","download_url":"https://codeload.github.com/ptsochantaris/trailer-json/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248688575,"owners_count":21145765,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","json","macos","performance","swift","watchos"],"created_at":"2024-11-07T22:22:55.819Z","updated_at":"2025-04-13T17:31:55.800Z","avatar_url":"https://github.com/ptsochantaris.png","language":"Swift","funding_links":["https://github.com/sponsors/ptsochantaris"],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"https://ptsochantaris.github.io/trailer/TrailerJsonLogo.webp\" alt=\"Logo\" width=256 align=\"right\"\u003e\n\n# TrailerJson\n\nA feather-weight JSON decoder in Swift with no dependencies. Is is roughly based on a version of Swift.org's open source replacement for the Apple JSONSerialisation framework.\n\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fptsochantaris%2Ftrailer-json%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/ptsochantaris/trailer-json) [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fptsochantaris%2Ftrailer-json%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/ptsochantaris/trailer-json)\n\nCurrently used in\n- [Trailer](https://github.com/ptsochantaris/trailer)\n- [Trailer-CLI](https://github.com/ptsochantaris/trailer-cli)\n- Heavily tested and used in production with GitHub JSON v3 and v4 API payloads.\n\nDetailed docs [can be found here](https://swiftpackageindex.com/ptsochantaris/trailer-json/documentation)\n\n### The parsers\nThere are two parsers in this package:\n- `TrailerJson` will parse the entire data blob in one go, producing a dictionary much like JSONSerialization does.\n- `TypedJson` will quickly scan the data blob and provide results of type `Entry`, which have typed access (`asInt`, `asFloat`, `asBool`, `asString`, etc) and parses that data only when accessed.\n\n### Compared to JSONSerialisation (when running optimised)\nThe `TrailerJson` parser performs almost equivalently _BUT!_ the results are all native Swift types, so using those results incurs no bridging or copying costs, which is a major performance bonus.\n\nThe `TypedJson` parser is much faster, and ideal if you are only accessing a subset of the JSON data. It also makes it possible to parallelise the subsequent parsing in threads if needed.\n\n### Compared to Swift.org's version\nBecause it heavily trades features for decode-only performance, and that it returns native Swift types without the need to bridge them to ObjC for compatibility, it is by definition faster than the Swift.org version.\n\n### TL;DR\n👍 Ideal for parsing stable and known service API responses like GraphQL, or on embedded devices. Self contained with no setup overhead.\n\n👎 Bad at parsing/verifying potentially broken JSON, APIs which may suddenly include unexpected schema entries, or when you're better served by `Decodable` types.\n\n### Examples\n```\nlet url = URL(string: \"http://date.jsontest.com\")!\nlet data = try await URLSession.shared.data(from: url).0\n```\n\n```\n// TrailerJson - parse in one go to [String: Sendable]\nif let json = try data.asJsonObject(),      // parse as dictionary\n   let timeField = json[\"time\"],\n   let timeString = timeField as? String {\n   \n    print(\"The time is\", timeString)\n}\n```\n\n```\n// TypedJson - scan the data and only parse 'time' as a String\nif let json = try data.asTypedJson(),         // scan data\n   let timeField = try? json[\"time\"],\n   let timeString = try? timeField.asString { // parse field\n   \n    print(\"The time is\", timeString)\n}\n```\n\nTrailerJson works directly with raw bytes so it can accept data from any type that exposes a raw byte buffer, such as NIO's ByteBuffer, without expensive casting or copies in-between:\n\n```\nlet byteBuffer: ByteBuffer = ...\n```\n\n```\n// TrailerJson\nlet jsonArray = try byteBuffer.withVeryUnsafeBytes { \n    try TrailerJson.parse(bytes: $0) as? [Sendable]\n}\nlet number = jsonArray[1] as? Int\nprint(number)\n```\n\n```        \n// TypedJson\nlet jsonArray = try byteBuffer.withVeryUnsafeBytes { \n    try TypedJson.parse(bytes: $0)\n}\nlet number = try jsonArray[1].asInt\nprint(number)\n```\n\n```        \n// TypedJson - using bytesNoCopy, lazy parsing (max performance, but with caveats!)\nlet number = try byteBuffer.withVeryUnsafeBytes { \n\n    // jsonArray and any Entry from it must not be accessed outside the closure \n    let jsonArray = try TypedJson.parse(bytesNoCopy: $0)\n\n    // `secondEntry` reads from the original bytes, so it can't escape \n    let secondEntry = try jsonArray[1]\n\n    // but parsed values can escape\n    return try secondEntry.asInt\n}\nprint(number)        \n```\n\nIf you need to pass a TypedJson entry into a method that needs an untyped dictionary, you can eagerly parse a chunk by using the `parse` method - but beware that this can be slow for large sets of data, so it is best used for very specific cases!\n\n```\n// TypedJson - eager parsing (slowest performance)\nlet numberArray = try byteBuffer.withVeryUnsafeBytes { \n\n    // numbers and any Entry from it must not be accessed outside the closure \n    let numbers = try TypedJson.parse(bytes: $0)\n\n    // but parsed value can escape - note that parsing the whole document would be \n    // very slow, so for cases like these the `TrailerJson` parser is 10x faster!\n    return try numbers.parsed as! [Int]\n}\nlet number = numberArray[1]\nprint(number)        \n```\n\n### Notes\n- Supports UTF8 JSON data only\n- Uses native Swift data types in the results, no bridging overheads\n- null objects, fields, or array entries are thrown away, they are not kept\n- Floating point numbers are parsed as Float (i.e. not Double)\n- Does not support exponent numbers, only integers and floats\n- Does little to error-correct if the JSON feed isn't to spec\n\n## License\nCopyright (c) 2023-2024 Paul Tsochantaris. [Licensed under Apache License v2.0 with Runtime Library Exception](https://www.apache.org/licenses/LICENSE-2.0.html), as per the [open source material it is based on](https://github.com/apple/swift-corelibs-foundation/blob/bafd3d0f800397a15a3d092979ee7e788082feee/Sources/Foundation/JSONSerialization.swift)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fptsochantaris%2Ftrailer-json","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fptsochantaris%2Ftrailer-json","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fptsochantaris%2Ftrailer-json/lists"}