From cc57a60ce27ec5eb4a983872fc041fac6bb7e13a Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Mon, 21 Sep 2020 20:51:10 -0700 Subject: [PATCH] add better documentation on relationship metadata --- documentation/usage.md | 56 ++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/documentation/usage.md b/documentation/usage.md index 5dc298f..30cebdc 100644 --- a/documentation/usage.md +++ b/documentation/usage.md @@ -11,6 +11,7 @@ In this documentation, in order to draw attention to the difference between the - [`RawIdType`](#rawidtype) - [Convenient `typealiases`](#convenient-typealiases) - [`JSONAPI.Relationships`](#jsonapirelationships) + - [Relationship Metadata](#relationship-metadata) - [`JSONAPI.Attributes`](#jsonapiattributes) - [`Transformer`](#transformer) - [`Validator`](#validator) @@ -149,6 +150,33 @@ Note that I am calling an unidentified person is a "new" person. This is general There are three types of `Relationships`: `MetaRelationship`, `ToOneRelationship` and `ToManyRelationship`. A `ResourceObjectDescription`'s `Relationships` type can contain any number of `Relationship` properties of any of these types. Do not store anything other than `Relationship` properties in the `Relationships` struct of a `ResourceObjectDescription`. +The `MetaRelationship` is special in that it represents a Relationship Object with no `data` (it must contain at least one of `meta` or `links`). The other two relationship types are Relationship Objects with either singular resource linkages (`ToOneRelationship`) or arrays of resource linkages (`ToManyRelationship`). + +To describe a relationship that may be omitted (i.e. the key is not even present in the JSON object), you make the entire `MetaRelationship`, `ToOneRelationship` or `ToManyRelationship` optional. +```swift +// note the question mark at the very end of the line. +let optionalRelative: ToOneRelationship? +``` + +A `ToOneRelationship` can be marked as nullable (i.e. the value could be either `null` or a resource identifier) like this: +```swift +// note the question mark just after `Person`. +let nullableRelative: ToOneRelationship +``` + +A `ToManyRelationship` can naturally represent the absence of related values with an empty array, so `ToManyRelationship` do not support nullability. + +A `ResourceObject` that does not have relationships can be described by adding the following to a `ResourceObjectDescription`: +```swift +typealias Relationships = NoRelationships +``` + +`Relationship` values boil down to `Ids` of other resource objects. To access the `Id` of a related `ResourceObject`, you can use the custom `~>` operator with the `KeyPath` of the `Relationship` from which you want the `Id`. The friends of the above `Person` `ResourceObject` can be accessed as follows (type annotations for clarity): +```swift +let friendIds: [Person.Id] = person ~> \.friends +``` + +#### Relationship Metadata In addition to identifying resource objects by ID and type, `Relationships` can contain `Meta` or `Links` that follow the same rules as [`Meta`](#jsonapimeta) and [`Links`](#jsonapilinks) elsewhere in the JSON:API Document. Metadata can be specified both in the Relationship Object and in the Resource Identifier Object. You specify the two types of metadata differently. As always, you can use `NoMetadata` to indicate you do not intend the JSON:API relationship to contain metadata. @@ -186,30 +214,16 @@ let relationship3: ToOneRelationship // ^ assumes `CoolMetadata` is a `Codable` struct defined elsewhere ``` -The `MetaRelationship` is special in that it represents a Relationship Object with no `data` (it must contain at least one of `meta` or `links`). The other two relationship types are Relationship Objects with either singular resource linkages (`ToOneRelationship`) or arrays of resource linkages (`ToManyRelationship`). +When you need metadata out of a to-one relationship, you can access the Relationship Object metadata with the `meta` property and the Resource Identifer metadata with the `idMeta` property. When you need metadata out of a to-many relationship, you can access the Relationship Object metadata with the `meta` property (there is only one such metadata object) and you can access the Resource Identifier metadata (of which there is one per related resource) by asking each element of the `idsWithMeta` property for its `meta` property. -To describe a relationship that may be omitted (i.e. the key is not even present in the JSON object), you make the entire `MetaRelationship`, `ToOneRelationship` or `ToManyRelationship` optional. ```swift -// note the question mark at the very end of the line. -let optionalRelative: ToOneRelationship? -``` +// to-one +let relation = entity.relationships.home +let idMeta = relation.idMeta -A `ToOneRelationship` can be marked as nullable (i.e. the value could be either `null` or a resource identifier) like this: -```swift -// note the question mark just after `Person`. -let nullableRelative: ToOneRelationship -``` - -A `ToManyRelationship` can naturally represent the absence of related values with an empty array, so `ToManyRelationship` do not support nullability. - -A `ResourceObject` that does not have relationships can be described by adding the following to a `ResourceObjectDescription`: -```swift -typealias Relationships = NoRelationships -``` - -`Relationship` values boil down to `Ids` of other resource objects. To access the `Id` of a related `ResourceObject`, you can use the custom `~>` operator with the `KeyPath` of the `Relationship` from which you want the `Id`. The friends of the above `Person` `ResourceObject` can be accessed as follows (type annotations for clarity): -```swift -let friendIds: [Person.Id] = person ~> \.friends +// to-many +let relations = entity.relationships.friends +let idMeta = relations.idsWithMeta.map { $0.meta } ``` ### `JSONAPI.Attributes`