{"action":"created","comment":{"url":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/comments/177100488","pull_request_review_id":106914602,"id":177100488,"diff_hunk":"@@ -0,0 +1,177 @@\n+//\n+//  Copyright (c) 2016 Algolia\n+//  http://www.algolia.com/\n+//\n+//  Permission is hereby granted, free of charge, to any person obtaining a copy\n+//  of this software and associated documentation files (the \"Software\"), to deal\n+//  in the Software without restriction, including without limitation the rights\n+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+//  copies of the Software, and to permit persons to whom the Software is\n+//  furnished to do so, subject to the following conditions:\n+//\n+//  The above copyright notice and this permission notice shall be included in\n+//  all copies or substantial portions of the Software.\n+//\n+//  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n+//  THE SOFTWARE.\n+//\n+\n+import Foundation\n+import AlgoliaSearch\n+\n+/// A Transformable data source\n+public protocol Transformable {\n+    associatedtype IResults\n+    associatedtype IParameters\n+    \n+    typealias SearchResultsHandler = (_ results: IResults?, _ error: Error?) -> Void\n+    \n+    // Search operation\n+    func search(_ query: IParameters, searchResultsHandler: @escaping SearchResultsHandler)\n+    \n+    // Transforms the Algolia params to custom backend params.\n+    func map(query: Query) -> IParameters\n+    \n+    // Transforms the custom backend result to an Algolia result.\n+    func map(results: IResults) -> SearchResults\n+    \n+    \n+    // Disjunctive Search operation\n+    func searchDisjunctiveFaceting(_ query: IParameters, searchResultsHandler: @escaping SearchResultsHandler)\n+    \n+    // Transforms the Algolia disjunctive params to custom backend params.\n+    func map(query: Query, disjunctiveFacets: [String], refinements: [String : [String]]) -> IParameters\n+    \n+    \n+    // Search for facet value operation\n+    func searchForFacetValues(_ query: IParameters, searchResultsHandler: @escaping SearchResultsHandler)\n+    \n+    // Transforms the Algolia facet value params to custom backend params.\n+    func map(query: Query?, facetName: String, matching text: String) -> IParameters\n+}\n+\n+/// Base class used to implement a custom backend with Algolia\n+/// You need to make sure to implement the following method:\n+/// - search(query:searchResultsHandler:)\n+/// - map(query:)\n+/// - map(results:)\n+open class SearchTransformer<Parameters, Results>: Transformable, Searchable {\n+    \n+    public typealias IParameters = Parameters\n+    public typealias IResults = Results\n+    \n+    public init() {}\n+    \n+    // Transformable protocol\n+    \n+    open func search(_ query: Parameters, searchResultsHandler: @escaping SearchResultsHandler) {\n+        fatalError(\"make sure to override search(query:searchResultsHandler:) for custom backend\")\n+    }\n+    \n+    open func map(query: Query) -> Parameters {\n+        fatalError(\"make sure to override map(query:) for custom backend\")\n+    }\n+    \n+    open func map(results: Results) -> SearchResults {\n+        fatalError(\"make sure to override map(results:) for custom backend\")","path":"Sources/Transformer.swift","position":76,"original_position":81,"commit_id":"4fcae1f4aa4b406c8a59907ea95e6d6494a738ff","original_commit_id":"8bf8ffe8d0e8a948a35dd49f4843b006cfba3e0d","user":{"login":"francoischalifour","id":6137112,"avatar_url":"https://avatars3.githubusercontent.com/u/6137112?v=4","gravatar_id":"","url":"https://api.github.com/users/francoischalifour","html_url":"https://github.com/francoischalifour","followers_url":"https://api.github.com/users/francoischalifour/followers","following_url":"https://api.github.com/users/francoischalifour/following{/other_user}","gists_url":"https://api.github.com/users/francoischalifour/gists{/gist_id}","starred_url":"https://api.github.com/users/francoischalifour/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/francoischalifour/subscriptions","organizations_url":"https://api.github.com/users/francoischalifour/orgs","repos_url":"https://api.github.com/users/francoischalifour/repos","events_url":"https://api.github.com/users/francoischalifour/events{/privacy}","received_events_url":"https://api.github.com/users/francoischalifour/received_events","type":"User","site_admin":false},"body":"The web team actually went for \"response\" instead of \"result\".\r\n\r\nBut this naming in Swift is internal, right?","created_at":"2018-03-26T14:01:46Z","updated_at":"2018-03-26T14:01:46Z","html_url":"https://github.com/algolia/instantsearch-core-swift/pull/20#discussion_r177100488","pull_request_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/20","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/comments/177100488"},"html":{"href":"https://github.com/algolia/instantsearch-core-swift/pull/20#discussion_r177100488"},"pull_request":{"href":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/20"}},"in_reply_to_id":175366540},"pull_request":{"url":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/20","id":174425057,"html_url":"https://github.com/algolia/instantsearch-core-swift/pull/20","diff_url":"https://github.com/algolia/instantsearch-core-swift/pull/20.diff","patch_url":"https://github.com/algolia/instantsearch-core-swift/pull/20.patch","issue_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/issues/20","number":20,"state":"open","locked":false,"title":"Custom Backend POC","user":{"login":"spinach","id":1502519,"avatar_url":"https://avatars1.githubusercontent.com/u/1502519?v=4","gravatar_id":"","url":"https://api.github.com/users/spinach","html_url":"https://github.com/spinach","followers_url":"https://api.github.com/users/spinach/followers","following_url":"https://api.github.com/users/spinach/following{/other_user}","gists_url":"https://api.github.com/users/spinach/gists{/gist_id}","starred_url":"https://api.github.com/users/spinach/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spinach/subscriptions","organizations_url":"https://api.github.com/users/spinach/orgs","repos_url":"https://api.github.com/users/spinach/repos","events_url":"https://api.github.com/users/spinach/events{/privacy}","received_events_url":"https://api.github.com/users/spinach/received_events","type":"User","site_admin":false},"body":"## Starting Note\r\n\r\nThis is a hacky-ish and quickly done solution, but it's on purpose: I am sending it early so that I can quickly get feedback and iterate. I'd love to get ideas from you guys on how we should proceed.\r\nAlso note that this has been inspired partly by the POC that the Francois did on the web side. \r\n\r\n## Structure of this PR\r\n\r\nYou will see 2 Proof of concepts (POC), with respective 2 implementation examples. The comments in the files will inform you on which POC you are looking at. \r\n\r\nPlease start by checking the the source code of the library [here](https://github.com/algolia/instantsearch-core-swift/compare/custom-source?expand=1#diff-f9bbdf29602edd6c239935b01ebecc1C), then proceed to check an implementation example [here](https://github.com/algolia/instantsearch-core-swift/compare/custom-source?expand=1#diff-361131c7771e8eff4685bd7a965d8ba9). \r\n\r\nFor most important parts of the PR, please check `// IMPORTANT` comments \r\n\r\n## DX on implementing a `Transformer`\r\n\r\n**Required**\r\n\r\n```swift\r\n    // Search operation\r\n    func search(_ query: IParameters, searchResultsHandler: @escaping SearchResultsHandler)\r\n    \r\n    // Transforms the Algolia params to custom backend params.\r\n    func map(query: Query) -> IParameters\r\n    \r\n    // Transforms the custom backend result to an Algolia result.\r\n    func map(results: IResults) -> SearchResults\r\n```\r\n\r\n**Optional**\r\n\r\n```swift    \r\n    // Transforms the Algolia disjunctive params to custom backend params.\r\n    func map(query: Query, disjunctiveFacets: [String], refinements: [String : [String]]) -> IParameters\r\n    \r\n    \r\n    // Search for facet value operation\r\n    func searchForFacetValues(_ query: IParameters, searchResultsHandler: @escaping SearchResultsHandler)\r\n    \r\n    // Transforms the Algolia facet value params to custom backend params.\r\n    func map(query: Query?, facetName: String, matching text: String) -> IParameters\r\n```\r\n\r\n## Example of implementation of a Custom backend\r\n\r\n```swift\r\n// Search Data Models of the custom backend\r\npublic struct CustomSearchResults {\r\n    var nbHitsCustom: Int\r\n    var hitsCustom: [[String: Any]]\r\n}\r\n\r\npublic struct CustomSearchParameters {\r\n    var query: String?\r\n    var filters: String?\r\n    var facets: [String]?\r\n}\r\n\r\npublic class CustomSearchableImplementation: SearchTransformer<CustomSearchParameters, CustomSearchResults> {\r\n    \r\n    public override func search(_ query: CustomSearchParameters, searchResultsHandler: @escaping SearchResultsHandler) {\r\n\r\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1.5, execute: {\r\n            guard let path = Bundle.main.path(forResource: \"mock-custom\", ofType: \"json\") else {\r\n                print(\"Invalid filename/path.\")\r\n                return\r\n            }\r\n            do {\r\n                guard let text = query.query else { return }\r\n                \r\n                let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .alwaysMapped)\r\n                var jsonObj = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]\r\n                jsonObj![\"hitsCustom\"] = (jsonObj![\"hitsCustom\"] as! [[String: String]]).filter({ item in\r\n                    (item[\"nameCustom\"]?.contains(text))! || (item[\"descriptionCustom\"]?.contains(text))!\r\n                })\r\n                let nbHitsCustom = jsonObj![\"nbHitsCustom\"] as! Int\r\n                let hitsCustom = jsonObj![\"hitsCustom\"] as! [[String: Any]]\r\n                let customSearchResults = CustomSearchResults(nbHitsCustom: nbHitsCustom, hitsCustom: hitsCustom)\r\n                \r\n                // IMPORTANT: Need to call the searchResultHandler when done, this is the responsibility of the 3rd party dev\r\n                searchResultsHandler(customSearchResults, nil)\r\n            } catch let error {\r\n                searchResultsHandler(nil, error)\r\n                print(error.localizedDescription)\r\n            }\r\n            \r\n        })\r\n        \r\n    }\r\n    \r\n    public override func map(query: Query?, facetName: String, matching text: String) -> CustomSearchParameters {\r\n        return CustomSearchParameters(query: text, filters: facetName, facets: nil)\r\n    }\r\n    \r\n    // Transforms the Algolia params to custom backend params.\r\n    public override func map(query: Query) -> CustomSearchParameters {\r\n        let queryText = query.query\r\n        let filters = query.filters\r\n        let facets = query.facets\r\n        \r\n        return CustomSearchParameters(query: queryText, filters: filters, facets: facets)\r\n    }\r\n    \r\n    // Transforms the custom backend result to an Algolia result.\r\n    public override func map(results: CustomSearchResults) -> SearchResults {\r\n        let nbHitsCustom = results.nbHitsCustom\r\n        let hitsCustom = results.hitsCustom\r\n        \r\n        return SearchResults(nbHits: nbHitsCustom, hits: hitsCustom)\r\n    }\r\n}\r\n```\r\n\r\n## DX on creating the custom backend implem\r\n\r\n```swift\r\n    let index = CustomSearchableImplementation()\r\n```\r\n\r\n## Implementation  Details\r\n\r\nYou will see that in order to implement a custom backend in both of these POCs, the 3rd party dev will have to create a class that implements a protocol (or interface in Java). The reason for that was to guide them to correctly convert (or transform) his search schema to our search schemas. Implementing 2 `map` methods (for params and results) is at the core of these prototypes. After that, the customer will have to implement the search functions that will take care of doing the search on their backend. \r\n\r\nWe note that the search functions return an operation, and that IS-Core will take care of out of order requests and cancelling the irrelevant ones. This is one feature that we can consider as part of our offering. They can decide to ignore that part and just return a default operation. In that case, there's no guarantee that request will come in order (so it's not recommended). Also They have to start their operations, we don't do it for them (at least with these POCs)\r\n\r\nAs part of doing the search function, the one thing they need to take care of is at the end calling the `searchResultsHandler` method.\r\n\r\n\r\n###  POC 2 Remark\r\n\r\nYou will realise that there is a lot of `Any` there. I wanted to move from `Any` to generics or associatedType, but I ran into the PAT problem described [here](https://stackoverflow.com/questions/24888560/usage-of-protocols-as-array-types-and-function-parameters-in-swift). In short, it is a limitation of Swift: when using a protocol as a class member, we can't use generics. This is will lead to a lot of type casting which means less safety and can lead to bugs. (hence why I prefer POC 1)\r\n\r\n## Other attempts \r\n\r\nI tried to Provide an abstract class [example](https://stackoverflow.com/a/24110512/905425) but unfortunately it is impossible with Searchable having @objc requirement (see problem mentioned in this [SO question](https://stackoverflow.com/questions/38980887/protocol-extension-on-an-objc-protocol))","created_at":"2018-03-12T16:34:37Z","updated_at":"2018-03-26T14:01:46Z","closed_at":null,"merged_at":null,"merge_commit_sha":"dfa0434ee26c3839dbe214e2fd3039baf587ac7e","assignee":null,"assignees":[],"requested_reviewers":[{"login":"mthuret","id":6885378,"avatar_url":"https://avatars0.githubusercontent.com/u/6885378?v=4","gravatar_id":"","url":"https://api.github.com/users/mthuret","html_url":"https://github.com/mthuret","followers_url":"https://api.github.com/users/mthuret/followers","following_url":"https://api.github.com/users/mthuret/following{/other_user}","gists_url":"https://api.github.com/users/mthuret/gists{/gist_id}","starred_url":"https://api.github.com/users/mthuret/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mthuret/subscriptions","organizations_url":"https://api.github.com/users/mthuret/orgs","repos_url":"https://api.github.com/users/mthuret/repos","events_url":"https://api.github.com/users/mthuret/events{/privacy}","received_events_url":"https://api.github.com/users/mthuret/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/20/commits","review_comments_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/20/comments","review_comment_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/comments{/number}","comments_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/issues/20/comments","statuses_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/statuses/4fcae1f4aa4b406c8a59907ea95e6d6494a738ff","head":{"label":"algolia:custom-source","ref":"custom-source","sha":"4fcae1f4aa4b406c8a59907ea95e6d6494a738ff","user":{"login":"algolia","id":2034458,"avatar_url":"https://avatars0.githubusercontent.com/u/2034458?v=4","gravatar_id":"","url":"https://api.github.com/users/algolia","html_url":"https://github.com/algolia","followers_url":"https://api.github.com/users/algolia/followers","following_url":"https://api.github.com/users/algolia/following{/other_user}","gists_url":"https://api.github.com/users/algolia/gists{/gist_id}","starred_url":"https://api.github.com/users/algolia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/algolia/subscriptions","organizations_url":"https://api.github.com/users/algolia/orgs","repos_url":"https://api.github.com/users/algolia/repos","events_url":"https://api.github.com/users/algolia/events{/privacy}","received_events_url":"https://api.github.com/users/algolia/received_events","type":"Organization","site_admin":false},"repo":{"id":64117204,"name":"instantsearch-core-swift","full_name":"algolia/instantsearch-core-swift","owner":{"login":"algolia","id":2034458,"avatar_url":"https://avatars0.githubusercontent.com/u/2034458?v=4","gravatar_id":"","url":"https://api.github.com/users/algolia","html_url":"https://github.com/algolia","followers_url":"https://api.github.com/users/algolia/followers","following_url":"https://api.github.com/users/algolia/following{/other_user}","gists_url":"https://api.github.com/users/algolia/gists{/gist_id}","starred_url":"https://api.github.com/users/algolia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/algolia/subscriptions","organizations_url":"https://api.github.com/users/algolia/orgs","repos_url":"https://api.github.com/users/algolia/repos","events_url":"https://api.github.com/users/algolia/events{/privacy}","received_events_url":"https://api.github.com/users/algolia/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/algolia/instantsearch-core-swift","description":"⚡️ InstantSearch Core library for Swift and Objective-C","fork":false,"url":"https://api.github.com/repos/algolia/instantsearch-core-swift","forks_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/forks","keys_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/keys{/key_id}","collaborators_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/teams","hooks_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/hooks","issue_events_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/issues/events{/number}","events_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/events","assignees_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/assignees{/user}","branches_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/branches{/branch}","tags_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/tags","blobs_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/git/refs{/sha}","trees_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/git/trees{/sha}","statuses_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/statuses/{sha}","languages_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/languages","stargazers_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/stargazers","contributors_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/contributors","subscribers_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/subscribers","subscription_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/subscription","commits_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/commits{/sha}","git_commits_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/git/commits{/sha}","comments_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/comments{/number}","issue_comment_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/issues/comments{/number}","contents_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/contents/{+path}","compare_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/compare/{base}...{head}","merges_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/merges","archive_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/downloads","issues_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/issues{/number}","pulls_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls{/number}","milestones_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/milestones{/number}","notifications_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/labels{/name}","releases_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/releases{/id}","deployments_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/deployments","created_at":"2016-07-25T08:27:45Z","updated_at":"2018-03-13T13:00:44Z","pushed_at":"2018-03-21T15:55:09Z","git_url":"git://github.com/algolia/instantsearch-core-swift.git","ssh_url":"git@github.com:algolia/instantsearch-core-swift.git","clone_url":"https://github.com/algolia/instantsearch-core-swift.git","svn_url":"https://github.com/algolia/instantsearch-core-swift","homepage":"https://community.algolia.com/instantsearch-core-swift/","size":689,"stargazers_count":7,"watchers_count":7,"language":"Swift","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":3,"mirror_url":null,"archived":false,"open_issues_count":3,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":3,"open_issues":3,"watchers":7,"default_branch":"master"}},"base":{"label":"algolia:master","ref":"master","sha":"3a2b895eb4fc2cceb640c7009431737426c1f4e6","user":{"login":"algolia","id":2034458,"avatar_url":"https://avatars0.githubusercontent.com/u/2034458?v=4","gravatar_id":"","url":"https://api.github.com/users/algolia","html_url":"https://github.com/algolia","followers_url":"https://api.github.com/users/algolia/followers","following_url":"https://api.github.com/users/algolia/following{/other_user}","gists_url":"https://api.github.com/users/algolia/gists{/gist_id}","starred_url":"https://api.github.com/users/algolia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/algolia/subscriptions","organizations_url":"https://api.github.com/users/algolia/orgs","repos_url":"https://api.github.com/users/algolia/repos","events_url":"https://api.github.com/users/algolia/events{/privacy}","received_events_url":"https://api.github.com/users/algolia/received_events","type":"Organization","site_admin":false},"repo":{"id":64117204,"name":"instantsearch-core-swift","full_name":"algolia/instantsearch-core-swift","owner":{"login":"algolia","id":2034458,"avatar_url":"https://avatars0.githubusercontent.com/u/2034458?v=4","gravatar_id":"","url":"https://api.github.com/users/algolia","html_url":"https://github.com/algolia","followers_url":"https://api.github.com/users/algolia/followers","following_url":"https://api.github.com/users/algolia/following{/other_user}","gists_url":"https://api.github.com/users/algolia/gists{/gist_id}","starred_url":"https://api.github.com/users/algolia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/algolia/subscriptions","organizations_url":"https://api.github.com/users/algolia/orgs","repos_url":"https://api.github.com/users/algolia/repos","events_url":"https://api.github.com/users/algolia/events{/privacy}","received_events_url":"https://api.github.com/users/algolia/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/algolia/instantsearch-core-swift","description":"⚡️ InstantSearch Core library for Swift and Objective-C","fork":false,"url":"https://api.github.com/repos/algolia/instantsearch-core-swift","forks_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/forks","keys_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/keys{/key_id}","collaborators_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/teams","hooks_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/hooks","issue_events_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/issues/events{/number}","events_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/events","assignees_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/assignees{/user}","branches_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/branches{/branch}","tags_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/tags","blobs_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/git/refs{/sha}","trees_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/git/trees{/sha}","statuses_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/statuses/{sha}","languages_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/languages","stargazers_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/stargazers","contributors_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/contributors","subscribers_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/subscribers","subscription_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/subscription","commits_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/commits{/sha}","git_commits_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/git/commits{/sha}","comments_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/comments{/number}","issue_comment_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/issues/comments{/number}","contents_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/contents/{+path}","compare_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/compare/{base}...{head}","merges_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/merges","archive_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/downloads","issues_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/issues{/number}","pulls_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls{/number}","milestones_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/milestones{/number}","notifications_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/labels{/name}","releases_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/releases{/id}","deployments_url":"https://api.github.com/repos/algolia/instantsearch-core-swift/deployments","created_at":"2016-07-25T08:27:45Z","updated_at":"2018-03-13T13:00:44Z","pushed_at":"2018-03-21T15:55:09Z","git_url":"git://github.com/algolia/instantsearch-core-swift.git","ssh_url":"git@github.com:algolia/instantsearch-core-swift.git","clone_url":"https://github.com/algolia/instantsearch-core-swift.git","svn_url":"https://github.com/algolia/instantsearch-core-swift","homepage":"https://community.algolia.com/instantsearch-core-swift/","size":689,"stargazers_count":7,"watchers_count":7,"language":"Swift","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":3,"mirror_url":null,"archived":false,"open_issues_count":3,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit"},"forks":3,"open_issues":3,"watchers":7,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/20"},"html":{"href":"https://github.com/algolia/instantsearch-core-swift/pull/20"},"issue":{"href":"https://api.github.com/repos/algolia/instantsearch-core-swift/issues/20"},"comments":{"href":"https://api.github.com/repos/algolia/instantsearch-core-swift/issues/20/comments"},"review_comments":{"href":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/20/comments"},"review_comment":{"href":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/algolia/instantsearch-core-swift/pulls/20/commits"},"statuses":{"href":"https://api.github.com/repos/algolia/instantsearch-core-swift/statuses/4fcae1f4aa4b406c8a59907ea95e6d6494a738ff"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"francoischalifour"}}