Skip to content

Commit

Permalink
add better documentation on relationship metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
mattpolzin committed Sep 22, 2020
1 parent ce52882 commit cc57a60
Showing 1 changed file with 35 additions and 21 deletions.
56 changes: 35 additions & 21 deletions documentation/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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<Person, NoIdMetadata, NoMetadata, NoLinks>?
```

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<Person?, NoIdMetadata, NoMetadata, NoLinks>
```

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.
Expand Down Expand Up @@ -186,30 +214,16 @@ let relationship3: ToOneRelationship<Person, CoolMetadata, NoMetadata, NoLinks>
// ^ 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<Person, NoIdMetadata, NoMetadata, NoLinks>?
```
// 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<Person?, NoIdMetadata, NoMetadata, NoLinks>
```

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`
Expand Down

0 comments on commit cc57a60

Please sign in to comment.