From 83cf5bba875b44e927b11ae47938f3a4e88666a3 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Tue, 30 Apr 2024 09:31:36 -0500 Subject: [PATCH] allow optional metadata to be omitted as well as nulled out. --- Sources/JSONAPI/Resource/Relationship.swift | 3 --- .../Resource Object/ResourceObject.swift | 12 +++++++++- .../ResourceObject/ResourceObjectTests.swift | 22 +++++++++++++++++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Sources/JSONAPI/Resource/Relationship.swift b/Sources/JSONAPI/Resource/Relationship.swift index fc03c4e..4a2c3fa 100644 --- a/Sources/JSONAPI/Resource/Relationship.swift +++ b/Sources/JSONAPI/Resource/Relationship.swift @@ -263,9 +263,6 @@ extension MetaRelationship: Codable { } } -fileprivate protocol _Optional {} -extension Optional: _Optional {} - extension ToOneRelationship: Codable where Identifiable.ID: OptionalId { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: ResourceLinkageCodingKeys.self) diff --git a/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift b/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift index 77d367e..1b4308b 100644 --- a/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift +++ b/Sources/JSONAPI/Resource/Resource Object/ResourceObject.swift @@ -447,7 +447,17 @@ public extension ResourceObject { ) } - meta = try (NoMetadata() as? MetaType) ?? container.decode(MetaType.self, forKey: .meta) + do { + meta = try (NoMetadata() as? MetaType) ?? container.decode(MetaType.self, forKey: .meta) + } catch let decodingError as DecodingError { + let anyNil: Any? = nil + + guard case .keyNotFound = decodingError, + let omittedMeta = anyNil as? MetaType else { + throw decodingError + } + meta = omittedMeta + } links = try (NoLinks() as? LinksType) ?? container.decode(LinksType.self, forKey: .links) } diff --git a/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift b/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift index d492b18..77a75c7 100644 --- a/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift +++ b/Tests/JSONAPITests/ResourceObject/ResourceObjectTests.swift @@ -151,6 +151,11 @@ extension ResourceObjectTests { data: entity_no_relationships_no_attributes) } + func test_EntityNoMetaDecodesAsOptionalMeta() { + let _ = decoded(type: TestEntityOptionalMeta.self, + data: entity_no_relationships_no_attributes) + } + func test_EntityNoRelationshipsSomeAttributes() { let entity = decoded(type: TestEntity5.self, data: entity_no_relationships_some_attributes) @@ -861,13 +866,13 @@ extension ResourceObjectTests { public struct Relationships: JSONAPI.Relationships { public init() { - optionalMeta = nil + optionalMeta = nil optionalOne = nil optionalNullableOne = nil optionalMany = nil } - let optionalMeta: MetaRelationship? + let optionalMeta: MetaRelationship? let optionalOne: ToOneRelationship? @@ -879,6 +884,19 @@ extension ResourceObjectTests { typealias TestEntity12 = BasicEntity + enum TestEntityOptionalMetaType: JSONAPI.ResourceObjectDescription { + public static var jsonType: String { return "test_entities" } + + typealias Attributes = NoAttributes + typealias Relationships = NoRelationships + } + + struct UnimportantMeta: JSONAPI.Meta { + let property1: String + } + + typealias TestEntityOptionalMeta = JSONAPI.ResourceObject + enum UnidentifiedTestEntityType: ResourceObjectDescription { public static var jsonType: String { return "unidentified_test_entities" }