Skip to content

Commit

Permalink
Add optional includesLevel parameter to Client.fetch (#274)
Browse files Browse the repository at this point in the history
 Add optional includesLevel parameter to Client.fetch
  • Loading branch information
Khaledgarbaya committed Jun 27, 2019
2 parents 6f5aeee + a6f87cd commit 3b8e6ef
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ Packages

# Carthage
Carthage/Build/
*.framework.zip
26 changes: 19 additions & 7 deletions Sources/Contentful/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -447,33 +447,45 @@ extension Client {
/// - Parameters:
/// - resourceType: A reference to the Swift type which conforms to `Decodable & EndpointAccessible`
/// - id: The identifier of the resource which should be fetched.
/// - include: Specifies the level of includes to be resolved. Optional, because we leave it to the server
/// to decide the optimal default value: [Retrieval of linked items]
/// - completion: The handler being called on completion of the request with a Result wrapping your decoded type or an error.
/// - Returns: Returns the `URLSessionDataTask` of the request which can be used for request cancellation.
///
/// [Retrieval of linked items]: https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/links/retrieval-of-linked-items
@discardableResult
public func fetch<ResourceType>(_ resourceType: ResourceType.Type,
id: String,
include includesLevel: UInt? = nil,
then completion: @escaping ResultsHandler<ResourceType>) -> URLSessionDataTask
where ResourceType: Decodable & EndpointAccessible {

// If the resource is not an entry, then don't worry about fetching with includes.
// If the resource is not an entry, includes are not supported.
if !(resourceType is EntryDecodable.Type) && resourceType != Entry.self {
var url = self.url(endpoint: ResourceType.endpoint)
url.appendPathComponent(id)
return fetch(url: url, then: completion)
}

// Before `completion` is called, either the first item is extracted, and
// sent as `.success`, or an `.error` is sent.
let fetchCompletion: (Result<HomogeneousArrayResponse<ResourceType>>) -> Void = { result in
switch result {
case .success(let response) where response.items.first != nil:
completion(Result.success(response.items.first!))
case .success(let response):
guard let firstItem = response.items.first else {
completion(.error(SDKError.noResourceFoundFor(id: id)))
break
}
completion(.success(firstItem))
case .error(let error):
completion(Result.error(error))
default:
completion(Result.error(SDKError.noResourceFoundFor(id: id)))
completion(.error(error))
}
}

let query = ResourceQuery.where(sys: .id, .equals(id))
var query = ResourceQuery.where(sys: .id, .equals(id))
if let includesLevel = includesLevel {
query = query.include(includesLevel)
}
return fetch(url: url(endpoint: ResourceType.endpoint, parameters: query.parameters), then: fetchCompletion)
}

Expand Down
41 changes: 41 additions & 0 deletions Tests/ContentfulTests/DVRRecordings/LinkResolverTests.json
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,47 @@
}
}
},
{
"request" : {
"headers" : {
"Authorization" : "Bearer 14d305ad526d4487e21a99b5b9313a8877ce6fbf540f02b12189eea61550ef34",
"X-Contentful-User-Agent" : "sdk contentful.swift\/4.2.2; platform Swift\/4.0; os macOS\/10.13.6;"
},
"url" : "https:\/\/cdn.contentful.com\/spaces\/smf0sqiu0c5s\/environments\/master\/entries?sys.id=2JFSeiPTZYm4goMSUeYSCU&include=0",
"method" : "GET"
},
"recorded_at" : 1544085038.169528,
"response" : {
"url" : "https:\/\/cdn.contentful.com\/spaces\/smf0sqiu0c5s\/environments\/master\/entries?sys.id=2JFSeiPTZYm4goMSUeYSCU&include=0",
"status" : 200,
"body" : "ewogICJzeXMiOiB7CiAgICAidHlwZSI6ICJBcnJheSIKICB9LAogICJ0b3RhbCI6IDEsCiAgInNraXAiOiAwLAogICJsaW1pdCI6IDEwMCwKICAiaXRlbXMiOiBbCiAgICB7CiAgICAgICJzeXMiOiB7CiAgICAgICAgInNwYWNlIjogewogICAgICAgICAgInN5cyI6IHsKICAgICAgICAgICAgInR5cGUiOiAiTGluayIsCiAgICAgICAgICAgICJsaW5rVHlwZSI6ICJTcGFjZSIsCiAgICAgICAgICAgICJpZCI6ICJzbWYwc3FpdTBjNXMiCiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAiaWQiOiAiMkpGU2VpUFRaWW00Z29NU1VlWVNDVSIsCiAgICAgICAgInR5cGUiOiAiRW50cnkiLAogICAgICAgICJjcmVhdGVkQXQiOiAiMjAxNy0xMS0yN1QwOTozMzo0Ny4yNTBaIiwKICAgICAgICAidXBkYXRlZEF0IjogIjIwMTgtMDgtMTRUMDk6NTQ6NDIuOTM2WiIsCiAgICAgICAgImVudmlyb25tZW50IjogewogICAgICAgICAgInN5cyI6IHsKICAgICAgICAgICAgImlkIjogIm1hc3RlciIsCiAgICAgICAgICAgICJ0eXBlIjogIkxpbmsiLAogICAgICAgICAgICAibGlua1R5cGUiOiAiRW52aXJvbm1lbnQiCiAgICAgICAgICB9CiAgICAgICAgfSwKICAgICAgICAicmV2aXNpb24iOiAyLAogICAgICAgICJjb250ZW50VHlwZSI6IHsKICAgICAgICAgICJzeXMiOiB7CiAgICAgICAgICAgICJ0eXBlIjogIkxpbmsiLAogICAgICAgICAgICAibGlua1R5cGUiOiAiQ29udGVudFR5cGUiLAogICAgICAgICAgICAiaWQiOiAic2luZ2xlUmVjb3JkIgogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgImxvY2FsZSI6ICJlbi1VUyIKICAgICAgfSwKICAgICAgImZpZWxkcyI6IHsKICAgICAgICAidGV4dEJvZHkiOiAiUmVjb3JkIHdpdGggYXJyYXkgb2YgYXNzZXRzIiwKICAgICAgICAiYXNzZXRzQXJyYXlMaW5rRmllbGQiOiBbCiAgICAgICAgICB7CiAgICAgICAgICAgICJzeXMiOiB7CiAgICAgICAgICAgICAgInR5cGUiOiAiTGluayIsCiAgICAgICAgICAgICAgImxpbmtUeXBlIjogIkFzc2V0IiwKICAgICAgICAgICAgICAiaWQiOiAiNldzejhvd2h0Q0dTSUNnNDRJVVlBbSIKICAgICAgICAgICAgfQogICAgICAgICAgfSwKICAgICAgICAgIHsKICAgICAgICAgICAgInN5cyI6IHsKICAgICAgICAgICAgICAidHlwZSI6ICJMaW5rIiwKICAgICAgICAgICAgICAibGlua1R5cGUiOiAiQXNzZXQiLAogICAgICAgICAgICAgICJpZCI6ICI2RzMwbjV3M3NXY1M2eUVXbzhxNkNJIgogICAgICAgICAgICB9CiAgICAgICAgICB9LAogICAgICAgICAgewogICAgICAgICAgICAic3lzIjogewogICAgICAgICAgICAgICJ0eXBlIjogIkxpbmsiLAogICAgICAgICAgICAgICJsaW5rVHlwZSI6ICJBc3NldCIsCiAgICAgICAgICAgICAgImlkIjogIjh5QnBXUjBlbjZVVXNPNFE2RWlPSyIKICAgICAgICAgICAgfQogICAgICAgICAgfSwKICAgICAgICAgIHsKICAgICAgICAgICAgInN5cyI6IHsKICAgICAgICAgICAgICAidHlwZSI6ICJMaW5rIiwKICAgICAgICAgICAgICAibGlua1R5cGUiOiAiQXNzZXQiLAogICAgICAgICAgICAgICJpZCI6ICI3aThUVUJiNGlJQW9XdVF1aVVHZ2cwIgogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgXQogICAgICB9CiAgICB9CiAgXQp9Cg==",
"headers" : {
"Vary" : "Accept-Encoding",
"Date" : "Thu, 06 Dec 2018 08:30:38 GMT",
"x-cache-hits" : "1",
"access-control-max-age" : "86400",
"x-cache" : "HIT",
"Content-Type" : "application\/vnd.contentful.delivery.v1+json",
"access-control-allow-methods" : "GET,HEAD,OPTIONS",
"x-content-type-options" : "nosniff",
"x-served-by" : "cache-bma1628-BMA",
"Age" : "210",
"access-control-expose-headers" : "Etag",
"Content-Length" : "1183",
"Access-Control-Allow-Origin" : "*",
"x-contentful-region" : "us-east-1",
"Etag" : "W\/\"14d8cbbace0e1781f6e3031018a67358\"",
"Server" : "Contentful",
"Cache-Control" : "max-age=0",
"x-contentful-request-id" : "6986b677c8ae08d777634757d3300dd9",
"Content-Encoding" : "gzip",
"Accept-Ranges" : "bytes",
"contentful-api" : "cda_cached",
"access-control-allow-headers" : "Accept,Accept-Language,Authorization,Cache-Control,Content-Length,Content-Range,Content-Type,DNT,Destination,Expires,If-Match,If-Modified-Since,If-None-Match,Keep-Alive,Last-Modified,Origin,Pragma,Range,User-Agent,X-Http-Method-Override,X-Mx-ReqToken,X-Requested-With,X-Contentful-Version,X-Contentful-Content-Type,X-Contentful-Organization,X-Contentful-Skip-Transformation,X-Contentful-User-Agent,X-Contentful-Enable-Alpha-Feature",
"Via" : "1.1 varnish"
}
}
},
{
"request" : {
"headers" : {
Expand Down
18 changes: 18 additions & 0 deletions Tests/ContentfulTests/EntryDecodableLinkResolutionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,22 @@ class LinkResolverTests: XCTestCase {
}
self.waitForExpectations(timeout: 10.0, handler: nil)
}

/// This test exists mainly to check that the fetch URL does have the `include=0`
/// parameter (or else, the test JSON would not be found in the cassette), and
/// that parsing does still work.
func testFetchZeroIncludesOmitsLinkResolving() {
let expectation = self.expectation(description: "Fetching an Entry with include=0 prevents link resolution")

LinkResolverTests.client.fetch(SingleRecord.self, id: "2JFSeiPTZYm4goMSUeYSCU", include: 0) { result in
switch result {
case .success(let record):
XCTAssert(record.assetsArrayLinkField?.isEmpty ?? true)
case .error(let error):
XCTFail("Should not throw an error \(error)")
}
expectation.fulfill()
}
self.waitForExpectations(timeout: 10.0, handler: nil)
}
}

0 comments on commit 3b8e6ef

Please sign in to comment.