From 662a84ccf0a045fa4b30c2a40f74c485d0807bb5 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Sat, 12 Oct 2019 09:35:01 -0700 Subject: [PATCH] Add examples around modifying attributes/relationships on resource object and then preparing a new request (i.e. for PATCHing) --- .../PATCHing.xcplaygroundpage/Contents.swift | 147 ++++++++++++++++++ JSONAPI.playground/Sources/Entities.swift | 25 +++ JSONAPI.playground/contents.xcplayground | 1 + 3 files changed, 173 insertions(+) create mode 100644 JSONAPI.playground/Pages/PATCHing.xcplaygroundpage/Contents.swift diff --git a/JSONAPI.playground/Pages/PATCHing.xcplaygroundpage/Contents.swift b/JSONAPI.playground/Pages/PATCHing.xcplaygroundpage/Contents.swift new file mode 100644 index 0000000..937b873 --- /dev/null +++ b/JSONAPI.playground/Pages/PATCHing.xcplaygroundpage/Contents.swift @@ -0,0 +1,147 @@ +//: [Previous](@previous) + +import Foundation +import JSONAPI + +/******* + + Please enjoy these examples, but allow me the forced casting and the lack of error checking for the sake of brevity. + + This playground focuses on receiving a resource, making some changes, and then creating a request body for a PATCH request. + As with all examples in these playround pages, no actual networking code will be provided. + + ********/ + +// Mapping functions (will be included in future version of library) +extension JSONAPI.ResourceObject { + func mapAttributes(_ transform: (Description.Attributes) -> Description.Attributes) -> Self { + return Self(id: id, + attributes: transform(attributes), + relationships: relationships, + meta: meta, + links: links) + } + + func mapRelationships(_ transform: (Description.Relationships) -> Description.Relationships) -> Self { + return Self(id: id, + attributes: attributes, + relationships: transform(relationships), + meta: meta, + links: links) + } +} + +// Mock up a server response +let mockDogData = """ +{ + "data": { + "id": "1234", + "type": "dogs", + "attributes": { + "name": "Sparky" + }, + "relationships": { + "owner": { + "data": null + } + } + } +} +""".data(using: .utf8)! + +// +// MARK: - EXAMPLE 1 (Mutable Attributes) +// + +// pretend to have requested a Dog and received the mock data +// now parse it. +let parsedResponse = try! JSONDecoder().decode(MutableDogDocument.self, from: mockDogData) + +// extract our Dog (skipping over any robustness to handle errors) +var dog = parsedResponse.body.primaryResource!.value +print("Received dog named: \(dog.name)") + +// change the dog's name +let changedDog = dog.mapAttributes { currentAttributes in + var ret = currentAttributes + ret.name = .init(value: "Julia") + return ret +} + +// create a document to be used as a request body for a PATCH request +let patchRequest = MutableDogDocument(apiDescription: .none, + body: .init(resourceObject: changedDog), + includes: .none, + meta: .none, + links: .none) + +// encode and send off to server +let encodedPatchRequest = try! JSONEncoder().encode(patchRequest) +print("----") +print(String(data: encodedPatchRequest, encoding:.utf8)!) + + +// +// MARK: - EXAMPLE 2 (Immutable Attributes) +// +print() +print("####") +print() + +// pretend to have requested a Dog and received the mock data +// now parse it. +let parsedResponse2 = try! JSONDecoder().decode(SingleDogDocument.self, from: mockDogData) + +// extract our Dog (skipping over any robustness to handle errors) +var dog2 = parsedResponse2.body.primaryResource!.value +print("Received dog named: \(dog2.name)") + +// change the dog's name +let changedDog2 = dog2.mapAttributes { _ in + return .init(name: .init(value: "Nigel")) +} + +// create a document to be used as a request body for a PATCH request +let patchRequest2 = SingleDogDocument(apiDescription: .none, + body: .init(resourceObject: changedDog2), + includes: .none, + meta: .none, + links: .none) + +// encode and send off to server +let encodedPatchRequest2 = try! JSONEncoder().encode(patchRequest2) +print("----") +print(String(data: encodedPatchRequest2, encoding:.utf8)!) + + +// +// MARK: - EXAMPLE 3 (Change relationship) +// +print() +print("####") +print() + +// pretend to have requested a Dog and received the mock data +// now parse it. +let parsedResponse3 = try! JSONDecoder().decode(SingleDogDocument.self, from: mockDogData) + +// extract our Dog (skipping over any robustness to handle errors) +var dog3 = parsedResponse2.body.primaryResource!.value +print("Received dog with owner: \(dog3 ~> \.owner)") + +// give the dog an owner +let changedDog3 = dog3.mapRelationships { _ in + return .init(owner: .init(id: Id(rawValue: "1"))) +} + +// create a document to be used as a request body for a PATCH request +let patchRequest3 = SingleDogDocument(apiDescription: .none, + body: .init(resourceObject: changedDog3), + includes: .none, + meta: .none, + links: .none) + +// encode and send off to server +let encodedPatchRequest3 = try! JSONEncoder().encode(patchRequest3) +print("----") +print(String(data: encodedPatchRequest3, encoding:.utf8)!) diff --git a/JSONAPI.playground/Sources/Entities.swift b/JSONAPI.playground/Sources/Entities.swift index 4ae56c9..1bd6109 100644 --- a/JSONAPI.playground/Sources/Entities.swift +++ b/JSONAPI.playground/Sources/Entities.swift @@ -119,6 +119,29 @@ public enum AlternativeDogDescription: ResourceObjectDescription { public typealias AlternativeDog = ExampleEntity +public enum MutableDogDescription: ResourceObjectDescription { + + public static var jsonType: String { return "dogs" } + + public struct Attributes: JSONAPI.Attributes { + public var name: Attribute + + public init(name: Attribute) { + self.name = name + } + } + + public struct Relationships: JSONAPI.Relationships { + public var owner: ToOne + + public init(owner: ToOne) { + self.owner = owner + } + } +} + +public typealias MutableDog = ExampleEntity + public extension ResourceObject where Description == DogDescription, MetaType == NoMetadata, LinksType == NoLinks, EntityRawIdType == String { init(name: String, owner: Person?) throws { self = Dog(attributes: .init(name: .init(value: name)), relationships: DogDescription.Relationships(owner: .init(resourceObject: owner)), meta: .none, links: .none) @@ -141,4 +164,6 @@ public typealias House = ExampleEntity public typealias SingleDogDocument = JSONAPI.Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, BasicJSONAPIError> +public typealias MutableDogDocument = JSONAPI.Document, NoMetadata, NoLinks, NoIncludes, NoAPIDescription, BasicJSONAPIError> + public typealias BatchPeopleDocument = JSONAPI.Document, NoMetadata, NoLinks, Include2, NoAPIDescription, BasicJSONAPIError> diff --git a/JSONAPI.playground/contents.xcplayground b/JSONAPI.playground/contents.xcplayground index 21e919c..e777e3c 100644 --- a/JSONAPI.playground/contents.xcplayground +++ b/JSONAPI.playground/contents.xcplayground @@ -6,5 +6,6 @@ + \ No newline at end of file