diff --git a/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift b/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift index cbc2856..234294c 100644 --- a/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift +++ b/JSONAPI.playground/Pages/Usage.xcplaygroundpage/Contents.swift @@ -11,7 +11,7 @@ Please enjoy these examples, but allow me the forced casting and the lack of err // MARK: - Create a request or response body with one Dog in it let dogFromCode = try! Dog(name: "Buddy", owner: nil) -typealias SingleDogDocument = JSONAPI.Document, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError> +typealias SingleDogDocument = JSONAPI.Document, NoMetadata, NoLinks, NoIncludes, NoJSONAPIDescription, UnknownJSONAPIError> let singleDogDocument = SingleDogDocument(body: SingleResourceBody(entity: dogFromCode)) @@ -27,7 +27,7 @@ let dogs = try! [Dog(name: "Buddy", owner: personIds[0]), Dog(name: "Joy", owner let houses = [House(), House()] let people = try! [Person(id: personIds[0], name: ["Gary", "Doe"], favoriteColor: "Orange-Red", friends: [], dogs: [dogs[0], dogs[1]], home: houses[0]), Person(id: personIds[1], name: ["Elise", "Joy"], favoriteColor: "Red", friends: [], dogs: [dogs[2]], home: houses[1])] -typealias BatchPeopleDocument = JSONAPI.Document, NoMetadata, NoLinks, Include2, UnknownJSONAPIError> +typealias BatchPeopleDocument = JSONAPI.Document, NoMetadata, NoLinks, Include2, NoJSONAPIDescription, UnknownJSONAPIError> let includes = dogs.map { BatchPeopleDocument.Include($0) } + houses.map { BatchPeopleDocument.Include($0) } let batchPeopleDocument = BatchPeopleDocument(body: .init(entities: people), includes: .init(values: includes)) diff --git a/Sources/JSONAPI/Document/APIDescription.swift b/Sources/JSONAPI/Document/APIDescription.swift new file mode 100644 index 0000000..9a9875e --- /dev/null +++ b/Sources/JSONAPI/Document/APIDescription.swift @@ -0,0 +1,56 @@ +// +// APIDescription.swift +// JSONAPI +// +// Created by Mathew Polzin on 12/1/18. +// + +/// This is what the JSON API Spec calls the "JSON:API Object" +public protocol APIDescriptionType: Codable, Equatable { + associatedtype Meta +} + +/// This is what the JSON API Spec calls the "JSON:API Object" +public struct APIDescription: APIDescriptionType { + public let version: String? + public let meta: Meta +} + +public struct NoAPIDescription: APIDescriptionType, CustomStringConvertible { + public typealias Meta = NoMetadata + + public init() {} + + public static var none: NoAPIDescription { return .init() } + + public var description: String { return "No JSON:API Object" } +} + +extension APIDescription { + private enum CodingKeys: String, CodingKey { + case version + case meta + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + version = try container.decode(String?.self, forKey: .version) + + if let metaVal = NoMetadata() as? Meta { + meta = metaVal + } else { + meta = try container.decode(Meta.self, forKey: .meta) + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(version, forKey: .version) + + if Meta.self != NoMetadata.self { + try container.encode(meta, forKey: .meta) + } + } +} diff --git a/Sources/JSONAPI/Document/Document.swift b/Sources/JSONAPI/Document/Document.swift index 1949c29..c41be3c 100644 --- a/Sources/JSONAPI/Document/Document.swift +++ b/Sources/JSONAPI/Document/Document.swift @@ -10,9 +10,10 @@ public protocol JSONAPIDocument: Codable, Equatable { associatedtype MetaType: JSONAPI.Meta associatedtype LinksType: JSONAPI.Links associatedtype IncludeType: JSONAPI.Include + associatedtype APIDescription: APIDescriptionType associatedtype Error: JSONAPIError - typealias Body = Document.Body + typealias Body = Document.Body var body: Body { get } } @@ -24,11 +25,19 @@ public protocol JSONAPIDocument: Codable, Equatable { /// API uses snake case, you will want to use /// a conversion such as the one offerred by the /// Foundation JSONEncoder/Decoder: `KeyDecodingStrategy` -public struct Document: JSONAPIDocument { +public struct Document: JSONAPIDocument { public typealias Include = IncludeType + /// The JSON API Spec calls this the JSON:API Object. It contains version + /// and metadata information about the API itself. + public let apiDescription: APIDescription + + /// The Body of the Document. This body is either one or more errors + /// with links and metadata attempted to parse but not guaranteed or + /// it is a successful data struct containing all the primary and + /// included resources, the metadata, and the links that this + /// document type specifies. public let body: Body -// public let jsonApi: APIDescription? public enum Body: Equatable { case errors([Error], meta: MetaType?, links: LinksType?) @@ -91,54 +100,86 @@ public struct Document, meta: MetaType, links: LinksType) { + public init(apiDescription: APIDescription, body: PrimaryResourceBody, includes: Includes, meta: MetaType, links: LinksType) { self.body = .data(.init(primary: body, includes: includes, meta: meta, links: links)) + self.apiDescription = apiDescription } } extension Document where IncludeType == NoIncludes { - public init(body: PrimaryResourceBody, meta: MetaType, links: LinksType) { - self.body = .data(.init(primary: body, includes: .none, meta: meta, links: links)) + public init(apiDescription: APIDescription, body: PrimaryResourceBody, meta: MetaType, links: LinksType) { + self.init(apiDescription: apiDescription, body: body, includes: .none, meta: meta, links: links) } } extension Document where MetaType == NoMetadata { - public init(body: PrimaryResourceBody, includes: Includes, links: LinksType) { - self.body = .data(.init(primary: body, includes: includes, meta: .none, links: links)) + public init(apiDescription: APIDescription, body: PrimaryResourceBody, includes: Includes, links: LinksType) { + self.init(apiDescription: apiDescription, body: body, includes: includes, meta: .none, links: links) } } extension Document where LinksType == NoLinks { - public init(body: PrimaryResourceBody, includes: Includes, meta: MetaType) { - self.body = .data(.init(primary: body, includes: includes, meta: meta, links: .none)) + public init(apiDescription: APIDescription, body: PrimaryResourceBody, includes: Includes, meta: MetaType) { + self.init(apiDescription: apiDescription, body: body, includes: includes, meta: meta, links: .none) + } +} + +extension Document where APIDescription == NoAPIDescription { + public init(body: PrimaryResourceBody, includes: Includes, meta: MetaType, links: LinksType) { + self.init(apiDescription: .none, body: body, includes: includes, meta: meta, links: links) } } extension Document where IncludeType == NoIncludes, LinksType == NoLinks { - public init(body: PrimaryResourceBody, meta: MetaType) { - self.body = .data(.init(primary: body, includes: .none, meta: meta, links: .none)) + public init(apiDescription: APIDescription, body: PrimaryResourceBody, meta: MetaType) { + self.init(apiDescription: apiDescription, body: body, meta: meta, links: .none) } } extension Document where IncludeType == NoIncludes, MetaType == NoMetadata { - public init(body: PrimaryResourceBody, links: LinksType) { - self.body = .data(.init(primary: body, includes: .none, meta: .none, links: links)) + public init(apiDescription: APIDescription, body: PrimaryResourceBody, links: LinksType) { + self.init(apiDescription: apiDescription, body: body, meta: .none, links: links) + } +} + +extension Document where IncludeType == NoIncludes, APIDescription == NoAPIDescription { + public init(body: PrimaryResourceBody, meta: MetaType, links: LinksType) { + self.init(apiDescription: .none, body: body, meta: meta, links: links) } } extension Document where MetaType == NoMetadata, LinksType == NoLinks { - public init(body: PrimaryResourceBody, includes: Includes) { - self.body = .data(.init(primary: body, includes: includes, meta: .none, links: .none)) + public init(apiDescription: APIDescription, body: PrimaryResourceBody, includes: Includes) { + self.init(apiDescription: apiDescription, body: body, includes: includes, links: .none) + } +} + +extension Document where MetaType == NoMetadata, APIDescription == NoAPIDescription { + public init(body: PrimaryResourceBody, includes: Includes, links: LinksType) { + self.init(apiDescription: .none, body: body, includes: includes, links: links) } } extension Document where IncludeType == NoIncludes, MetaType == NoMetadata, LinksType == NoLinks { + public init(apiDescription: APIDescription, body: PrimaryResourceBody) { + self.init(apiDescription: apiDescription, body: body, includes: .none) + } +} + +extension Document where MetaType == NoMetadata, LinksType == NoLinks, APIDescription == NoAPIDescription { + public init(body: PrimaryResourceBody, includes: Includes) { + self.init(apiDescription: .none, body: body, includes: includes) + } +} + +extension Document where IncludeType == NoIncludes, MetaType == NoMetadata, LinksType == NoLinks, APIDescription == NoAPIDescription { public init(body: PrimaryResourceBody) { - self.body = .data(.init(primary: body, includes: .none, meta: .none, links: .none)) + self.init(apiDescription: .none, body: body) } } @@ -155,6 +196,12 @@ extension Document { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: RootCodingKeys.self) + if let noData = NoAPIDescription() as? APIDescription { + apiDescription = noData + } else { + apiDescription = try container.decode(APIDescription.self, forKey: .jsonapi) + } + let errors = try container.decodeIfPresent([Error].self, forKey: .errors) let meta: MetaType? @@ -242,6 +289,10 @@ extension Document { try container.encode(data.links, forKey: .links) } } + + if APIDescription.self != NoAPIDescription.self { + try container.encode(apiDescription, forKey: .jsonapi) + } } } diff --git a/Tests/JSONAPITests/Document/DocumentTests.swift b/Tests/JSONAPITests/Document/DocumentTests.swift index 0d1dbc4..e850a10 100644 --- a/Tests/JSONAPITests/Document/DocumentTests.swift +++ b/Tests/JSONAPITests/Document/DocumentTests.swift @@ -11,7 +11,7 @@ import JSONAPI class DocumentTests: XCTestCase { func test_singleDocumentNull() { - let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, + let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_null) XCTAssertFalse(document.body.isError) @@ -20,15 +20,36 @@ class DocumentTests: XCTestCase { XCTAssertEqual(document.body.meta, NoMetadata()) XCTAssertNil(document.body.primaryData?.value) XCTAssertEqual(document.body.includes?.count, 0) + XCTAssertEqual(document.body.links, NoLinks()) + XCTAssertEqual(document.apiDescription, .none) } func test_singleDocumentNull_encode() { - test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, + test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_null) } + func test_singleDocumentNullWithAPIDescription() { + let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, + data: single_document_null_with_api_description) + + XCTAssertFalse(document.body.isError) + XCTAssertNil(document.body.errors) + XCTAssertNotNil(document.body.primaryData) + XCTAssertEqual(document.body.meta, NoMetadata()) + XCTAssertNil(document.body.primaryData?.value) + XCTAssertEqual(document.body.includes?.count, 0) + XCTAssertEqual(document.body.links, NoLinks()) + XCTAssertEqual(document.apiDescription.version, "1.0") + } + + func test_singleDocumentNullWithAPIDescription_encode() { + test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, TestAPIDescription, UnknownJSONAPIError>.self, + data: single_document_null_with_api_description) + } + func test_singleDocumentNonOptionalFailsOnNull() { - XCTAssertThrowsError(try JSONDecoder().decode(Document, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, + XCTAssertThrowsError(try JSONDecoder().decode(Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, from: single_document_null)) } } @@ -36,7 +57,7 @@ class DocumentTests: XCTestCase { // MARK: - Error Document Tests extension DocumentTests { func test_unknownErrorDocumentNoMeta() { - let document = decoded(type: Document.self, + let document = decoded(type: Document.self, data: error_document_no_metadata) XCTAssertTrue(document.body.isError) @@ -56,12 +77,12 @@ extension DocumentTests { } func test_unknownErrorDocumentNoMeta_encode() { - test_DecodeEncodeEquality(type: Document.self, + test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata) } func test_unknownErrorDocumentMissingMeta() { - let document = decoded(type: Document.self, data: error_document_no_metadata) + let document = decoded(type: Document.self, data: error_document_no_metadata) XCTAssertTrue(document.body.isError) XCTAssertNil(document.body.meta) @@ -80,11 +101,11 @@ extension DocumentTests { } func test_unknownErrorDocumentMissingMeta_encode() { - test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata) + test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata) } func test_errorDocumentNoMeta() { - let document = decoded(type: Document.self, + let document = decoded(type: Document.self, data: error_document_no_metadata) XCTAssertTrue(document.body.isError) @@ -104,12 +125,12 @@ extension DocumentTests { } func test_errorDocumentNoMeta_encode() { - test_DecodeEncodeEquality(type: Document.self, + test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata) } func test_unknownErrorDocumentWithMeta() { - let document = decoded(type: Document.self, + let document = decoded(type: Document.self, data: error_document_with_metadata) XCTAssertTrue(document.body.isError) @@ -128,12 +149,12 @@ extension DocumentTests { } func test_unknownErrorDocumentWithMeta_encode() { - test_DecodeEncodeEquality(type: Document.self, + test_DecodeEncodeEquality(type: Document.self, data: error_document_with_metadata) } func test_unknownErrorDocumentWithMetaWithLinks() { - let document = decoded(type: Document.self, + let document = decoded(type: Document.self, data: error_document_with_metadata_with_links) XCTAssertTrue(document.body.isError) @@ -156,12 +177,12 @@ extension DocumentTests { } func test_unknownErrorDocumentWithMetaWithLinks_encode() { - test_DecodeEncodeEquality(type: Document.self, + test_DecodeEncodeEquality(type: Document.self, data: error_document_with_metadata_with_links) } func test_unknownErrorDocumentWithLinks() { - let document = decoded(type: Document.self, + let document = decoded(type: Document.self, data: error_document_with_links) XCTAssertTrue(document.body.isError) @@ -182,12 +203,12 @@ extension DocumentTests { } func test_unknownErrorDocumentWithLinks_encode() { - test_DecodeEncodeEquality(type: Document.self, + test_DecodeEncodeEquality(type: Document.self, data: error_document_with_links) } func test_unknownErrorDocumentMissingLinks() { - let document = decoded(type: Document.self, + let document = decoded(type: Document.self, data: error_document_no_metadata) XCTAssertTrue(document.body.isError) @@ -205,7 +226,7 @@ extension DocumentTests { } func test_unknownErrorDocumentMissingLinks_encode() { - test_DecodeEncodeEquality(type: Document.self, + test_DecodeEncodeEquality(type: Document.self, data: error_document_no_metadata) } } @@ -213,7 +234,7 @@ extension DocumentTests { // MARK: - Meta Document Tests extension DocumentTests { func test_metaDataDocument() { - let document = decoded(type: Document.self, + let document = decoded(type: Document.self, data: metadata_document) XCTAssertFalse(document.body.isError) @@ -224,12 +245,12 @@ extension DocumentTests { } func test_metaDataDocument_encode() { - test_DecodeEncodeEquality(type: Document.self, + test_DecodeEncodeEquality(type: Document.self, data: metadata_document) } func test_metaDataDocumentWithLinks() { - let document = decoded(type: Document.self, + let document = decoded(type: Document.self, data: metadata_document_with_links) XCTAssertFalse(document.body.isError) @@ -244,14 +265,14 @@ extension DocumentTests { } func test_metaDataDocumentWithLinks_encode() { - test_DecodeEncodeEquality(type: Document.self, + test_DecodeEncodeEquality(type: Document.self, data: metadata_document_with_links) } func test_metaDocumentMissingMeta() { - XCTAssertThrowsError(try JSONDecoder().decode(Document.self, from: metadata_document_missing_metadata)) + XCTAssertThrowsError(try JSONDecoder().decode(Document.self, from: metadata_document_missing_metadata)) - XCTAssertThrowsError(try JSONDecoder().decode(Document.self, from: metadata_document_missing_metadata2)) + XCTAssertThrowsError(try JSONDecoder().decode(Document.self, from: metadata_document_missing_metadata2)) } } @@ -259,7 +280,7 @@ extension DocumentTests { // MARK: Single Document Tests extension DocumentTests { func test_singleDocumentNoIncludes() { - let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, + let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) XCTAssertFalse(document.body.isError) @@ -271,12 +292,12 @@ extension DocumentTests { } func test_singleDocumentNoIncludes_encode() { - test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, + test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) } func test_singleDocumentNoIncludesOptionalNotNull() { - let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, + let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) XCTAssertFalse(document.body.isError) @@ -288,12 +309,12 @@ extension DocumentTests { } func test_singleDocumentNoIncludesOptionalNotNull_encode() { - test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, + test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) } func test_singleDocumentNoIncludesWithMetadata() { - let document = decoded(type: Document, TestPageMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, + let document = decoded(type: Document, TestPageMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata) XCTAssertFalse(document.body.isError) @@ -305,12 +326,12 @@ extension DocumentTests { } func test_singleDocumentNoIncludesWithMetadata_encode() { - test_DecodeEncodeEquality(type: Document, TestPageMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, + test_DecodeEncodeEquality(type: Document, TestPageMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata) } func test_singleDocumentNoIncludesWithLinks() { - let document = decoded(type: Document, NoMetadata, TestLinks, NoIncludes, UnknownJSONAPIError>.self, + let document = decoded(type: Document, NoMetadata, TestLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_links) XCTAssertFalse(document.body.isError) @@ -327,12 +348,12 @@ extension DocumentTests { } func test_singleDocumentNoIncludesWithLinks_encode() { - test_DecodeEncodeEquality(type: Document, NoMetadata, TestLinks, NoIncludes, UnknownJSONAPIError>.self, + test_DecodeEncodeEquality(type: Document, NoMetadata, TestLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_links) } func test_singleDocumentNoIncludesWithMetadataWithLinks() { - let document = decoded(type: Document, TestPageMetadata, TestLinks, NoIncludes, UnknownJSONAPIError>.self, + let document = decoded(type: Document, TestPageMetadata, TestLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata_with_links) XCTAssertFalse(document.body.isError) @@ -349,20 +370,20 @@ extension DocumentTests { } func test_singleDocumentNoIncludesWithMetadataWithLinks_encode() { - test_DecodeEncodeEquality(type: Document, TestPageMetadata, TestLinks, NoIncludes, UnknownJSONAPIError>.self, + test_DecodeEncodeEquality(type: Document, TestPageMetadata, TestLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes_with_metadata_with_links) } func test_singleDocumentNoIncludesWithMetadataMissingLinks() { - XCTAssertThrowsError(try JSONDecoder().decode(Document, TestPageMetadata, TestLinks, NoIncludes, UnknownJSONAPIError>.self, from: single_document_no_includes_with_metadata)) + XCTAssertThrowsError(try JSONDecoder().decode(Document, TestPageMetadata, TestLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, from: single_document_no_includes_with_metadata)) } func test_singleDocumentNoIncludesMissingMetadata() { - XCTAssertThrowsError(try JSONDecoder().decode(Document, TestPageMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, from: single_document_no_includes)) + XCTAssertThrowsError(try JSONDecoder().decode(Document, TestPageMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, from: single_document_no_includes)) } func test_singleDocumentSomeIncludes() { - let document = decoded(type: Document, NoMetadata, NoLinks, Include1, UnknownJSONAPIError>.self, + let document = decoded(type: Document, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes) XCTAssertFalse(document.body.isError) @@ -375,12 +396,12 @@ extension DocumentTests { } func test_singleDocumentSomeIncludes_encode() { - test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, Include1, UnknownJSONAPIError>.self, + test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes) } func test_singleDocumentSomeIncludesWithMetadata() { - let document = decoded(type: Document, TestPageMetadata, NoLinks, Include1, UnknownJSONAPIError>.self, + let document = decoded(type: Document, TestPageMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata) XCTAssertFalse(document.body.isError) @@ -394,12 +415,12 @@ extension DocumentTests { } func test_singleDocumentSomeIncludesWithMetadata_encode() { - test_DecodeEncodeEquality(type: Document, TestPageMetadata, NoLinks, Include1, UnknownJSONAPIError>.self, + test_DecodeEncodeEquality(type: Document, TestPageMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata) } func test_singleDocumentNoIncludesWithSomeIncludesWithMetadataWithLinks() { - let document = decoded(type: Document, TestPageMetadata, TestLinks, Include1, UnknownJSONAPIError>.self, + let document = decoded(type: Document, TestPageMetadata, TestLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata_with_links) XCTAssertFalse(document.body.isError) @@ -417,7 +438,7 @@ extension DocumentTests { } func test_singleDocumentNoIncludesWithSomeIncludesMetadataWithLinks_encode() { - test_DecodeEncodeEquality(type: Document, TestPageMetadata, TestLinks, Include1, UnknownJSONAPIError>.self, + test_DecodeEncodeEquality(type: Document, TestPageMetadata, TestLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_some_includes_with_metadata_with_links) } } @@ -426,21 +447,21 @@ extension DocumentTests { extension DocumentTests { func test_singleDocument_PolyPrimaryResource() { let article = Article(id: Id(rawValue: "1"), relationships: .init(author: ToOneRelationship(id: Id(rawValue: "33")))) - let document = decoded(type: Document>, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, data: single_document_no_includes) + let document = decoded(type: Document>, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) XCTAssertEqual(document.body.primaryData?.value[Article.self], article) XCTAssertNil(document.body.primaryData?.value[Author.self]) } func test_singleDocument_PolyPrimaryResource_encode() { - test_DecodeEncodeEquality(type: Document>, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, data: single_document_no_includes) + test_DecodeEncodeEquality(type: Document>, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: single_document_no_includes) } } // MARK: - ManyResourceBody Tests extension DocumentTests { func test_manyDocumentNoIncludes() { - let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, + let document = decoded(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: many_document_no_includes) XCTAssertFalse(document.body.isError) @@ -454,12 +475,12 @@ extension DocumentTests { } func test_manyDocumentNoIncludes_encode() { - test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, UnknownJSONAPIError>.self, + test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, UnknownJSONAPIError>.self, data: many_document_no_includes) } func test_manyDocumentSomeIncludes() { - let document = decoded(type: Document, NoMetadata, NoLinks, Include1, UnknownJSONAPIError>.self, + let document = decoded(type: Document, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: many_document_some_includes) XCTAssertFalse(document.body.isError) @@ -477,7 +498,7 @@ extension DocumentTests { } func test_manyDocumentSomeIncludes_encode() { - test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, Include1, UnknownJSONAPIError>.self, + test_DecodeEncodeEquality(type: Document, NoMetadata, NoLinks, Include1, NoAPIDescription, UnknownJSONAPIError>.self, data: many_document_some_includes) } } @@ -520,6 +541,8 @@ extension DocumentTests { } } + typealias TestAPIDescription = APIDescription + enum TestError: JSONAPIError { case unknownError case basic(BasicError) diff --git a/Tests/JSONAPITests/Document/stubs/DocumentStubs.swift b/Tests/JSONAPITests/Document/stubs/DocumentStubs.swift index 214a4d6..0c3fb0e 100644 --- a/Tests/JSONAPITests/Document/stubs/DocumentStubs.swift +++ b/Tests/JSONAPITests/Document/stubs/DocumentStubs.swift @@ -11,6 +11,15 @@ let single_document_null = """ } """.data(using: .utf8)! +let single_document_null_with_api_description = """ +{ + "data": null, + "jsonapi": { + "version": "1.0" + } +} +""".data(using: .utf8)! + let single_document_no_includes = """ { "data": {