mirror of
https://github.com/encounter/JSONAPI.git
synced 2026-03-30 11:18:38 -07:00
+1
-1
@@ -16,7 +16,7 @@ Pod::Spec.new do |spec|
|
||||
#
|
||||
|
||||
spec.name = "JSONAPI"
|
||||
spec.version = "0.31.1"
|
||||
spec.version = "1.0.0"
|
||||
spec.summary = "Swift Codable JSON API framework."
|
||||
|
||||
# This description is used to generate tags and improve search results.
|
||||
|
||||
@@ -5,7 +5,7 @@ A Swift package for encoding to- and decoding from **JSON API** compliant reques
|
||||
|
||||
See the JSON API Spec here: https://jsonapi.org/format/
|
||||
|
||||
:warning: Although I find the type-safety of this framework appealing, the Swift compiler currently has enough trouble with it that it can become difficult to reason about errors produced by small typos. Similarly, auto-complete fails to provide reasonable suggestions much of the time. If you get the code right, everything compiles, otherwise it can suck to figure out what is wrong. This is mostly a concern when creating resource objects in-code (servers and test suites must do this). Writing a client that uses this framework to ingest JSON API Compliant API responses is much less painful. :warning:
|
||||
:warning: This library provides well-tested type safety when working with JSON:API 1.0, however the Swift compiler can sometimes have difficulty tracking down small typos when initializing `ResourceObjects`. Once the code is written correctly, it will compile, but tracking down the source of programmer errors can be an annoyance. This is mostly a concern when creating resource objects in-code (servers and test cases must do this). Writing a client that uses this framework to ingest JSON API Compliant API responses is much less painful. :warning:
|
||||
|
||||
## Table of Contents
|
||||
<!-- TOC depthFrom:1 depthTo:6 withLinks:1 updateOnSave:1 orderedList:0 -->
|
||||
@@ -109,52 +109,34 @@ Note that Playground support for importing non-system Frameworks is still a bit
|
||||
|
||||
### JSON:API
|
||||
#### Document
|
||||
- `data`
|
||||
- [x] Encoding/Decoding
|
||||
- `included`
|
||||
- [x] Encoding/Decoding
|
||||
- `errors`
|
||||
- [x] Encoding/Decoding
|
||||
- `meta`
|
||||
- [x] Encoding/Decoding
|
||||
- `jsonapi` (i.e. API Information)
|
||||
- [x] Encoding/Decoding
|
||||
- `links`
|
||||
- [x] Encoding/Decoding
|
||||
- [x] `data`
|
||||
- [x] `included`
|
||||
- [x] `errors`
|
||||
- [x] `meta`
|
||||
- [x] `jsonapi` (i.e. API Information)
|
||||
- [x] `links`
|
||||
|
||||
#### Resource Object
|
||||
- `id`
|
||||
- [x] Encoding/Decoding
|
||||
- `type`
|
||||
- [x] Encoding/Decoding
|
||||
- `attributes`
|
||||
- [x] Encoding/Decoding
|
||||
- `relationships`
|
||||
- [x] Encoding/Decoding
|
||||
- `links`
|
||||
- [x] Encoding/Decoding
|
||||
- `meta`
|
||||
- [x] Encoding/Decoding
|
||||
- [x] `id`
|
||||
- [x] `type`
|
||||
- [x] `attributes`
|
||||
- [x] `relationships`
|
||||
- [x] `links`
|
||||
- [x] `meta`
|
||||
|
||||
#### Relationship Object
|
||||
- `data`
|
||||
- [x] Encoding/Decoding
|
||||
- `links`
|
||||
- [x] Encoding/Decoding
|
||||
- `meta`
|
||||
- [x] Encoding/Decoding
|
||||
- [x] `data`
|
||||
- [x] `links`
|
||||
- [x] `meta`
|
||||
|
||||
#### Links Object
|
||||
- `href`
|
||||
- [x] Encoding/Decoding
|
||||
- `meta`
|
||||
- [x] Encoding/Decoding
|
||||
- [x] `href`
|
||||
- [x] `meta`
|
||||
|
||||
### Misc
|
||||
- [x] Support transforms on `Attributes` values (e.g. to support different representations of `Date`)
|
||||
- [x] Support validation on `Attributes`.
|
||||
- [x] Support sparse fieldsets (encoding only). A client can likely just define a new model to represent a sparse population of another model in a very specific use case. On the server side, sparse fieldsets of Resource Objects can be encoded without creating one model for every possible sparse fieldset.
|
||||
- [ ] Create more descriptive errors that are easier to use for troubleshooting.
|
||||
- [x] Support sparse fieldsets (encoding only). A client can likely just define a new model to represent a sparse population of another model in a very specific use case for decoding purposes. On the server side, sparse fieldsets of Resource Objects can be encoded without creating one model for every possible sparse fieldset.
|
||||
|
||||
### Testing
|
||||
#### Resource Object Validator
|
||||
@@ -163,6 +145,8 @@ Note that Playground support for importing non-system Frameworks is still a bit
|
||||
- [x] Only allow `ToManyRelationship` and `ToOneRelationship` within `Relationships` struct.
|
||||
|
||||
### Potential Improvements
|
||||
These ideas could be implemented in future versions.
|
||||
|
||||
- [ ] (Maybe) Use `KeyPath` to specify `Includes` thus creating type safety around the relationship between a primary resource type and the types of included resources.
|
||||
- [ ] (Maybe) Replace `SingleResourceBody` and `ManyResourceBody` with support at the `Document` level to just interpret `PrimaryResource`, `PrimaryResource?`, or `[PrimaryResource]` as the same decoding/encoding strategies.
|
||||
- [ ] Support sideposting. JSONAPI spec might become opinionated in the future (https://github.com/json-api/json-api/pull/1197, https://github.com/json-api/json-api/issues/1215, https://github.com/json-api/json-api/issues/1216) but there is also an existing implementation to consider (https://jsonapi-suite.github.io/jsonapi_suite/ruby/writes/nested-writes). At this time, any sidepost implementation would be an awesome tertiary library to be used alongside the primary JSONAPI library. Maybe `JSONAPISideloading`.
|
||||
|
||||
@@ -53,7 +53,9 @@ public struct Document<PrimaryResourceBody: JSONAPI.EncodableResourceBody, MetaT
|
||||
case data(Data)
|
||||
|
||||
public struct Data: Equatable {
|
||||
/// The document's Primary Resource object(s)
|
||||
public let primary: PrimaryResourceBody
|
||||
/// The document's included objects
|
||||
public let includes: Includes<Include>
|
||||
public let meta: MetaType
|
||||
public let links: LinksType
|
||||
@@ -66,6 +68,8 @@ public struct Document<PrimaryResourceBody: JSONAPI.EncodableResourceBody, MetaT
|
||||
}
|
||||
}
|
||||
|
||||
/// `true` if the document represents one or more errors. `false` if the
|
||||
/// document represents JSON:API data and/or metadata.
|
||||
public var isError: Bool {
|
||||
guard case .errors = self else { return false }
|
||||
return true
|
||||
|
||||
@@ -9,6 +9,16 @@ import Poly
|
||||
|
||||
public typealias Include = EncodableJSONPoly
|
||||
|
||||
/// A structure holding zero or more included Resource Objects.
|
||||
/// The resources are accessed by their type using a subscript.
|
||||
///
|
||||
/// If you have
|
||||
///
|
||||
/// `let includes: Includes<Include2<Thing1, Thing2>> = ...`
|
||||
///
|
||||
/// then you can access all `Thing1` included resources with
|
||||
///
|
||||
/// `let includedThings = includes[Thing1.self]`
|
||||
public struct Includes<I: Include>: Encodable, Equatable {
|
||||
public static var none: Includes { return .init(values: []) }
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ public func +<R: Appendable>(_ left: R, right: R) -> R {
|
||||
return left.appending(right)
|
||||
}
|
||||
|
||||
/// A type allowing for a document body containing 1 primary resource.
|
||||
/// If the `Entity` specialization is an `Optional` type, the body can contain
|
||||
/// 0 or 1 primary resources.
|
||||
public struct SingleResourceBody<Entity: JSONAPI.OptionalEncodablePrimaryResource>: EncodableResourceBody {
|
||||
public let value: Entity
|
||||
|
||||
@@ -56,6 +59,7 @@ public struct SingleResourceBody<Entity: JSONAPI.OptionalEncodablePrimaryResourc
|
||||
}
|
||||
}
|
||||
|
||||
/// A type allowing for a document body containing 0 or more primary resources.
|
||||
public struct ManyResourceBody<Entity: JSONAPI.EncodablePrimaryResource>: EncodableResourceBody, Appendable {
|
||||
public let values: [Entity]
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ public protocol CreatableRawIdType: RawIdType {
|
||||
|
||||
extension String: RawIdType {}
|
||||
|
||||
/// A type that can be used as the `MaybeRawId` for a `ResourceObject` that does not
|
||||
/// have an Id (most likely because it was created by a client and the server will be responsible
|
||||
/// for assigning it an Id).
|
||||
public struct Unidentified: MaybeRawId, CustomStringConvertible {
|
||||
public init() {}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// Created by Mathew Polzin on 8/4/19.
|
||||
//
|
||||
|
||||
public class SparseFieldEncoder<SparseKey: CodingKey & Equatable>: Encoder {
|
||||
class SparseFieldEncoder<SparseKey: CodingKey & Equatable>: Encoder {
|
||||
private let wrappedEncoder: Encoder
|
||||
private let allowedKeys: [SparseKey]
|
||||
|
||||
@@ -37,7 +37,7 @@ public class SparseFieldEncoder<SparseKey: CodingKey & Equatable>: Encoder {
|
||||
}
|
||||
}
|
||||
|
||||
public struct SparseFieldKeyedEncodingContainer<Key, SparseKey>: KeyedEncodingContainerProtocol where SparseKey: CodingKey, SparseKey: Equatable, Key: CodingKey {
|
||||
struct SparseFieldKeyedEncodingContainer<Key, SparseKey>: KeyedEncodingContainerProtocol where SparseKey: CodingKey, SparseKey: Equatable, Key: CodingKey {
|
||||
private var wrappedContainer: KeyedEncodingContainer<Key>
|
||||
private let allowedKeys: [SparseKey]
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import JSONAPI
|
||||
@testable import JSONAPI
|
||||
import Foundation
|
||||
|
||||
class SparseFieldEncoderTests: XCTestCase {
|
||||
|
||||
Reference in New Issue
Block a user