Skip to content

Commit

Permalink
Merge pull request #87 from mattpolzin/release/v5
Browse files Browse the repository at this point in the history
Release/v5
  • Loading branch information
mattpolzin authored Sep 26, 2020
2 parents f64ef95 + 6a7072e commit c645c73
Show file tree
Hide file tree
Showing 35 changed files with 1,079 additions and 252 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ jobs:
- swift:5.2-focal
- swift:5.2-centos8
- swift:5.2-amazonlinux2
- swiftlang/swift:nightly-5.3-xenial
- swiftlang/swift:nightly-5.3-bionic
- swift:5.3-xenial
- swift:5.3-bionic
- swift:5.3-focal
- swift:5.3-centos8
- swift:5.3-amazonlinux2
container: ${{ matrix.image }}
steps:
- name: Checkout code
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ typealias UnidentifiedJSONEntity<Description: ResourceObjectDescription> = JSONA
// Create relationship typealiases because we do not expect
// JSON:API Relationships for this particular API to have
// Metadata or Links associated with them.
typealias ToOneRelationship<Entity: JSONAPIIdentifiable> = JSONAPI.ToOneRelationship<Entity, NoMetadata, NoLinks>
typealias ToManyRelationship<Entity: Relatable> = JSONAPI.ToManyRelationship<Entity, NoMetadata, NoLinks>
typealias ToOneRelationship<Entity: JSONAPIIdentifiable> = JSONAPI.ToOneRelationship<Entity, NoIdMetadata, NoMetadata, NoLinks>
typealias ToManyRelationship<Entity: Relatable> = JSONAPI.ToManyRelationship<Entity, NoIdMetadata, NoMetadata, NoLinks>

// Create a typealias for a Document because we do not expect
// JSON:API Documents for this particular API to have Metadata, Links,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ enum AuthorDescription: ResourceObjectDescription {
}

struct Relationships: JSONAPI.Relationships {
let articles: ToManyRelationship<Article, ToManyRelationshipMetadata, ToManyRelationshipLinks>
let articles: ToManyRelationship<Article, NoIdMetadata, ToManyRelationshipMetadata, ToManyRelationshipLinks>
}
}

Expand All @@ -88,11 +88,11 @@ enum ArticleDescription: ResourceObjectDescription {

struct Relationships: JSONAPI.Relationships {
/// The primary attributed author of the article.
let primaryAuthor: ToOneRelationship<Author, NoMetadata, NoLinks>
let primaryAuthor: ToOneRelationship<Author, NoIdMetadata, NoMetadata, NoLinks>
/// All authors excluding the primary author.
/// It is customary to print the primary author's
/// name first, followed by the other authors.
let otherAuthors: ToManyRelationship<Author, ToManyRelationshipMetadata, ToManyRelationshipLinks>
let otherAuthors: ToManyRelationship<Author, NoIdMetadata, ToManyRelationshipMetadata, ToManyRelationshipLinks>
}
}

Expand Down
4 changes: 2 additions & 2 deletions JSONAPI.playground/Sources/Entities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ extension String: CreatableRawIdType {

// MARK: - typealiases for convenience
public typealias ExampleEntity<Description: ResourceObjectDescription> = ResourceObject<Description, NoMetadata, NoLinks, String>
public typealias ToOne<E: JSONAPIIdentifiable> = ToOneRelationship<E, NoMetadata, NoLinks>
public typealias ToMany<E: Relatable> = ToManyRelationship<E, NoMetadata, NoLinks>
public typealias ToOne<E: JSONAPIIdentifiable> = ToOneRelationship<E, NoIdMetadata, NoMetadata, NoLinks>
public typealias ToMany<E: Relatable> = ToManyRelationship<E, NoIdMetadata, NoMetadata, NoLinks>

// MARK: - A few resource objects (entities)
public enum PersonDescription: ResourceObjectDescription {
Expand Down
2 changes: 1 addition & 1 deletion JSONAPI.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Pod::Spec.new do |spec|
#

spec.name = "MP-JSONAPI"
spec.version = "4.0.0"
spec.version = "5.0.0"
spec.summary = "Swift Codable JSON API framework."

# This description is used to generate tags and improve search results.
Expand Down
2 changes: 1 addition & 1 deletion Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"pins": [
{
"package": "Poly",
"repositoryURL": "https://github.com/mattpolzin/Poly",
"repositoryURL": "https://github.com/mattpolzin/Poly.git",
"state": {
"branch": null,
"revision": "36ba3f624bffa34f5f9b9c7648eab3cfdcab4748",
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# JSONAPI
[![MIT license](http://img.shields.io/badge/license-MIT-lightgrey.svg)](http://opensource.org/licenses/MIT) [![Swift 5.2](http://img.shields.io/badge/Swift-5.2-blue.svg)](https://swift.org) [![Build Status](https://app.bitrise.io/app/c8295b9589aa401e/status.svg?token=vzcyqWD5bQ4xqQfZsaVzNw&branch=master)](https://app.bitrise.io/app/c8295b9589aa401e)
[![MIT license](http://img.shields.io/badge/license-MIT-lightgrey.svg)](http://opensource.org/licenses/MIT) [![Swift 5.2+](http://img.shields.io/badge/Swift-5.2/5.3-blue.svg)](https://swift.org) [![Build Status](https://app.bitrise.io/app/c8295b9589aa401e/status.svg?token=vzcyqWD5bQ4xqQfZsaVzNw&branch=master)](https://app.bitrise.io/app/c8295b9589aa401e)

A Swift package for encoding to- and decoding from **JSON API** compliant requests and responses.

Expand Down Expand Up @@ -66,7 +66,7 @@ If you find something wrong with this library and it isn't already mentioned und
### Swift Package Manager
Just include the following in your package's dependencies and add `JSONAPI` to the dependencies for any of your targets.
```swift
.package(url: "https://github.com/mattpolzin/JSONAPI.git", from: "4.0.0")
.package(url: "https://github.com/mattpolzin/JSONAPI.git", from: "5.0.0")
```

### Xcode project
Expand Down
54 changes: 49 additions & 5 deletions Sources/JSONAPI/Document/Includes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,15 @@ extension Includes: Decodable where I: Decodable {
}
}
guard errors.count == error.individualTypeFailures.count else {
throw IncludesDecodingError(error: error, idx: idx)
throw IncludesDecodingError(error: error, idx: idx, totalIncludesCount: container.count ?? 0)
}
throw IncludesDecodingError(
error: IncludeDecodingError(failures: errors),
idx: idx
idx: idx,
totalIncludesCount: container.count ?? 0
)
} catch let error {
throw IncludesDecodingError(error: error, idx: idx)
throw IncludesDecodingError(error: error, idx: idx, totalIncludesCount: container.count ?? 0)
}
}

Expand Down Expand Up @@ -208,7 +209,13 @@ extension Includes where I: _Poly11 {
// MARK: - DecodingError
public struct IncludesDecodingError: Swift.Error, Equatable {
public let error: Swift.Error
/// The zero-based index of the include that failed to decode.
public let idx: Int
/// The total count of includes in the document that failed to decode.
///
/// In other words, "of `totalIncludesCount` includes, the `(idx + 1)`th
/// include failed to decode.
public let totalIncludesCount: Int

public static func ==(lhs: Self, rhs: Self) -> Bool {
return lhs.idx == rhs.idx
Expand All @@ -218,18 +225,55 @@ public struct IncludesDecodingError: Swift.Error, Equatable {

extension IncludesDecodingError: CustomStringConvertible {
public var description: String {
return "Include \(idx + 1) failed to parse: \(error)"
let ordinalSuffix: String
if (idx % 100) + 1 > 9 && (idx % 100) + 1 < 20 {
// the teens
ordinalSuffix = "th"
} else {
switch ((idx % 10) + 1) {
case 1:
ordinalSuffix = "st"
case 2:
ordinalSuffix = "nd"
case 3:
ordinalSuffix = "rd"
default:
ordinalSuffix = "th"
}
}
let ordinalDescription = "\(idx + 1)\(ordinalSuffix)"

return "Out of the \(totalIncludesCount) includes in the document, the \(ordinalDescription) one failed to parse: \(error)"
}
}

public struct IncludeDecodingError: Swift.Error, Equatable, CustomStringConvertible {
public let failures: [ResourceObjectDecodingError]

public var description: String {
// concise error when all failures are mismatched JSON:API types:
if case let .jsonTypeMismatch(foundType: foundType)? = failures.first?.cause,
failures.allSatisfy({ $0.cause.isTypeMismatch }) {
let expectedTypes = failures
.compactMap { "'\($0.resourceObjectJsonAPIType)'" }
.joined(separator: ", ")

return "Found JSON:API type '\(foundType)' but expected one of \(expectedTypes)"
}

// concise error when all but failures but one are type mismatches because
// we can assume the correct type was found but there was some other error:
let nonTypeMismatches = failures.filter({ !$0.cause.isTypeMismatch})
if nonTypeMismatches.count == 1, let nonTypeMismatch = nonTypeMismatches.first {
return String(describing: nonTypeMismatch)
}

// fall back to just describing all of the reasons it could not have been any of the available
// types:
return failures
.enumerated()
.map {
"\nCould not have been Include Type \($0.offset + 1) because:\n\($0.element)"
"\nCould not have been Include Type `\($0.element.resourceObjectJsonAPIType)` because:\n\($0.element)"
}.joined(separator: "\n")
}
}
7 changes: 7 additions & 0 deletions Sources/JSONAPI/Meta/Meta.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,10 @@ public struct NoMetadata: Meta, CustomStringConvertible {

public var description: String { return "No Metadata" }
}

/// The type of metadata found in a Resource Identifier Object.
///
/// It is sometimes more legible to differentiate between types of metadata
/// even when the underlying type is the same. This typealias is only here
/// to make code more easily understandable.
public typealias NoIdMetadata = NoMetadata
Loading

0 comments on commit c645c73

Please sign in to comment.